 /*
  * Khoros: $Id$
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id$";
#endif

 /*
  * $Log$
  */ 

/*
 *----------------------------------------------------------------------
 *
 * Copyright 1991, University of New Mexico.  All rights reserved.
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as to the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including, for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *---------------------------------------------------------------------
 */

#include "unmcopyright.h"        /* Copyright 1991 by UNM */

/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 >>>>
 >>>>  		        Legend Routines
 >>>>
 >>>> 			add_legend_node()
 >>>> 			delete_legend_node()
 >>>> 			update_xcolors_from_legend()
 >>>> 			legend_colorbox_cb()
 >>>> 			legend_textwid_cb()
 >>>> 			add_legend_entry()
 >>>> 			delete_legend_entry()
 >>>> 			update_legend_color()
 >>>> 			add_cluster_from_img()
 >>>>
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/

#include "spectrum.h"
#include "colorspace.h"


/****************************************************************
*
* Routine Name: add_legend_node
*
*      Purpose: adds one node to the spc_legend list.
*
*	 Input: red        - red value of RGB triple
*		green      - green value of RGB triple
*		blue       - blue value of RGB triple
*		text       - string assoc. w/ legend info
*		clusters   - array of cluster numbers
*		clusternum - # of cluster numbers (size of clusters array)
*
*       Output: the spc_legend list is one node longer
*   Written By: Danielle Argiro
*
****************************************************************/

legend_list *add_legend_node(class, red, green, blue, text, clusters, clusternum)
short class;
short red, green, blue;
char *text;
int  *clusters;
int  clusternum;
{
	int i, cluster_id;
	legend_list *legend_ptr, *last; 

	/* create the first node in the legend list */
	if (spc_legend_list == NULL)
	{
	   spc_legend_list = (legend_list *) calloc (1, sizeof(legend_list));
	   spc_legend_list->class = class;
	   spc_legend_list->red = red;
	   spc_legend_list->green = green;
	   spc_legend_list->blue = blue;
	   spc_legend_list->text = xvf_strcpy(text);
	   spc_legend_list->clusternum = clusternum;
	   spc_legend_list->clusters = clusters;
	   spc_legend_list->next = NULL;
	   spc_legend_list->hidden = false;

	   spc_legend_lookup = (legend_list **) 
				calloc(1, sizeof(legend_list *) 
					* spc_map_rownum);

	   /* add associated clusters to legend node */
	   for (i = 0; i < clusternum; i++)
	   {
		cluster_id = spc_legend_list->clusters[i];
		spc_legend_lookup[cluster_id] = spc_legend_list;
	   }
           return(spc_legend_list);
	}

	/* create later nodes in the legend list */
	else
	{
	   last = spc_legend_list;
	   while (last->next != NULL)
		last = last->next;

	   legend_ptr = (legend_list *) calloc (1, sizeof(legend_list));
	   legend_ptr->class = class;
           legend_ptr->red = red;
           legend_ptr->green = green;
           legend_ptr->blue = blue;
           legend_ptr->text = xvf_strcpy(text);
           legend_ptr->clusternum = clusternum;
           legend_ptr->clusters = clusters;
           legend_ptr->next = NULL;
	   legend_ptr->hidden = false;
	   last->next = legend_ptr;

	   /* add associated clusters to legend node */
	   for (i = 0; i < clusternum; i++)
	   {
		cluster_id = legend_ptr->clusters[i];
		spc_legend_lookup[cluster_id] = legend_ptr;
	   }
           return(legend_ptr);
	}
}

