/****************************************************************************/
/*                                                                          */
/*  VolVis is a volume visualization system for investigating, manipulating */
/*  and rendering geometric and volumetric data.                            */
/*                                                                          */
/*  Copyright (C) 1993 by the Research Foundation of the State University   */
/*                            of New York                                   */
/*                                                                          */
/*  This program is free software; you can redistribute it and/or modify    */
/*  it under the terms of the GNU General Public License as published by    */
/*  the Free Software Foundation; either version 1, or (at your option)     */
/*  any later version.                                                      */
/*                                                                          */
/*  This program is distributed in the hope that it will be useful,         */
/*  but WITHOUT ANY WARRANTY; without even the implied warranty of          */
/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           */
/*  GNU General Public License for more details.                            */
/*                                                                          */
/*  You should have received a copy of the GNU General Public License       */
/*  along with this program; if not, write to the Free Software             */
/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               */
/*                                                                          */
/*  For information on VolVis, contact us at:                               */
/*                                                                          */
/*                volvis@cs.sunysb.edu                         (email)      */
/*                                                                          */
/*                Lisa Sobierajski & Ricardo Avila             (US Mail)    */
/*                Department of Computer Science                            */
/*                State University of New York at Stony Brook               */
/*                Stony Brook, New York  11794-4400                         */
/*                                                                          */
/****************************************************************************/




/*
 *			File: MOTIF_oco_modify_light.c 
 *		      Author: Cliff Bohm 
 *			Date: 02/28/93
 *		 Description: Motif Windowing Routines to alter the values of
 *		 	      the lights. (name, position, color, on/off) 
 *	Modification History:
 *
 *		Who?		When?		Why?
 *	--------------------------------------------------------------------
 *
 */

#include <stdio.h>
#include <math.h>
#include <Xm/Xm.h>
#include <Xm/RowColumn.h>
#include <X11/StringDefs.h>
#include <Xm/PushB.h>
#include <Xm/PushBG.h>
#include <Xm/BulletinB.h>
#include <Xm/LabelG.h>
#include <Xm/Text.h>
#include <Xm/TextF.h>
#include <Xm/DrawingA.h>
#include <Xm/Frame.h>
#include <Xm/Scale.h>

#include "C_volvis.h"
#include "MOTIF_windefs.h"
#include "C_help.h"
#include "C_oco.h"
#include <Xm/ToggleB.h>
#include <Xm/ToggleBG.h>

/* Global Variables For Motif Windowing */
/****
****/
/*
 *              Procedure Name: mod_PointLight
 *              Return Value:   none
 *              Input Variables:
 *                      light_index     - an int which is the index into
 *                                        world.lights[light_index]
 *
 *              Description:
 *                      In this procedure a pop up is created to contain all 
 *                      the widgets needed to alter a point light source. 
 *		   The feilds that can be altered are:
 *			name (a string)
 *			positon (a vector of floats)
 * 			Visiblity/Modifiablity
 *			color
 */

