/* :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 "knotinfo.h"

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

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

	/* Set string to 'S' in TEXT gadget 'G':	*/
#define Knot_Set_Gadget_Text(G, S) \
		GT_SetGadgetAttrs(KnotInfoGadgets[G], \
			Windows[W_KnotInfo].Window, NULL, \
			GTTX_Text, S)

	/* Set number to 'N' in number gadget 'G':	*/
#define Knot_Set_Gadget_Number(G, N) \
		GT_SetGadgetAttrs(KnotInfoGadgets[G], \
			Windows[W_KnotInfo].Window, NULL, \
			GTNM_Number, (long) (N))

static char	Knot_Pos_X_Text[20];
static char	Knot_Pos_Y_Text[20];
static char	Knot_Pos_Z_Text[20];

static Boolean_T Modify_Active;
static short  	Modify_Mode = 0;	/* 0: tension, 1:bias, 2: cont.	*/
static short  	Old_Modify_X;
static double 	Old_Value;
static double 	Current_Value;


void KnotInfo_Show_Pos(Vector_T Pos)
/************************************************************************/
/*                                                                      */
/*                                                                      */
/************************************************************************/
{
    char Buffer[Buffer_Length+1];

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

    sprintf(Knot_Pos_X_Text, " %.2lf", Pos[0]);
    Knot_Set_Gadget_Text(GDX_G_Knot_Pos_X, Knot_Pos_X_Text);

    sprintf(Knot_Pos_Y_Text, " %.2lf", Pos[1]);
    Knot_Set_Gadget_Text(GDX_G_Knot_Pos_Y, Knot_Pos_Y_Text);

    sprintf(Knot_Pos_Z_Text, " %.2lf", Pos[2]);
    Knot_Set_Gadget_Text(GDX_G_Knot_Pos_Z, Knot_Pos_Z_Text);


} /* KnotInfo_Show_Pos */

void KnotInfo_Show_Spline_Info(double Tension, double Bias, double Continuity)
/************************************************************************/
/*                                                                      */
/*                                                                      */
/************************************************************************/
{
    char Buffer[Buffer_Length+1];
    if (Windows[W_KnotInfo].Window == NULL) return;

    sprintf(Buffer, " %.2lf", Tension);
    Knot_Set_Gadget_String(GDX_G_Tension_Value, Buffer);

    sprintf(Buffer, " %.2lf", Bias);
    Knot_Set_Gadget_String(GDX_G_Bias_Value, Buffer);

    sprintf(Buffer, " %.2lf",  Continuity);
    Knot_Set_Gadget_String(GDX_G_Continuity_Value, Buffer);

} /* KnotInfo_Show_Spline_Info */

void KnotInfo_Show_Info(Spline_T *Spline, Knot_T *Knot)
/************************************************************************/
/*                                                                      */
/* Display spline/knot id and tension/bias/continuity info.		*/
/*                                                                      */
/************************************************************************/
{
    double 	Tension;
    double 	Bias;
    double 	Continuity;
    short  	Point_Id;
    Vector_T	Pos;

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

    if (Knot != NULL) Point_Id = Knot->Point_Id;
    else              Point_Id = -1;

    Knot_Set_Gadget_Number(GDX_G_Point_Id, Point_Id);

    if (Spline == NULL || Knot == NULL) {

        Tension    = 0.0;
	Bias       = 0.0;
	Continuity = 0.0;

	Pos[0] = Pos[1] = Pos[2] = 0.0;

	KnotInfo_Show_Pos(Pos);

    } else {

        Tension    = Knot->Tension;
	Bias       = Knot->Bias;
	Continuity = Knot->Continuity; 
	Point_Id   = Knot->Point_Id;

	KnotInfo_Show_Pos(Points[Point_Id].Pos);

    } /* if .. else .. */

    KnotInfo_Show_Spline_Info(Tension, Bias, Continuity); 

} /* KnotInfo_Show_Info */

void Handle_G_Tension_Value()
/************************************************************************/
/*                                                                      */
/*                                                                      */
/************************************************************************/
{
    char Buffer[Buffer_Length+1];

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

    Current_Value = atof(Knot_Get_Gadget_String(GDX_G_Tension_Value));
    sprintf(Buffer, " %.2lf",  Current_Value);
    Current_Value = atof(Buffer);
    Knot_Set_Gadget_String(GDX_G_Tension_Value, Buffer);

    if (Group_Mode) {

	Points_Set_Tension(Current_Value);
	Compute_Splines();

    } else if (Select_Knot != NULL) {

	Select_Knot->Tension = Current_Value;
	Compute_Marked_Segments();

    } /* if .. else .. */

    Redraw_Mask |= What_All;

} /* Handle_G_Tension_Value */

