/*
 * Copyright (c) 2001 Fenris, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * File:  display.c
 *
 * Purpose:  This source file contains the definitions use to implement
 * a nested list structure that holds the information necessary to 
 * display the source nodes, destination nodes, the lines between them,
 * and their respective colors.  After initializing a display object,
 * the display object and a network object (see network.c) are passed
 * to the populate() function which extracts the appropriate information
 * from the network object, and builds the display.  The display should
 * be "cleared" after every use.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "display.h"
#include "globals.h"


int init_dsp(Display* dsp)
{
    if ((dsp->src_list = malloc(sizeof(Dsp_List))) == NULL)
        die("malloc");
    if ((dsp->dst_list = malloc(sizeof(Dsp_List))) == NULL)
        die("malloc");
    if ((dsp->pair_list = malloc(sizeof(Dsp_List))) == NULL)
        die("malloc");

    init_dsp_list(dsp->src_list);
    init_dsp_list(dsp->dst_list);
    init_dsp_list(dsp->pair_list);

    return 0;
}


void populate_dsp(Display* dsp, Network* net)
{
    Net_Node * 		current_net_node = NULL;
    Net_List * 		net_sublist;
    Dsp_Obj * 		new_dsp_obj;
    Net_Node * 		net_node;
    Net_Obj * 		net_obj;
    float 		rate;
    Color 		color;

    pthread_mutex_lock(net_mutex);

    refresh_net(net);

    /* loop through src_list lists and calc the src_list display objects */
    if (net->src_list != NULL) {
        current_net_node = net->src_list->head;
    }
    while (current_net_node != NULL) {
        net_sublist = current_net_node->obj;
        if (net_sublist != NULL) {
            net_node = net_sublist->head;
            if (net_node != NULL) {
                net_obj = net_node->obj;
                rate = ((float)net_sublist->size * 8) / (float)net->timeout;
                /* XXX Handle this case in the future. */
                if (dsp->abs) {
                    /* use max n min */
                    rate_to_color(dsp, rate, &color);
                } else {
                    /* set max n min first */
                    rate_to_color(dsp, rate, &color);
                }
                if ((new_dsp_obj = malloc(sizeof(Dsp_Obj))) == NULL)
                    die("malloc");
                new_dsp_obj->src = net_obj->src;
                strncpy(new_dsp_obj->src_name,
                        net_sublist->src, MAX_HOSTNAME_LEN);
                new_dsp_obj->color.red = color.red; 
                new_dsp_obj->color.blue = color.blue; 
                new_dsp_obj->color.green = color.green; 
                new_dsp_obj->dst = 0;
                insert_src_dsp_obj(dsp->src_list, new_dsp_obj);
            }
        }
        current_net_node = current_net_node->next;
    }

    /* repeat for dst_list */
    if (net->dst_list != NULL) {
        current_net_node = net->dst_list->head;
    }
    while (current_net_node != NULL) {
        net_sublist = current_net_node->obj;
        if (net_sublist != NULL) {
            net_node = net_sublist->head;
            if (net_node != NULL) {
                net_obj = net_node->obj;
                rate = ((float)net_sublist->size * 8) / (float)net->timeout;
                /* XXX Handle this case in the future. */
                if (dsp->abs) {
                    rate_to_color(dsp, rate, &color);
                } else {
                    rate_to_color(dsp, rate, &color);
                }
                if ((new_dsp_obj = malloc(sizeof(Dsp_Obj))) == NULL)
                    die("malloc");
                new_dsp_obj->dst = net_obj->dst;
                strncpy(new_dsp_obj->dst_name,
                        net_sublist->dst, MAX_HOSTNAME_LEN);
                new_dsp_obj->color.red = color.red; 
                new_dsp_obj->color.blue = color.blue; 
                new_dsp_obj->color.green = color.green; 
                new_dsp_obj->src = 0;
                insert_dst_dsp_obj(dsp->dst_list, new_dsp_obj);
            }
        }
        current_net_node = current_net_node->next;
    }

    /* repeat for pair_lists */
    if (net->pair_list != NULL) {
        current_net_node = net->pair_list->head;
    }
    while (current_net_node != NULL) {
        net_sublist = current_net_node->obj;
        if (net_sublist != NULL) {
            net_node = net_sublist->head;
            if (net_node != NULL) {
                net_obj = net_node->obj;
                rate = ((float)net_sublist->size * 8) / (float)net->timeout;
                /* XXX Handle this case in the future. */
                if (dsp->abs) {
                    rate_to_color(dsp, rate, &color);
                } else {
                    rate_to_color(dsp, rate, &color);
                }
                if ((new_dsp_obj = malloc(sizeof(Dsp_Obj))) == NULL)
                    die("malloc");
                new_dsp_obj->src = net_obj->src;
                new_dsp_obj->dst = net_obj->dst;
                new_dsp_obj->color.red = color.red; 
                new_dsp_obj->color.blue = color.blue; 
                new_dsp_obj->color.green = color.green; 
                append_dsp_list(dsp->pair_list, new_dsp_obj);
            }
        }
        current_net_node = current_net_node->next;
    }
    pthread_mutex_unlock(net_mutex);
}


void clear_dsp(Display* dsp)
{
    empty_dsp_list(dsp->src_list);
    empty_dsp_list(dsp->dst_list);
    empty_dsp_list(dsp->pair_list);
    return;
}


void rate_to_color(Display* dsp, float rate, Color* color)
{
    float 		step;
    int 		num_steps;

    step = (float)(dsp->max_rate - dsp->min_rate) / (float)RES;
    num_steps = (rate - dsp->min_rate) / step;

    if (num_steps < 5) {
        color->blue = PMAX; 
        color->green = (num_steps * STEP);  
        color->red = PMIN;
        return;
    }
    if (num_steps < 10) {
        num_steps = num_steps - 5;
        color->red = PMIN;
        color->blue = PMAX - (num_steps * STEP);
        color->green = PMAX;
        return;
    }
    if (num_steps < 15) {
        num_steps = num_steps - 10;
        color->red = (num_steps * STEP); 
        color->green = PMAX;
        color->blue = PMIN; 
        return;
    }
    else {
        num_steps = num_steps - 15;
        color->red = PMAX;
        color->blue = PMIN;
        color->green = PMAX - (num_steps * STEP); 
        return;
    }
}


syntax highlighted by Code2HTML, v. 0.9.1