void oco_mod_pointlight(light_index)
int			light_index;
{
	extern C_ColorSelectInfo 	*C_create_color_selection();
	extern void 			oco_light_vis_CB();		
	extern void 			oco_light_mod_CB();	

	extern Widget			vv_toplevel;	
	extern C_WindowDefs		window_defs;
	extern C_World			world;
	extern C_ObjectControlInfo	oco_info;

	void close_callback();
	void help_callback();
	void oco_set_new_light();
	void oco_reset_old_light();

	Arg             args[20];
	int             n;
	OcoLightInfo	*linfo;

	Widget	frame;
	Widget	label;
	C_Color *light_color;
	Widget	toggle;
	Widget	rowcolumn, button;
	char	string[16];

	light_color=&(world.light[light_index]->light.light_point->light_color);

	oco_info.light_info[light_index] = linfo = C_New( OcoLightInfo );

	if ( !linfo )
	{
		C_error_message("Not enough memory left to modify light!\n");
		return;
	}

	n=0;
	XtSetArg( args[n], XmNautoUnmanage, False ); n++;
	C_Set_Color_Dialog( args, n, window_defs );
	linfo->light_displayed = XmCreateBulletinBoardDialog(
			vv_toplevel,
                       	"modify_PointLight", args, n );

	/****** Light Name                  *******/
	/****** a label and a text widget,  *******/
	/****** which shows the name of the *******/
	/****** light, and which can be     *******/
	/******  changed                    *******/
	
	n = 0;
        XtSetArg( args[n], XmNx, 0 ); n++;
        XtSetArg( args[n], XmNy, 0 ); n++;
        C_Set_Color_Frame( args, n, window_defs );

	label = 
		XmCreateLabelGadget(linfo->light_displayed, "Light Name:",
				       args, n );
	XtManageChild(label);
	n=0;
        XtSetArg( args[n], XmNx, 120 ); n++;
        XtSetArg( args[n], XmNy, 0 ); n++;
        XtSetArg( args[n], XmNcolumns, 15 ); n++;
        XtSetArg( args[n], XmNvalue, world.light[light_index]->light_name); n++;
        C_Set_Color_Text( args, n, window_defs );
        linfo->light_name = XmCreateTextField( linfo->light_displayed,
                                 "light_name", args, n );
        XtManageChild(  linfo->light_name );

	/****** Visiblity/Modifiablity  *********/
	/****** for both Visiblity and  *********/
	/****** Modifiablity there is a *********/
	/****** labeled toggle widget   *********/         
	n=0;
        XtSetArg( args[n], XmNx, 0); n++;
        XtSetArg( args[n], XmNy, 330 ); n++;
        C_Set_Color_ToggleGadget( args, n, window_defs );
        XtSetArg( args[n], XmNset, (world.light[light_index])->visible ); n++;
        toggle = XmCreateToggleButtonGadget
			( linfo->light_displayed,
                          "Visible", args, n );
        XtAddCallback( toggle, XmNvalueChangedCallback,
                               oco_light_vis_CB, light_index );
        XtManageChild( toggle );

	n=0;
        XtSetArg( args[n], XmNx, 100 ); n++;
        XtSetArg( args[n], XmNy, 330 ); n++;
        C_Set_Color_ToggleGadget( args, n, window_defs );
        XtSetArg( args[n], XmNset, (world.light[light_index])->modifiable );n++;
        toggle = XmCreateToggleButtonGadget
			( linfo->light_displayed,
		          "Modifiable", args, n );
        XtAddCallback( toggle, XmNvalueChangedCallback,
                       oco_light_mod_CB, light_index );
        XtManageChild( toggle );
	
	
	n=0;
        XtSetArg( args[n], XmNx, 0 ); n++;
        XtSetArg( args[n], XmNy, 50); n++;
	label = XmCreateLabelGadget(linfo->light_displayed,
                                       "X Position:",
                                       args, n );
	XtManageChild( label );
	
	n=0;
        XtSetArg( args[n], XmNx, 120 ); n++;
        XtSetArg( args[n], XmNy, 50 ); n++;
        XtSetArg( args[n], XmNcolumns, 15 ); n++;
        sprintf( string, "%f",
		 world.light[light_index]->light.light_point->light_pos.x );
	XtSetArg( args[n], XmNvalue, string); n++;
	C_Set_Color_Text( args, n, window_defs );
        linfo->light_position_x =
		 XmCreateTextField(linfo->light_displayed,
                 "position_X", args, n );
        XtManageChild(  linfo->light_position_x );



        n=0;
        XtSetArg( args[n], XmNx, 0 ); n++;
        XtSetArg( args[n], XmNy, 80); n++;
        label= XmCreateLabelGadget(linfo->light_displayed,
                                       "Y Position:",
                                       args, n );
        XtManageChild( label );       


        n=0;
        XtSetArg( args[n], XmNx, 120 ); n++;
        XtSetArg( args[n], XmNy, 80 ); n++;
        XtSetArg( args[n], XmNcolumns, 15 ); n++;
        sprintf( string, "%f", 
		 world.light[light_index]->light.light_point->light_pos.y );
        XtSetArg( args[n], XmNvalue, string); n++; 
        C_Set_Color_Text( args, n, window_defs );
        linfo->light_position_y = 
		XmCreateTextField( linfo->light_displayed,
                "position_Y", args, n );
        XtManageChild(  linfo->light_position_y );

        n=0;
        XtSetArg( args[n], XmNx, 0 ); n++;
        XtSetArg( args[n], XmNy, 110); n++;
        label = XmCreateLabelGadget(linfo->light_displayed,
                                       "Z Position:",
                                       args, n );
        XtManageChild( label );       

        n=0;
        XtSetArg( args[n], XmNx, 120 ); n++;
        XtSetArg( args[n], XmNy, 110 ); n++;
        XtSetArg( args[n], XmNcolumns, 15 ); n++;
        sprintf( string, "%f",
		 world.light[light_index]->light.light_point->light_pos.z );
        XtSetArg( args[n], XmNvalue, string); n++; 
        C_Set_Color_Text( args, n, window_defs );
        linfo->light_position_z =
		 XmCreateTextField( linfo->light_displayed,
                 "position_Z", args, n );
        XtManageChild(  linfo->light_position_z );




        n=0;
        XtSetArg( args[n], XmNx, 0 ); n++;
        XtSetArg( args[n], XmNy, 140 ); n++;
        label = XmCreateLabelGadget(linfo->light_displayed,
                                       "Light Intensity:",
                                       args, n );
        XtManageChild( label );

        n=0;
        XtSetArg( args[n], XmNx, 120 ); n++;
        XtSetArg( args[n], XmNy, 140 ); n++;
        XtSetArg( args[n], XmNcolumns, 15 ); n++;
        sprintf( string, "%f",
                 world.light[light_index]->light.light_point->light_intensity );
        XtSetArg( args[n], XmNvalue, string); n++;
        C_Set_Color_Text( args, n, window_defs );
        linfo->light_intensity =
                 XmCreateTextField(linfo->light_displayed,
                 "light_intensity", args, n );
        XtManageChild(  linfo->light_intensity );

	linfo->light_color_selector = C_create_color_selection(
				 linfo->light_displayed,
                                 0, 180,
                                 "Light Color:", "",
				 light_color);

        
	n = 0;
        XtSetArg( args[n], XmNorientation, XmHORIZONTAL ); n++;
       	XtSetArg( args[n], XmNy, 370 ); n++;
        C_Set_Color_RowColumn( args, n, window_defs );
        rowcolumn =
                XmCreateRowColumn( linfo->light_displayed,
					 "rowcolumn", args, n);
        XtManageChild (rowcolumn);


        n = 0;
        C_Set_Color_Button( args, n, window_defs );
        button = XtCreateManagedWidget("Accept",
                        xmPushButtonWidgetClass, rowcolumn, args, n );

        XtAddCallback( button, XmNactivateCallback,
                       oco_set_new_light, light_index);


        n = 0;
        C_Set_Color_Button( args, n, window_defs );
        button = XtCreateManagedWidget("Cancel",
                        xmPushButtonWidgetClass, rowcolumn, args, n );

        XtAddCallback( button, XmNactivateCallback,
                       oco_reset_old_light,light_index );
        
	n=0;
        C_Set_Color_Button( args, n, window_defs );
        button = XtCreateManagedWidget( "Close",
                xmPushButtonWidgetClass, rowcolumn, args, n );
        XtAddCallback( button, XmNactivateCallback,
                       close_callback, linfo->light_displayed);

        n = 0;
        C_Set_Color_Button( args, n, window_defs );
        button = XtCreateManagedWidget("Help",
                        xmPushButtonWidgetClass, rowcolumn, args, n );
        XtAddCallback( button, XmNactivateCallback,
                       help_callback, C_OCO_MODIFY_LIGHT_HELP );

	XtManageChild(linfo->light_displayed);		
}