/****************************************************************
*
* Routine Name: delete_legend_node
*
*      Purpose: deletes one node from the spc_legend list.
*
*	 Input: red        - red value of RGB triple
*		green      - green value of RGB triple
*		blue       - blue value of RGB triple
*		text       - string assoc. w/ legend info
*		clusters   - array of cluster numbers
*		clusternum - # of cluster numbers (size of clusters array)
*
*       Output: the spc_legend list is one node longer
*
*   Written By: Danielle Argiro
*
********************************************************/
delete_legend_node(legend_ptr)
legend_list *legend_ptr;
{
	int i;
	legend_list *last, *save;

	/* nothing to delete */
	if (spc_legend_list == NULL)
	{
	    xvf_error_wait("No legend entries (current classes) to delete!",
			   "Spectrum", NULL);
	    return;
	}

	if (legend_ptr == spc_legend_list)
	{
	    /* delete pointers from lookup list assoc. w/ each 
	       cluster in this class */
	    for (i = 0; i < legend_ptr->clusternum; i++)
	    {
		draw_single_marker(legend_ptr->clusters[i], &PlotColors[0]);
	        spc_legend_lookup[legend_ptr->clusters[i]] = NULL;
	    }

	    /* delete the node */
	    save = spc_legend_list->next;
	    free(spc_legend_list->clusters);
	    if (spc_legend_list->entry_ptr == current_entry) 
		current_entry = NULL;
	    free(spc_legend_list->entry_ptr);
	    free(spc_legend_list);
	    spc_legend_list = save;
	}
	else
	{
	    /* delete pointers from lookup list assoc. w/ each 
	       cluster in this class */
	    for (i = 0; i < legend_ptr->clusternum; i++)
	        spc_legend_lookup[legend_ptr->clusters[i]] = NULL;

	    /* find the node to be deleted */
	    last = spc_legend_list;
	    while (last->next != legend_ptr)
                last = last->next;

	    /* delete the node */
	    last->next = legend_ptr->next;
	    free(legend_ptr->clusters);
	    if (legend_ptr->entry_ptr == current_entry) 
		current_entry = NULL;
	    free(legend_ptr->entry_ptr);
	    free(legend_ptr);
	}
	spc_lgd_classnum--;
}

/********************************************************
*
*  Routine Name:  update_xcolors_from_legend
*
*       Purpose:  update the RGB values shown in legend, according
*		  to RGB values specified in legend.
*
*         Input:  none
*        Output:  none
*    Written By:  Danielle Argiro
*
********************************************************/

update_xcolors_from_legend()
{
	legend_list *legend_ptr; 
        int i, xcolor_index;
     
	legend_ptr = spc_legend_list;

	while (legend_ptr != NULL)
	{
	    for (i = 0; i < legend_ptr->clusternum; i++)
	    {
	        if (!legend_ptr->hidden)
	 	{
	            xcolor_index = legend_ptr->clusters[i];
		    xvdisplay->xcolors[xcolor_index].red = 
				legend_ptr->red << 8;
		    xvdisplay->xcolors[xcolor_index].green = 
				legend_ptr->green << 8;
		    xvdisplay->xcolors[xcolor_index].blue = 
				legend_ptr->blue << 8;
		}
	    }
	    legend_ptr = legend_ptr->next;
	}
	xvd_update_xcolors(xvdisplay);
}



/********************************************************
*
*  Routine Name:  legend_colorbox_cb
*
*       Purpose:  sets the global current_entry pointer
*		  to the entry that the user has just 
*		  selected the colorbox of.
*
*         Input:  widget     - colorbox of the entry
*		  clientData - the current entry
*		  callData   - not used
*        Output:  none
*    Written By:  Danielle Argiro
*
********************************************************/

void legend_colorbox_cb(widget, clientData, callData)
Widget widget;
caddr_t clientData, callData;
{
	LegendEntry *entry_ptr;

	entry_ptr = (LegendEntry *) clientData;

	current_entry = entry_ptr;

	xvf_change_input(form, 
			 master_info.scatter_plot->scatter->select_index + 1, 
			 xvf_title_chng, current_entry->legend_ptr->text, 50);

	update_legend_scrolls_from_colorbox(entry_ptr->legend_ptr);

	draw_plot();
}

/********************************************************
*
*  Routine Name:  legend_textwid_cb
*
*       Purpose:  updates the name of the selected class
*
*         Input:  widget     - text widget of the entry
*		  clientData - the current entry
*		  callData   - not used
*        Output:  none
*    Written By:  Danielle Argiro
*
********************************************************/

void legend_textwid_cb(widget, clientData, callData)
Widget widget;
caddr_t clientData, callData;
{
	LegendEntry *entry_ptr;
	int status = 0;

	entry_ptr = (LegendEntry *) clientData;

	while (status != 1)
 	    status = set_new_classname(entry_ptr);
	if (entry_ptr == current_entry)
	    xvf_change_input(form, 
		 master_info.scatter_plot->scatter->select_index + 1, 
		 xvf_title_chng, current_entry->legend_ptr->text, 50);
}