void Handle_G_Bias_Value()
/************************************************************************/
/*                                                                      */
/*                                                                      */
/************************************************************************/
{
    char Buffer[Buffer_Length+1];

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

    Current_Value = atof(Knot_Get_Gadget_String(GDX_G_Bias_Value));
    sprintf(Buffer, " %.2lf",  Current_Value);
    Current_Value = atof(Buffer);
    Knot_Set_Gadget_String(GDX_G_Bias_Value, Buffer);

    if (Group_Mode) {

	Points_Set_Bias(Current_Value);
	Compute_Splines();

    } else if (Select_Knot != NULL) {

	Select_Knot->Bias = Current_Value;
	Compute_Marked_Segments();

    } /* if .. else .. */

    Redraw_Mask |= What_All;

} /* Handle_G_Bias_Value */

void Handle_G_Continuity_Value()
/************************************************************************/
/*                                                                      */
/*                                                                      */
/************************************************************************/
{
    char Buffer[Buffer_Length+1];

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

    Current_Value = atof(Knot_Get_Gadget_String(GDX_G_Continuity_Value));
    sprintf(Buffer, " %.2lf",  Current_Value);
    Current_Value = atof(Buffer);
    Knot_Set_Gadget_String(GDX_G_Continuity_Value, Buffer);


    if (Group_Mode) {

	Points_Set_Continuity(Current_Value);
	Compute_Splines();

    } else if (Select_Knot != NULL) {

	Select_Knot->Continuity =  Current_Value;
	Compute_Marked_Segments();

    } /* if .. else .. */

    Redraw_Mask |= What_All;

} /* Handle_G_Continuity_Value */

static
void Modify_KnotInfo_Timeout()
/************************************************************************/
/*                                                                      */
/* Function called when timer expires: Draw all splines.            	*/
/*                                                                      */
/************************************************************************/
{
    Compute_Splines();
    Clear_All(What_All);
    Draw_All(What_All);
    Draw_Marked_Segments(DM_Erase, What_S);
    Draw_Marked_Segments(DM_Plane, What_S);

    Stop_Timer();

} /* Modify_KnotInfo_Timeout */

static
void Modify_KnotInfo_Redraw(long Mask)
/************************************************************************/
/*                                                                      */
/* Function called to redraw the screen while changing spline parms.	*/
/*                                                                      */
/************************************************************************/
{
    char	Buffer[Buffer_Length+1];

    switch (Modify_Mode) {

    case 0:	/* Tension */
        sprintf(Buffer, " %.2lf",  Current_Value);
	Knot_Set_Gadget_String(GDX_G_Tension_Value, Buffer);

	if (Group_Mode) {
	    Points_Set_Tension(Current_Value);
	} else {
	    Select_Knot->Tension = Current_Value;
 	}
	break;

    case 1:	/* Bias */
        sprintf(Buffer, " %.2lf",  Current_Value);
	Knot_Set_Gadget_String(GDX_G_Bias_Value, Buffer);
	if (Group_Mode) {
	    Points_Set_Bias(Current_Value);
	} else {
	    Select_Knot->Bias = Current_Value;
	}
	break;

    case 2: 	/* Continuity */
        sprintf(Buffer, " %.2lf",  Current_Value);
	Knot_Set_Gadget_String(GDX_G_Continuity_Value, Buffer);
	if (Group_Mode) {
	    Points_Set_Continuity(Current_Value);
	} else {
	    Select_Knot->Continuity = Current_Value;
	}
	break;

    } /* switch */

	/* Only update selected knot until timeout, then draw all */

    Compute_Marked_Segments();
    Clear_Plane(3, What_All);
    Draw_Marked_Segments(DM_Plane, What_S);

    if (Group_Mode) Start_Timer(Delay_Draw_Seconds, Delay_Draw_Micros);

    Redraw_Mask = 0;

} /* Modify_KnotInfo_Redraw */

