/* :ts=8 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>

#include "general.h"
#include "globals.h"
#include "intui.h"
#include "timer.h"
#include "spl_math.h"
#include "spl_util.h"
#include "spl_gfx.h"
#include "scale_g.h"

/* Get Stringinfo buffer for the Scale_Group gadget with id 'G':	*/
#define Get_Gadget_String(G) (((struct StringInfo *) \
			(Scale_GroupGadgets[G]->SpecialInfo))->Buffer)

	/* Set string to 'S' in string gadget 'G':	*/
#define Set_Gadget_String(G, S) \
		GT_SetGadgetAttrs(Scale_GroupGadgets[G], \
			Windows[W_Scale_Group].Window, NULL, \
			GTST_String, S)

	/* Set check state to  to 'On_Off' in check gadget 'G':	*/
#define Set_Gadget_State(G, On_Off) \
		GT_SetGadgetAttrs(Scale_GroupGadgets[G], \
			Windows[W_Scale_Group].Window, NULL, \
			GTCB_Checked, (BOOL) (On_Off))

	/* Get gadget state for check gadget 'G':	*/
#define Get_Gadget_State(G) \
		(Scale_GroupGadgets[G]->Flags & GFLG_SELECTED)

static Boolean_T	Scale_Group_Active;
static short		Orig_Scale_Group_X;
static short		Prev_Scale_Group_X;
static double		Scale_Group_Factor;
static Vector_T		Box_Min, Box_Max;

static
void Set_Scale_Group_Factor_Value(double Factor)
/************************************************************************/
/*                                                                      */
/* Set scale factor value gadget to 'Factor'.				*/
/*                                                                      */
/************************************************************************/
{
    char Buffer[Buffer_Length+1];

    if (Windows[W_Scale_Group].Window == NULL) return;

    sprintf(Buffer, " %.2lf", Factor);
    Set_Gadget_String(GDX_Scale_Group_Factor_Value, Buffer);

} /* Set_Scale_Group_Factor_Value */

static 
void Scale_Group_Timeout()
/************************************************************************/
/*                                                                      */
/* Function called when timer expires: Draw all splines.		*/
/*                                                                      */
/************************************************************************/
{    
    Boolean_T	Do_Scale_Group_X;
    Boolean_T	Do_Scale_Group_Y;
    Boolean_T	Do_Scale_Group_Z;

    Do_Scale_Group_X =  Get_Gadget_State(GDX_Scale_Group_X);
    Do_Scale_Group_Y =  Get_Gadget_State(GDX_Scale_Group_Y);
    Do_Scale_Group_Z =  Get_Gadget_State(GDX_Scale_Group_Z);

    Points_Scale(Scale_Group_Factor, 
		 Do_Scale_Group_X, Do_Scale_Group_Y, Do_Scale_Group_Z);

    Compute_Splines();
    Clear_All(What_All);
    Draw_All(What_All);

    Redraw_Mask = 0;
    Stop_Timer();

} /* Scale_Group_Timeout */

static 
void Scale_Group_Redraw(long What)
/************************************************************************/
/*                                                                      */
/* Function called to redraw screen while scaling points.		*/
/*                                                                      */
/************************************************************************/
{    
    Boolean_T	Do_Scale_Group_X;
    Boolean_T	Do_Scale_Group_Y;
    Boolean_T	Do_Scale_Group_Z;
    Vector_T	B_Min, B_Max;

    if (Windows[W_Scale_Group].Window == NULL) return;

    Set_Scale_Group_Factor_Value(Scale_Group_Factor);

    Do_Scale_Group_X =  Get_Gadget_State(GDX_Scale_Group_X);
    Do_Scale_Group_Y =  Get_Gadget_State(GDX_Scale_Group_Y);
    Do_Scale_Group_Z =  Get_Gadget_State(GDX_Scale_Group_Z);

    if (Do_Scale_Group_X) {
	B_Min[0] = Scale_Group_Factor * Box_Min[0];
	B_Max[0] = Scale_Group_Factor * Box_Max[0];
    } else {
	B_Min[0] = Box_Min[0];
	B_Max[0] = Box_Max[0];
    }
    if (Do_Scale_Group_Y) {
	B_Min[1] = Scale_Group_Factor * Box_Min[1];
	B_Max[1] = Scale_Group_Factor * Box_Max[1];
    } else {
	B_Min[1] = Box_Min[1];
	B_Max[1] = Box_Max[1];
    }
    if (Do_Scale_Group_Z) {
	B_Min[2] = Scale_Group_Factor * Box_Min[2];
	B_Max[2] = Scale_Group_Factor * Box_Max[2];
    } else {
	B_Min[2] = Box_Min[2];
	B_Max[2] = Box_Max[2];
    }

    Clear_Plane(3, What_All);
    Draw_Box(B_Min, B_Max, NULL, DM_Plane, What_All);

    Start_Timer(Delay_Draw_Seconds, Delay_Draw_Micros);
    Redraw_Mask = 0;

} /* Scale_Group_Redraw */