/********************************************************
*
*  Routine Name:  add_legend_entry
*
*       Purpose:  adds a legend entry widget set to the 
*		  legend display
*
*         Input:  none
*        Output:  none
*    Written By:  Danielle Argiro
*
********************************************************/

add_legend_entry(cluster, name)
int cluster;
char *name;
{
	LegendEntry *entry_ptr;
	legend_list *legend_ptr;
	short red, green, blue;
	short class;
	int *clusters;
	int clusternum;
	char *get_new_classname();

	clusternum = 1;  /* only one cluster as of yet */

	/* want existing color from image */
	red   = xvdisplay->xcolors[cluster].red >> 8;
	green = xvdisplay->xcolors[cluster].green >> 8;
	blue  = xvdisplay->xcolors[cluster].blue >> 8;
	clusters = (int *) malloc (1 * sizeof(int));
	clusters[0] = cluster;

	if (spc_num_unused_classnums == 0)
 	    class = spc_lgd_classnum + 1;
	else
	{
	    class = spc_unused_classnums[spc_num_unused_classnums-1];
	    spc_num_unused_classnums--;
	}
	

     	legend_ptr = add_legend_node(class, red, green, blue, 
				     name, clusters, clusternum);
	entry_ptr = (LegendEntry *) calloc(1, sizeof(LegendEntry));
        entry_ptr->legend_ptr = legend_ptr;

	if (legend_ptr->text != NULL) free(legend_ptr->text);
	if (strcmp(name, "New Category") == 0)
	{
	    legend_ptr->text = NULL;
	    while (xvf_strlen(legend_ptr->text) == 0)
	       legend_ptr->text = get_new_classname();
	}
	else legend_ptr->text = xvf_strcpy(name);

	create_entry_display(entry_ptr, legend_ptr,NULL);
	legend_ptr->entry_ptr = entry_ptr;
	spc_lgd_classnum++;

	current_entry = entry_ptr;
	xvf_change_input(form, 
			 master_info.scatter_plot->scatter->select_index + 1, 
			 xvf_title_chng, current_entry->legend_ptr->text, 50);

	update_legend_scrolls_from_colorbox(legend_ptr);

fprintf(stderr, "Classes\n\n");
legend_ptr = spc_legend_list;
while (legend_ptr != NULL)
{
   fprintf(stderr, "Class %d -- %s\n", legend_ptr->class, legend_ptr->text);
   legend_ptr = legend_ptr->next;
}
fprintf(stderr, "\n\n");
}

/********************************************************
*
*  Routine Name:  delete_legend_entry
*
*       Purpose:  deletes a legend entry widget set from the 
*		  legend display, and eliminates the legend
*		  pointer from the spc_legend list.
*
*         Input:  none
*        Output:  none
*    Written By:  Danielle Argiro
*
********************************************************/

delete_legend_entry(legend_ptr, verbose)
legend_list *legend_ptr;
int verbose;
{
	LegendEntry *entry;
	char temp[MaxLength];

	entry = legend_ptr->entry_ptr;


	if (entry == NULL)
	{
	    xvf_error_wait("No legend entry selected to delete!  Please select an entry for deletion by clicking the mouse in the color box of the desired item in the legend display. ", "Spectrum", NULL);
	    return;
	}
	if (verbose)
	{
	    sprintf(temp, "Delete class category %s?", 
	 	    entry->legend_ptr->text);
	    if (!(xvf_warn_wait(temp, "Spectrum", NULL, NULL))) return;
	}
	xvf_change_input(form,
                         master_info.scatter_plot->scatter->select_index + 1,
                         xvf_title_chng, "none", 50);

	/* delete the legend entry widget set from legend display */
	XtDestroyWidget(entry->back);


	/* update display with values from original map data */
	restore_old_values(entry->legend_ptr, -1); 

	/* delete the legend node set from global list */
	save_unused_classnum(entry->legend_ptr->class);
	delete_legend_node(entry->legend_ptr); 

}

/********************************************************
*
*  Routine Name:  delete_legend
*       Purpose:  deletes all entries in current legend
*
*         Input:  none
*        Output:  none
*    Written By:  Danielle Argiro
*
********************************************************/