/*
 *		Procedure Name:	oco_set_new_light
 *		Return Value:	none
 *		Input Variables:
 *			w		- the widget which was activated
 *				 	  (in this case the accept button)
 *			light_index	- an int which is the index into
 *					  world.lights[light_index]
 *			call_data
 *
 *		Description:
 *			First the colors are set, then the x,y,z position
 *			then the name, and lastly, the tranformation matrix
 *			is updated.
 */

void oco_set_new_light( w,light_index, call_data )
Widget                  w;
int       		light_index;
XtPointer               call_data;
{
	extern int 	C_check_for_name();
	extern void 	update_oco_control_window();
	extern void 	update_oco_active_opt();

	extern C_ObjectControlInfo	oco_info;
	extern C_World			world;

	int            	tmp_val,error = 0,index_check;
	char    	*string,*ptr;
	C_Matrix        M;
	float		ox,oy,oz;
	OcoLightInfo	*linfo;


	linfo = oco_info.light_info[light_index];

	string= (char *)XmTextGetString(linfo->light_name);
	index_check = C_check_for_name( &world, string);
	if((index_check) && (index_check != light_index+world.num_volumes+1))
	{
	   C_error_message("The name has already been used\n");
	   error = 1;
	}
	string = (char *)XmTextGetString(
                        linfo->light_position_x);
	if((string != NULL) && (*string != NULL))
	{
		ptr = string;
		strtod(string,&ptr);
		if ((ptr != NULL) && (*ptr != NULL))
		{
			C_error_message(
			   "The input for X position is invalid.\n");
			error = 1;
		}
	}
	else
	{
		C_error_message("There is no value for X position.\n");
		error = 1;
	}
        string = (char *)XmTextGetString(
                        linfo->light_position_y);
        if((string != NULL) && (*string != NULL))
        {
                ptr = string;
                strtod(string,&ptr);
                if ((ptr != NULL) && (*ptr != NULL))
                {
                	C_error_message(
			   "The input for Y position is invalid.\n");
                        error = 1;
                }
        }
        else
        {
                C_error_message("There is no value for Y position.\n");
                error = 1;
        }
        string = (char *)XmTextGetString(
                        linfo->light_position_z);
        if((string != NULL) && (*string != NULL))
        {
                ptr = string;
                strtod(string,&ptr);
                if ((ptr != NULL) && (*ptr != NULL))
                {
                	C_error_message(
			   "The input for Z position is invalid.\n");
                        error = 1;
                }
        }
        else
        {
                C_error_message("There is no value for Z position.\n");
                error = 1;
        }
        string = (char *)XmTextGetString(
                        linfo->light_intensity);
        if((string != NULL) && (*string != NULL))
        {
                ptr = string;
                strtod(string,&ptr);
                if ((ptr != NULL) && (*ptr != NULL))
                {
                	C_error_message(
			   "The input for light intensity is invalid.\n");
			error = 1;
                }
        }
        else
        {
                C_error_message("There is no value for light intensity.\n");
                error = 1;
        }
	

	if (!error)
	{	

	XmScaleGetValue( linfo->light_color_selector->
			 red_slider, &tmp_val);
	world.light[light_index]->light.light_point->light_color.red = 
								tmp_val;

        XmScaleGetValue( linfo->light_color_selector->
			 green_slider, &tmp_val); 
	world.light[light_index]->light.light_point->light_color.green =
								 tmp_val;

        XmScaleGetValue( linfo->light_color_selector->
			 blue_slider, &tmp_val);
        world.light[light_index]->light.light_point->light_color.blue =
								 tmp_val;

	ox = world.light[light_index]->light.light_point->light_pos.x;
	oy = world.light[light_index]->light.light_point->light_pos.y;
	oz = world.light[light_index]->light.light_point->light_pos.z;

	string = (char *)XmTextGetString(
			linfo->light_position_x);
	world.light[light_index]->light.light_point->light_pos.x =
			atof( string );

	string = (char *)XmTextGetString(
			linfo->light_position_y);
	world.light[light_index]->light.light_point->light_pos.y = 
			atof( string );

        string = (char *)XmTextGetString(
			linfo->light_position_z);
	world.light[light_index]->light.light_point->light_pos.z = 
			atof( string );

	string = (char *)XmTextGetString(
                        linfo->light_intensity);
	world.light[light_index]->light.light_point->light_intensity=
			atof( string );

	
	world.light[light_index]->light_name =
		(char *)XmTextGetString(linfo->light_name);


	   C_translate3D(
	      world.light[light_index]->light.light_point->light_pos.x - ox,
	      world.light[light_index]->light.light_point->light_pos.y - oy,
	      world.light[light_index]->light.light_point->light_pos.z - oz,
	      &M );
	   C_matrix_multiply( C_POST_MULTIPLY,
	      &world.light[light_index]->light.light_point->transform,
	      &M);

	update_oco_control_window();
	update_oco_active_opt();
	}
}