static
void Scale_Group_Select_Up(short X, short Y)
/************************************************************************/
/*                                                                      */
/* X, Y are the actual coordinates in the active window.		*/
/*                                                                      */
/************************************************************************/
{
	/* If the timer hasn't expired, then call the timeout handler to*/
	/* compute and draw the splines.				*/

    if (!Check_Timer()) Scale_Group_Timeout();

    Set_Scale_Group_Factor_Value(1.0);
    Set_Mode_Normal();

} /* Scale_Group_Select_Up */

static 
void Scale_Group_Select_Down(short X, short Y)
/************************************************************************/
/*                                                                      */
/* X, Y are the actual coordinates in the active window.		*/
/*                                                                      */
/************************************************************************/
{

    if (X < 0) return;
    if (Get_Select_Bounding_Box(Box_Min, Box_Max)) {
	Display_Message("No points selected");
	return;
    }
    Draw_Box(Box_Min, Box_Max, NULL, DM_Plane, What_All);

    Scale_Group_Active = TRUE;

    Orig_Scale_Group_X = X;
    Prev_Scale_Group_X = X;

    Scale_Group_Factor = 1.0;

    if (MQ_Size_Scale_G > 0) {
	SetMouseQueue(Windows[Id_Active_Window].Window, MQ_Size_Scale_G); 
	Redraw_Always = TRUE;
    } else Redraw_Always = FALSE;

} /* Scale_Group_Select_Down */

static 
void  Scale_Group_Move(short X, short Y)
/************************************************************************/
/*                                                                      */
/* Function called when mouse is moved to scale points.			*/
/* X, Y are the actual coordinates in the active window.		*/
/*                                                                      */
/************************************************************************/
{
    if (X < 0) return;

    if (!Scale_Group_Active) return;
    if (ABS(X - Prev_Scale_Group_X) < 5) return;

    Scale_Group_Factor = (X - Orig_Scale_Group_X);
    Scale_Group_Factor = 1.0 + (Scale_Group_Factor / 100.0);

    Prev_Scale_Group_X = X;

    if (Redraw_Always) Scale_Group_Redraw(What_All);
    else               Redraw_Mask = What_All;

} /* Scale_Group_Move */

static
Boolean_T Scale_Group_Handle_Event(struct IntuiMessage *Msg)
/************************************************************************/
/*                                                                      */
/* Event handler routine for the 'SCALE GROUP' mode.			*/
/* Events handled:							*/
/*	Select down: Start scaling.					*/
/*	Select up  : Stop scaling.					*/
/*	Mouse move : Change scale factor.				*/
/*                                                                      */
/************************************************************************/
{

    switch (Msg->Class) {


    case IDCMP_MOUSEBUTTONS:
		/* Msg->Code contain id of button pressed 		*/
		/* Msg->MouseX and Msg->MouseY contain mouse position 			*/

	switch (Msg->Code) {

	case SELECTDOWN:
	    Scale_Group_Select_Down(Msg->MouseX, Msg->MouseY);
	    return(TRUE);

	case SELECTUP:
	    Scale_Group_Select_Up(Msg->MouseX, Msg->MouseY);
	    return(TRUE);

	} /* switch (Msg->Code) */
	break;

    case IDCMP_MOUSEMOVE:
	Scale_Group_Move(Msg->MouseX, Msg->MouseY);
	return(TRUE);

    } /* switch (Msg->Class) */

    return(FALSE);

} /* Scale_Group_Handle_Event */

void Handle_Scale_Group_Factor()
/************************************************************************/
/*                                                                      */
/* Change to SCALE GROUP mode.						*/
/*                                                                      */
/************************************************************************/
{
    if (Windows[W_Scale_Group].Window == NULL) return;

    Scale_Group_Active		= FALSE;
    State.Handle_Event		= Scale_Group_Handle_Event;
    State.Timeout		= Scale_Group_Timeout;
    State.Redraw		= Scale_Group_Redraw;

    sprintf(Error_Msg, "Scale group");
    Display_Status(Error_Msg);

    Points_Save();

} /* Handle_Scale_Group_Factor */

void Handle_Scale_Group_Factor_Value()
/************************************************************************/
/*                                                                      */
/* Handle a Scale_Group_Factor_Value gadget event.			*/
/*                                                                      */
/************************************************************************/
{
    Boolean_T	Do_Scale_Group_X;
    Boolean_T	Do_Scale_Group_Y;
    Boolean_T	Do_Scale_Group_Z;

    if (Windows[W_Scale_Group].Window == NULL) return;

    Points_Save();
    Scale_Group_Factor = atof(Get_Gadget_String(GDX_Scale_Group_Factor_Value));
    Do_Scale_Group_X   =  Get_Gadget_State(GDX_Scale_Group_X);
    Do_Scale_Group_Y   =  Get_Gadget_State(GDX_Scale_Group_Y);
    Do_Scale_Group_Z   =  Get_Gadget_State(GDX_Scale_Group_Z);

    Points_Scale(Scale_Group_Factor, 
	         Do_Scale_Group_X, Do_Scale_Group_Y, Do_Scale_Group_Z);

    Scale_Group_Timeout(); /* Compute and draw the splines */

    Set_Scale_Group_Factor_Value(1.0);

} /* Handle_Scale_Group_Factor_Value */