delete_legend()
{
	legend_list *legend_ptr, *save_next;

	/* delete legend list */
	legend_ptr = spc_legend_list;
	while (legend_ptr != NULL)
	{
	    XtDestroyWidget(legend_ptr->entry_ptr->back);
	    save_unused_classnum(legend_ptr->class);
	    save_next = legend_ptr->next;
	    delete_legend_node(legend_ptr);
	    legend_ptr = save_next;
	} 

	/* update display with values from original map data */
        change_band_function(current_red_func, SpcRed);
        change_band_function(current_green_func, SpcGreen);
        change_band_function(current_blue_func, SpcBlue); 
        update_xcolors_from_legend();
	xvd_update_xcolors(xvdisplay);

	/* no current entry */
        current_entry = NULL;
	xvf_change_input(form,
                         master_info.scatter_plot->scatter->select_index + 1,
                         xvf_title_chng, "none", 50);

	/* no legend entries => no unused class numbers */
	spc_num_unused_classnums = 0;
	free(spc_unused_classnums);
	spc_unused_classnums = NULL;
}

/********************************************************
*
*  Routine Name:  restore_old_values
*
*       Purpose:  restores the old color values that appeared
*		  in the image, before they were over-ridden
*		  by a legend color.  Used to restore colors
*		  after a legend category is deleted.
*
*         Input:  legend_ptr - pointer to legend node being deleted.
*        Output:  none
*    Written By:  Danielle Argiro
*
********************************************************/

restore_old_values(legend_ptr, cluster)
legend_list *legend_ptr;
int          cluster;
{
	int   i;

	/* restore red band */
	if (cluster == -1)
	   for(i = 0; i < legend_ptr->clusternum; i++)
	      xvdisplay->xcolors[legend_ptr->clusters[i]].red =  
		(((unsigned short) 
			norm_red_col[legend_ptr->clusters[i]]) << 8);
	else
	    xvdisplay->xcolors[cluster].red = 
		(((unsigned short) 
			norm_red_col[cluster]) << 8);

	/* restore green band */
	if (cluster == -1)
	  for(i = 0; i < legend_ptr->clusternum; i++)
	     xvdisplay->xcolors[legend_ptr->clusters[i]].green =  
		(((unsigned short) 
			norm_green_col[legend_ptr->clusters[i]]) << 8);
	else
	    xvdisplay->xcolors[cluster].green = 
		(((unsigned short) 
			norm_green_col[cluster]) << 8);

	/* restore blue band */
	if (cluster == -1)
	  for(i = 0; i < legend_ptr->clusternum; i++)
	     xvdisplay->xcolors[legend_ptr->clusters[i]].blue =  
	 	(((unsigned short) 
			norm_blue_col[legend_ptr->clusters[i]]) << 8);
	else
	    xvdisplay->xcolors[cluster].blue = 
		(((unsigned short) 
			norm_blue_col[cluster]) << 8);

}



/********************************************************
*
*  Routine Name:  update_legend_color
*
*       Purpose:  updates the legend color for the current
*		  entry according to the scroll bar values
*		  of the legend display
*
*         Input:  id    - id of the scroll bar that changed
*		  value - value given by scroll bar that changed
*        Output:  none
*    Written By:  Danielle Argiro
*
********************************************************/

