/** \file dease.c
 * Easement Button Hdlrs
 */

/*  XTrkCad - Model Railroad CAD
 *  Copyright (C) 2005 Dave Bullis
 *
 *  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 2 of the License, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include "common.h"
#include "ccurve.h"
#include "cjoin.h"
#include "cstraigh.h"
#include "custom.h"
#include "fileio.h"
#include "param.h"
#include "track.h"

EXPORT DIST_T easementVal = 0.0;
EXPORT DIST_T easeR = 0.0;
EXPORT DIST_T easeL = 0.0;

static wButton_p easementB;

static DIST_T easeX = 0.0;

static DIST_T Rvalues[3];
static DIST_T Lvalues[3];

static DIST_T oldEasementVal;

static wIcon_p enone_bm;
static wIcon_p esharp_bm;
static wIcon_p egtsharp_bm;
static wIcon_p eltsharp_bm;
static wIcon_p enormal_bm;
static wIcon_p eltbroad_bm;
static wIcon_p ebroad_bm;
static wIcon_p egtbroad_bm;
static wIcon_p ecornu_bm;

/****************************************
 *
 * EASEMENTW
 *
 */

static wWin_p easementW;

static void EasementSel( long );
static void SetEasement( DIST_T, void * );
static void EasementOk( void );
static void EasementCancel( void );

static char *easementChoiceLabels[] = { N_("None"), N_("Sharp"), N_("Normal"), N_("Broad"), N_("Cornu"), NULL };
static paramFloatRange_t r0n1_100 = { -1.0, 100.0, 60 };
static paramFloatRange_t r0_100 = { 0.0, 100.0, 60 };
static paramFloatRange_t r0_200 = { 0.0, 200.0, 60 };
static paramFloatRange_t r0_10 = { 0.0, 10.0, 60 };
static long easeM;
static paramData_t easementPLs[] = {
#define I_EASEVAL		(0)
	{	PD_FLOAT, &easementVal, "val", PDO_NOPSHUPD, &r0n1_100, N_("Value") },
	{	PD_FLOAT, &easeR, "r", PDO_DIM|PDO_DLGRESETMARGIN, &r0_200, N_("R"), BO_READONLY },
	{	PD_FLOAT, &easeX, "x", PDO_DIM|PDO_DLGHORZ, &r0_10, N_("X"), BO_READONLY },
	{	PD_FLOAT, &easeL, "l", PDO_DIM|PDO_DLGHORZ, &r0_100, N_("L"), BO_READONLY },
#define I_EASESEL		(4)
	{	PD_RADIO, &easeM, "radio", PDO_DIM|PDO_NORECORD|PDO_NOPREF|PDO_DLGRESETMARGIN, easementChoiceLabels, NULL, BC_HORZ|BC_NONE }
};
static paramGroup_t easementPG = { "easement", PGO_RECORD, easementPLs, COUNT( easementPLs ) };


static void SetEasement(
        DIST_T val,
        void * update )
/*
 * Set transition-curve parameters (R and L).
 */
{
	DIST_T z;
	long selVal = -1;
	wIcon_p bm;

	if (val < 0.0) {
		easeX = easeR = easeL = 0.0;
		selVal = 4;
		val = -1;
		bm = ecornu_bm;
	} else {
		if (val == 0.0) {
			easeX = easeR = easeL = 0.0;
			selVal = 0;
			val = 0;
			bm = enone_bm;
		} else if (val <= 1.0) {
			if (val < 0.21) { val = 0.21; }   //Eliminate values that give negative radii
			z = 1.0/val - 1.0;
			easeR = Rvalues[1] - z * (Rvalues[1] - Rvalues[0]);
			easeL = Lvalues[1] - z * (Lvalues[1] - Lvalues[0]);
			if (easeR != 0.0) {
				easeX = easeL*easeL/(24*easeR);
			} else {
				easeX = 0.0;
			}
			if (val == 1.0) {
				selVal = 2;
				bm = enormal_bm;
			} else if (val == 0.5) {
				selVal = 1;
				bm = esharp_bm;
			} else if (val < 0.5) {
				bm = eltsharp_bm;
				selVal = 1;
			} else {
				selVal = 1;
				bm = egtsharp_bm;
			}
		} else {
			z = val - 1.0;
			easeR = Rvalues[1] + z * (Rvalues[2] - Rvalues[1]);
			easeL = Lvalues[1] + z * (Lvalues[2] - Lvalues[1]);
			if (easeR != 0.0) {
				easeX = easeL*easeL/(24*easeR);
			} else {
				easeX = 0.0;
			}
			if (val == 2.0) {
				selVal = 3;
				bm = ebroad_bm;
			} else if (val < 2.0) {
				selVal = 3;
				bm = eltbroad_bm;
			} else {
				selVal = 3;
				bm = egtbroad_bm;
			}
		}
	}

	easeR = (floor(easeR*100.0))/100.0;
	easementVal = val;
	if (easementW && wWinIsVisible(easementW)) {
		ParamLoadControls( &easementPG );
		if (update) {
			easeM = selVal;
			ParamLoadControl( &easementPG, I_EASESEL );
		}
	}
	/*ParamChange( &easeValPD );*/

	if (easementB) {
		wButtonSetLabel( easementB, (char*)bm );
	}
}