static
void Modify_KnotInfo_Select_Up()
/************************************************************************/
/*                                                                      */
/* Function called to redraw the screen while changing spline parms.	*/
/*                                                                      */
/************************************************************************/
{
   
    if (Group_Mode) {

	/* If the timer hasn't expired, we need to compute and redraw   */
	/* all.								*/

	if (!Check_Timer()) {

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

    }

    Clear_Plane(3, What_All);
    Draw_Marked_Segments(DM_Normal, What_S);

    Stop_Timer();
    Set_Mode_Normal();

} /* Modify_KnotInfo_Select_Up */

static void  Modify_KnotInfo_Select_Down(short X, short Y)
/************************************************************************/
/*                                                                      */
/* Function called when mouse is moved to modify tension, bias or cont.	*/
/* of the selected knot.						*/
/* X, Y are the actual coordinates in the active window 'Win'.		*/
/*                                                                      */
/************************************************************************/
{
    if (Select_Spline == NULL || Select_Knot == NULL) return;


    Modify_Active = TRUE;

    Draw_Marked_Segments(DM_Erase, What_S);
    Draw_Marked_Segments(DM_Plane, What_S);

    Old_Modify_X = X;

    switch (Modify_Mode) {

    case 0: 	/* Tension 	*/
 	Old_Value = Select_Knot->Tension;
	break;

    case 1:	/* Bias 	*/
	Old_Value = Select_Knot->Bias;
	break;

    case 2: 	/* Continuity	*/
	Old_Value = Select_Knot->Continuity;
	break;

    } /* switch */

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

} /* Modify_KnotInfo_Select_Down */

static 
void  Modify_KnotInfo_Move(short X, short Y)
/************************************************************************/
/*                                                                      */
/* Function called when mouse is moved to modify tension, bias or cont.	*/
/* of the selected knot.						*/
/* X, Y are the actual coordinates in the active window 'Win'.		*/
/*                                                                      */
/************************************************************************/
{
    char Buffer[Buffer_Length+1];

    if (!Modify_Active) return;

    Current_Value = (X - Old_Modify_X);
    Current_Value = Current_Value / 400.0 + Old_Value;

    if (Redraw_Always) Modify_KnotInfo_Redraw(What_All);
    else 	       Redraw_Mask |= What_All;

} /* Modify_KnotInfo_Move */

static
Boolean_T Modify_KnotInfo_Handle_Event(struct IntuiMessage *Msg)
/************************************************************************/
/*                                                                      */
/*                                                                      */
/************************************************************************/
{

    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:
	    Modify_KnotInfo_Select_Down(Msg->MouseX, Msg->MouseY);
	    return(TRUE);

	case SELECTUP:
	    Modify_KnotInfo_Select_Up();
	    return(TRUE);

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

        case MOUSEMOVE:
	    Modify_KnotInfo_Move(Msg->MouseX, Msg->MouseY);
	    return(TRUE);

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

    return(FALSE);

} /* Modify_KnotInfo_Handle_Event */

void Handle_G_Tension()
/************************************************************************/
/*                                                                      */
/*                                                                      */
/************************************************************************/
{
    if (Windows[W_KnotInfo].Window == NULL) return;
    if (Select_Spline == NULL || Select_Knot == NULL) 
				if (!Select_Knot_From_Group()) return;

    Modify_Mode	        = 0;
    Modify_Active       = FALSE;
    State.Handle_Event  = Modify_KnotInfo_Handle_Event;
    State.Timeout 	= Modify_KnotInfo_Timeout;
    State.Redraw 	= Modify_KnotInfo_Redraw;

    Display_Status("Modify tension");

} /* Handle_G_Tension */

void Handle_G_Bias()
/************************************************************************/
/*                                                                      */
/*                                                                      */
/************************************************************************/
{
    if (Windows[W_KnotInfo].Window == NULL) return;
    if (Select_Spline == NULL || Select_Knot == NULL) 
				if (!Select_Knot_From_Group()) return;

    Modify_Mode	        = 1;
    Modify_Active       = FALSE;
    State.Handle_Event  = Modify_KnotInfo_Handle_Event;
    State.Timeout 	= Modify_KnotInfo_Timeout;
    State.Redraw 	= Modify_KnotInfo_Redraw;

    Display_Status("Modify bias");

} /* Handle_G_Bias */

void Handle_G_Continuity()
/************************************************************************/
/*                                                                      */
/*                                                                      */
/************************************************************************/
{
    if (Windows[W_KnotInfo].Window == NULL) return;
    if (Select_Spline == NULL || Select_Knot == NULL) 
				if (!Select_Knot_From_Group()) return;

    Modify_Mode	        = 2;
    Modify_Active       = FALSE;
    State.Handle_Event  = Modify_KnotInfo_Handle_Event;
    State.Timeout 	= Modify_KnotInfo_Timeout;
    State.Redraw 	= Modify_KnotInfo_Redraw;

    Display_Status("Modify continuity");

} /* Handle_G_Continuity */