update_legend_color(id, value, set)
int    id, set;
double value;
{
	Arg  arg[MaxArgs];
	char temp[MaxLength];
	int i, xcolor_index;
	legend_list *legend_ptr;
	XColor xcolor, color;
	double  val1, val2, val3;


    	if (current_entry == NULL) return;

	legend_ptr = current_entry->legend_ptr;
	if (legend_ptr->hidden == true) return;

	xcolor.red   = legend_ptr->red   << 8;
	xcolor.green = legend_ptr->green << 8;
	xcolor.blue  = legend_ptr->blue  << 8;

	switch(spc_color_model)
	{
	    case SpcRGB:
		 if (set) assign_color(id, value, &xcolor);
		 else increment_color(id, value, &xcolor);
		 break;

	    case SpcCMY:
		 RGB_to_CMY(xcolor, color);
		 if (set) assign_color(id, value, &color);
		 else increment_color(id, value, &color);
		 CMY_to_RGB(color, xcolor);
		 break;

	    case SpcHSV:
		 RGB_to_HSV(xcolor, val1, val2, val3);
		 if (set) assign_value(id, value, &val1, &val2, &val3);
		 else increment_value(id, value, &val1, &val2, &val3);
		 HSV_to_RGB(val1, val2, val3, xcolor);
		 break;

	    case SpcHLS:
		 RGB_to_HLS(xcolor, val1, val2, val3);
		 if (set) assign_value(id, value, &val1, &val2, &val3);
		 else increment_value(id, value, &val1, &val2, &val3);
		 HLS_to_RGB(val1, val2, val3, xcolor);
		 break;

	    case SpcGREY:
		 if (set)
		 {
		    xcolor.red   = ((short) value) << 8;
		    xcolor.green = ((short) value) << 8;
		    xcolor.blue  = ((short) value) << 8;
		 }
		 else
		 {
		    xcolor.red   += ((short) value) << 8;
		    xcolor.green += ((short) value) << 8;
		    xcolor.blue  += ((short) value) << 8;
		 }
		 break;
	}

	legend_ptr->red   = xcolor.red >> 8;
	legend_ptr->green = xcolor.green >> 8;
	legend_ptr->blue  = xcolor.blue >> 8;

	/* update color displayed on image */
       	for (i = 0; i < legend_ptr->clusternum; i++)
	{
	    xcolor_index = legend_ptr->clusters[i];
	    xvdisplay->xcolors[xcolor_index].red = xcolor.red;
	    xvdisplay->xcolors[xcolor_index].green = xcolor.green;
	    xvdisplay->xcolors[xcolor_index].blue = xcolor.blue;
	}
	xvd_update_xcolors(xvdisplay);

	/* update colorbox displayed in legend entry widget set if necc. */
	update_colorbox_from_img(legend_ptr);
	
	/* update RGB values displayed in legend entry widget set */
	i = 0;
        sprintf(temp, "RGB values:  %d %d %d", legend_ptr->red,
                legend_ptr->green, legend_ptr->blue);
	XtSetArg(arg[i], XtNlabel, xvf_strcpy(temp));               i++;
	XtSetValues(legend_ptr->entry_ptr->RGBwid, arg, i);
}

assign_color(id, value, xcolor)

int     id; 
double  value;
XColor	*xcolor;
{
	if (value < 0.0) value = 0.0;
	else if (value > MAX_INTEN) value = MAX_INTEN;

	/* update values stored w/ legend pointer */
	if (id == 0)
	    xcolor->red = value * 256.0;
	else if (id == 1) 
	    xcolor->green = value * 256.0;
	else if (id == 2) 
	    xcolor->blue = value * 256.0;
}

increment_color(id, value, xcolor)

int     id;
double  value;
XColor	*xcolor;
{
	/* update values stored w/ legend pointer */
	if (id == 0)
	    xcolor->red += value * 256.0;
	else if (id == 1) 
	    xcolor->green += value * 256.0;
	else if (id == 2)
	    xcolor->blue += value * 256.0;
}

assign_value(id, value, val1, val2, val3)

int     id;
double  value;
double  *val1, *val2, *val3;
{
	if (value < 0.0) value = 0.0;
	else if (value > 1.0) value = 1.0;

	/* update values stored w/ legend pointer */
	if (id == 0)
	    *val1 = value;
	else if (id == 1) 
	    *val2 = value;
	else if (id == 2) 
	    *val3 = value;
}

increment_value(id, value, val1, val2, val3)

int     id; 
double  value;
double  *val1, *val2, *val3;
{
	/* update values stored w/ legend pointer */
	if (id == 0)
	    *val1 += value;
	else if (id == 1) 
	    *val2 += value;
	else if (id == 2) 
	    *val3 += value;
}



/********************************************************
*
*  Routine Name:  add_cluster_from_img
*
*       Purpose:  This is the event handler that gets called
*		  when the user clicks the mouse in the image.
*		  Pops up a list of current classes to which 
*		  the user may add the cluster represented by
*		  the pixel under thier mouse pointer.
*
*         Input:  widget     -  the widget for the event
*                 clientData -  not used
*                 event      -  the ButtonPress event
*		  dispatch   - whether to allow event to propogate
*        Output:  none
*    Written By:  Danielle Argiro
*
********************************************************/