/*
 *              Procedure Name: reset_old_light
 *              Return Value:   none
 *              Input Variables:
 *                      w               - the widget which was activated
 *                                        (in this case the accept button)
 *                      light_index     - an int which is the index into
 *                                        world.lights[light_index]
 *                      call_data
 *
 *              Description:
 *                      This procedure resets all the values of the widgets 
 *                      to the values that are in the world.light[light_index] 
 *                      stucture.
 */


void oco_reset_old_light( w, light_index, call_data )
Widget                  w;
int      		light_index;
XtPointer               call_data;
{
	extern C_ObjectControlInfo	oco_info;
	extern C_World			world;

	Arg             args[1];
	char    	string[16];
	OcoLightInfo	*linfo;

	linfo = oco_info.light_info[light_index];

	XtSetArg( args[0], XmNvalue,
		 (int) (world.light[light_index]->light.light_point->
			light_color.red) );
	XtSetValues( linfo->light_color_selector->red_slider,
		     args, 1 );

        XtSetArg( args[0], XmNvalue,
                 (int) (world.light[light_index]->light.light_point->
			light_color.green) );
        XtSetValues( linfo->light_color_selector->green_slider,
		     args, 1 );

        XtSetArg( args[0], XmNvalue,
                 (int) (world.light[light_index]->light.light_point->
			light_color.blue) );
        XtSetValues( linfo->light_color_selector->blue_slider,
		     args, 1 );

        C_change_color(  linfo->light_color_selector->red_slider,
                          linfo->light_color_selector, NULL );
 

	sprintf( string, "%f", world.light[light_index]->light.light_point->
			       light_pos.x );
        XtSetArg( args[0], XmNvalue, string);
	XtSetValues( linfo->light_position_x, args, 1 );

	sprintf( string, "%f", world.light[light_index]->light.light_point->
			       light_pos.y );
        XtSetArg( args[0], XmNvalue, string);
        XtSetValues( linfo->light_position_y, args, 1 );

	sprintf( string, "%f", world.light[light_index]->light.light_point->
			       light_pos.z );
        XtSetArg( args[0], XmNvalue, string); 
	XtSetValues( linfo->light_position_z, args, 1 );		

	sprintf( string, "%f", world.light[light_index]->light.light_point->
                               light_intensity );
	XtSetArg( args[0], XmNvalue, string);
	XtSetValues( linfo->light_intensity, args, 1 );


	XtSetArg( args[0], XmNvalue, world.light[light_index]->light_name);
	XtSetValues( linfo->light_name, args, 1 );
}


/*
 *              Procedure Name: oco_create_light_display 
 *              Return Value:   none
 *              Input Variables:
 *                      light_index     - an int which is the index into
 *                                        world.lights[light_index]
 *              Description:
 *                      this prcedure calls the correct  modify procedure 
 *                      based on what the type of the light is.
 */

void oco_create_light_display( light_index )
int			light_index;
{
	extern C_World	world;

	switch ( world.light[light_index]->light_type )
	{
		case C_POINT_LIGHT:
			oco_mod_pointlight(light_index);
		break;

	default:
		C_error_message("Cannot alter that type of light yet!!!\n ");
		break;
	}
}