static void EasementOk( void )
{
	ParamLoadData( &easementPG );
	SetEasement( easementVal, I2VP(FALSE) );
	wHide( easementW );
}


static void EasementCancel( void )
{
	SetEasement( easementVal = oldEasementVal, I2VP(FALSE) );
	wHide( easementW );
}


static void EasementSel(
        long arg )
/*
 * Handle transition-curve parameter selection.
 */
{
	DIST_T val;
	switch (arg) {
	case 0:
		val = 0;
		break;
	case 1:
		val = 0.5;
		break;
	case 2:
		val = 1.0;
		break;
	case 3:
		val = 2.0;
		break;
	case 4:
		val = -1.0;
		break;
	default:
		CHECKMSG( FALSE, ( "easementSel: bad value %ld", arg) );
		val = 0.0;
		break;
	}
	SetEasement( val, I2VP(FALSE) );
}


static void EasementDlgUpdate(
        paramGroup_p pg,
        int inx,
        void * valueP )
{
	switch (inx) {
	case I_EASEVAL:
		SetEasement( *(FLOAT_T*)valueP, I2VP(1) );
		break;
	case I_EASESEL:
		EasementSel( *(long*)valueP );
		break;
	}
}


static void LayoutEasementW(
        paramData_t * pd,
        int inx,
        wWinPix_t colX,
        wWinPix_t * x,
        wWinPix_t * y )
{
	if ( inx == 2 ) {
		wControlSetPos( easementPLs[0].control, *x,
		                wControlGetPosY(easementPLs[0].control) );
	}
}


static void DoEasement( void * unused )
{
	if (easementW == NULL) {
		easementW = ParamCreateDialog( &easementPG, MakeWindowTitle(_("Easement")),
		                               _("Ok"), (paramActionOkProc)EasementOk, (paramActionCancelProc)EasementCancel,
		                               TRUE, LayoutEasementW, 0, EasementDlgUpdate );
		SetEasement( easementVal, I2VP(TRUE) );
	}
	oldEasementVal = easementVal;
	wShow( easementW );
	SetEasement( easementVal, I2VP(TRUE) );
}


static void EasementChange( long changes )
/*
 * Handle change of scale. Load new parameters.
 */
{
	if (changes&(CHANGE_SCALE|CHANGE_UNITS)) {
		GetScaleEasementValues( Rvalues, Lvalues );
		SetEasement( easementVal, I2VP(TRUE) );
	}
}


#include "bitmaps/ease-none.xpm3"
#include "bitmaps/ease-sharp.xpm3"
#include "bitmaps/ease-gt-sharp.xpm3"
#include "bitmaps/ease-lt-sharp.xpm3"
#include "bitmaps/ease-normal.xpm3"
#include "bitmaps/ease-broad.xpm3"
#include "bitmaps/ease-gt-broad.xpm3"
#include "bitmaps/ease-lt-broad.xpm3"
#include "bitmaps/ease-cornu.xpm3"


EXPORT addButtonCallBack_t EasementInit( void )
{
	ParamRegister( &easementPG );

	enone_bm = wIconCreatePixMap( ease_none_xpm3[iconSize] );
	eltsharp_bm = wIconCreatePixMap( ease_lt_sharp_xpm3[iconSize] );
	esharp_bm = wIconCreatePixMap( ease_sharp_xpm3[iconSize] );
	egtsharp_bm = wIconCreatePixMap( ease_gt_sharp_xpm3[iconSize] );
	enormal_bm = wIconCreatePixMap( ease_normal_xpm3[iconSize] );
	eltbroad_bm = wIconCreatePixMap( ease_lt_broad_xpm3[iconSize] );
	ebroad_bm = wIconCreatePixMap( ease_broad_xpm3[iconSize] );
	egtbroad_bm = wIconCreatePixMap( ease_gt_broad_xpm3[iconSize] );
	ecornu_bm = wIconCreatePixMap( ease_cornu_xpm3[iconSize] );
	easementB = AddToolbarButton( "cmdEasement", enone_bm, 0, DoEasementRedir,
	                              NULL );

	RegisterChangeNotification( EasementChange );
	return &DoEasement;
}