void add_cluster_from_img(widget, clientData, event, dispatch)
Widget  widget;
caddr_t clientData;
XEvent  *event;
Boolean *dispatch;
{
	int  i=0, dummy, cluster, status, listsize;
	char temp[MaxLength];
	char *prompt, *label, *realloc();
	char **classnames;
	legend_list *legend_ptr;
	XawListReturnStruct *class_list_return;

        cluster = get_cluster(widget, event->xbutton.x, event->xbutton.y);
	if (cluster == -1) 
	{
	    *dispatch = False;
	    return;
	}

	/* make sure they've named the last one */
	legend_ptr = spc_legend_list;
	while (legend_ptr != NULL)
	{
	    if (strcmp(legend_ptr->text, "New Category")==0)
	    {
	        xvf_error_wait("Please use the 'Legend' subform to assign a name & color to the last New Category before attempting further operations", "Spectrum", NULL);
	        *dispatch = false;
		return;
	    }
	    legend_ptr = legend_ptr->next;
	}

	if (spc_legend_list == NULL)
	{
	    sprintf(temp, "Add cluster %d to class:", cluster);
	}
	else if (spc_legend_lookup[cluster] != NULL)
	{
	    legend_ptr = spc_legend_lookup[cluster];
	    sprintf(temp, "Cluster number %d is already assigned to class %s. If you would like to transfer its membership to another class, click on TRANSFER; if you would like to delete the cluster from the class to which it is currently assigned, click on DELETE;  to cancel this action, click on CANCEL.", cluster, legend_ptr->text);
            status = xvf_exit_wait(temp, "Spectrum", "TRANSFER", 
				  "DELETE","CANCEL");
	    /* cancel */
	    if(status == -1)
	    {
	        *dispatch = false;
		return;
	    }
	    /* transfer */
	    else if (status == 1)
	    {
	        sprintf(temp,"Reassign cluster %d to class:", cluster);
	    }
	    /* delete */
	    else if (status == 0)
	    {
		delete_cluster_from_class(legend_ptr, cluster);
	        restore_old_values(legend_ptr, cluster);
		xvd_update_xcolors(xvdisplay);
                update_colorbox_from_legend(legend_ptr);
	        *dispatch = False;
		return;
	    }
	}
	else
	{
	    sprintf(temp, "Add cluster %d to class:", cluster);
	}

	/*
	 * put up list widget w/ text strings describing class categories
	 */
	prompt = xvf_strcpy(temp);
	label  = xvf_strcpy("Current Class Categories");
        classnames = create_category_list("New Category", SpcAll, 
					   &listsize, NULL, 0);
	class_list_return =  xvf_run_list_wait(classnames, listsize,
					      1, prompt, label, &dummy, False);

	if (class_list_return == NULL) 
	{
	    *dispatch = false;
	    return;
	}
	
        /*
         * if cluster was previously assigned, delete it from old
	 * class category
	 */
	if (spc_legend_lookup != NULL)
	{
            if (spc_legend_lookup[cluster] != NULL)
	    {
	        i = 0;
	        legend_ptr = spc_legend_lookup[cluster];
	        delete_cluster_from_class(legend_ptr, cluster);
		update_colorbox_from_legend(legend_ptr);
	    }
	}

	/*
	 * if they want to add a new category
	 */
	if (strcmp(class_list_return->string, "New Category") == 0)
	{
	    /* add a new legend category with cluster in it */
  	    add_legend_entry(cluster, "New Category");

	    /* update ScatterPlot subform "operation" logical to "add" */
	    xvf_change_input(form, 
	                     master_info.scatter_plot->scatter->operation_index,
			     xvf_logicalval_chng, "1", 30);
	    spc_plot_operation = 1;
	}

	else 
	{

	    /*
	     * find legend ptr assoc. w/ class chosen, 
	     * update text to be that of new class,
	     * and add cluster to new class
	     */
	    legend_ptr = find_legend_from_text(class_list_return->string);
	    free(legend_ptr->text); 
	    legend_ptr->text = xvf_strcpy(class_list_return->string);
	    add_cluster_to_class(legend_ptr, cluster);
	    current_entry = legend_ptr->entry_ptr;
	    update_colorbox_from_legend(legend_ptr);

	   /* update display with values from original map data */
            restore_old_values(legend_ptr, -1);
	    
	   /* update ScatterPlot subform "operation" logical to "add" */
	    xvf_change_input(form, 
	                     master_info.scatter_plot->scatter->operation_index,
			     xvf_logicalval_chng, "1", 30);
	    spc_plot_operation = 1;
	}

        /* update image w/ cluster numbers added (changed) in legend */
        update_xcolors_from_legend();

	for (i = 0; i < listsize; i++)
              free(classnames[i]);
	free(classnames); free(prompt); free(label);

	draw_single_marker(cluster, &(xvdisplay->xcolors[cluster]));
	*dispatch = False;
}


/****************************************************************
*
* Routine Name: add_cluster_to_class
*      Purpose: adds specified cluster to class
*	 Input: legend_ptr - points to legend node w/ class to be added to
*	Output: none
*   Written By: Danielle Argiro
*
****************************************************************/

add_cluster_to_class(legend_ptr, cluster)
legend_list *legend_ptr;
int cluster;
{
	int num_bytes;

	num_bytes = (legend_ptr->clusternum + 1)* sizeof(int);

	if (legend_ptr->clusters == NULL)
	     legend_ptr->clusters = (int *) malloc(sizeof(int));
	else legend_ptr->clusters = (int *) realloc(legend_ptr->clusters, 
					            num_bytes); 
	legend_ptr->clusters[legend_ptr->clusternum] = cluster;
	legend_ptr->clusternum++;
	spc_legend_lookup[cluster] = legend_ptr;

        legend_ptr->hidden = false;
}

/****************************************************************
*
* Routine Name: delete_cluster_from_class
*      Purpose: deletes specified cluster from class
*	 Input: legend_ptr - points to legend node w/ class to be deleted from
*	Output: none
*   Written By: Danielle Argiro
*
****************************************************************/
int delete_cluster_from_class(legend_ptr, cluster)
legend_list *legend_ptr;
int  cluster;
{
	int i = 0;

	/* find the cluster to be deleted */
	while ((legend_ptr->clusters[i] != cluster) &&
	       (i < legend_ptr->clusternum)) i++;

	/* return if cluster to be deleted is not in this class */
	if (i == legend_ptr->clusternum) return(false);

        legend_ptr->clusternum--;
	/* delete the cluster from the class */
        while (i < legend_ptr->clusternum)
        {
	    legend_ptr->clusters[i] = legend_ptr->clusters[i+1]; i++; 
        }
	spc_legend_lookup[cluster] = NULL;

	return(true);
}

/****************************************************************
*
* Routine Name: update_colorbox_from_legend
*      Purpose: updates the color box of a legend entry according to legend.
*	 Input: legend_ptr - points to legend node w/ colorbox to be updated.
*	Output: none
*   Written By: Danielle Argiro
*
****************************************************************/

update_colorbox_from_legend(legend_ptr)
legend_list *legend_ptr;
{
	int i;
	Arg arg[MaxArgs];

	i = 0;
	if (legend_ptr->clusternum == 0)
	{
	    XtSetArg(arg[i], XtNforeground, white); i++;
	    XtSetArg(arg[i], XtNbackground, white); i++;
	}
	else
	{
	    XtSetArg(arg[i], XtNforeground, 
		     xvdisplay->xcolors[legend_ptr->clusters[0]].pixel); i++;
	    XtSetArg(arg[i], XtNbackground, 
		     xvdisplay->xcolors[legend_ptr->clusters[0]].pixel); i++;
	}
	XtSetValues(legend_ptr->entry_ptr->colorbox, arg, i);
}
/****************************************************************
*
* Routine Name: update_colorbox_from_img
*      Purpose: updates the color box of a legend entry according to image.
*	 Input: legend_ptr - points to legend node w/ colorbox to be updated.
*	Output: none
*   Written By: Danielle Argiro
*
****************************************************************/

update_colorbox_from_img(legend_ptr)
legend_list *legend_ptr;
{
	int i, xcolor_index;
	Arg arg[MaxArgs];

	if (legend_ptr->clusters == NULL) return;
	i = 0;
	xcolor_index = legend_ptr->clusters[i];
	XtSetArg(arg[i], XtNforeground, 
		 xvdisplay->xcolors[xcolor_index].pixel); i++;
	XtSetArg(arg[i], XtNbackground, 
		 xvdisplay->xcolors[xcolor_index].pixel); i++;
	XtSetValues(legend_ptr->entry_ptr->colorbox, arg, i);
}


/****************************************************************
*
* Routine Name: update_legend_scrolls_from_colorbox
*      Purpose: updates the scroll bars in the legend according to color
*		shown in colorbox.
*	 Input: legend_ptr - points to legend node w/ colorbox to 
*		be updated in scroll bars.
*	Output: none
*   Written By: Danielle Argiro
*
****************************************************************/

update_legend_scrolls_from_colorbox(legend_ptr)
legend_list *legend_ptr;
{
	ScrollStruct  *scroll_data, *get_legend_scroll();
	double value, val1, val2, val3;
	XColor xcolor, color;

	xcolor.red   = legend_ptr->red   << 8;
	xcolor.green = legend_ptr->green << 8;
	xcolor.blue  = legend_ptr->blue  << 8;

	switch(spc_color_model)
	{
            case SpcRGB:
	         scroll_data = get_legend_scroll(0);
		 value = (double) legend_ptr->red;
	         set_scroll_thumb_to_value(scroll_data, value);
	         set_scroll_value_displayed(scroll_data, value);

		 scroll_data = get_legend_scroll(1);
		 value = (double) legend_ptr->green;
		 set_scroll_thumb_to_value(scroll_data, value);
		 set_scroll_value_displayed(scroll_data, value);

 		 scroll_data = get_legend_scroll(2);
		 value = (double) legend_ptr->blue;
		 set_scroll_thumb_to_value(scroll_data, value);
		 set_scroll_value_displayed(scroll_data, value);

		 break;

	    case SpcCMY:
		 RGB_to_CMY(xcolor, color);

	         scroll_data = get_legend_scroll(0);
		 value = (double) (color.red >> 8);
	         set_scroll_thumb_to_value(scroll_data, value);
	         set_scroll_value_displayed(scroll_data, value);

		 scroll_data = get_legend_scroll(1);
		 value = (double) (color.green >> 8);
		 set_scroll_thumb_to_value(scroll_data, value);
		 set_scroll_value_displayed(scroll_data, value);

 		 scroll_data = get_legend_scroll(2);
                 value = (double) (color.blue >> 8);
                 set_scroll_thumb_to_value(scroll_data, value);
                 set_scroll_value_displayed(scroll_data, value);

		 break;

	    case SpcHSV:
                 RGB_to_HSV(xcolor, val1, val2, val3);

		 scroll_data = get_legend_scroll(0);
		 value = val1;
		 set_scroll_thumb_to_value(scroll_data, value);
                 set_scroll_value_displayed(scroll_data, value);

		 scroll_data = get_legend_scroll(1);
		 value = val2;
		 set_scroll_thumb_to_value(scroll_data, value);
                 set_scroll_value_displayed(scroll_data, value);

		 scroll_data = get_legend_scroll(1);
		 value = val3;
		 set_scroll_thumb_to_value(scroll_data, value);
                 set_scroll_value_displayed(scroll_data, value);

		 break;

	    case SpcHLS:
		 RGB_to_HLS(xcolor, val1, val2, val3);

		 scroll_data = get_legend_scroll(0);
		 value = val1;
		 set_scroll_thumb_to_value(scroll_data, value);
                 set_scroll_value_displayed(scroll_data, value);

		 scroll_data = get_legend_scroll(1);
		 value = val2;
		 set_scroll_thumb_to_value(scroll_data, value);
                 set_scroll_value_displayed(scroll_data, value);

		 scroll_data = get_legend_scroll(2);
		 value = val3;
		 set_scroll_thumb_to_value(scroll_data, value);
                 set_scroll_value_displayed(scroll_data, value);

		 break;
		 
            case SpcGREY:
	         scroll_data = get_legend_scroll(0);
		 value = (double) legend_ptr->red;
	         set_scroll_thumb_to_value(scroll_data, value);
	         set_scroll_value_displayed(scroll_data, value);
		 break;
	}

}

