/************************************************************************/
/* Copyright 1992 MBARI							*/
/************************************************************************/
/* $Header: /usr/tiburon/unix/gui/proto/RCS/setupcall.c,v 1.1 1998/01/28 16:17:12 oreilly Exp $		*/
/* Summary  : Callbacks for Setup Screen of ROV User Interface		*/
/* Filename : setupcall.c						*/
/* Author   : Bob Herlien (rah)						*/
/* Project  : Tiburon ROV						*/
/* $Revision: 1.1 $							*/
/* Created  : 05/21/92							*/
/************************************************************************/
/* Modification History:						*/
/* $Log: setupcall.c,v $
 * Revision 1.1  1998/01/28 16:17:12  oreilly
 * Initial revision
 *
 * Revision 2.2  96/05/15  11:15:34  11:15:34  bobh (Bob Herlien)
 * Still supporting proto during final vehicle build
 * 
 * Revision 2.0  95/09/20  14:23:02  14:23:02  hebo (Bob Herlien)
 * Support for final vehicle integration.  AC, PDU micros.
 * 
 * Revision 1.8  94/08/19  17:20:23  17:20:23  hebo (Bob Herlien)
 * Interface to Unix version of Data Manager
 * 
 * Revision 1.7  94/03/21  14:15:16  14:15:16  hebo (Bob Herlien)
 * Misc bug fixes and enhancements
 * 
 * Revision 1.6  93/12/17  15:04:54  15:04:54  hebo (Bob Herlien)
 * December Wet Test
 * 
 * Revision 1.5  93/07/08  18:10:54  18:10:54  hebo (Bob Herlien)
 * Prior to Prototype Phase I testing
 * 
 * Revision 1.4  93/05/27  15:48:01  15:48:01  hebo (Bob Herlien)
 * Data Manager Interface
 * 
 * Revision 1.2  93/01/21  10:34:18  10:34:18  hebo (Bob Herlien)
 * Changes after Level 0
 * 
 * Revision 1.0  92/11/20  12:03:27  12:03:27  hebo (Bob Herlien)
 * Initial revision
 * 
*/
/************************************************************************/

#include <mbari/types.h>
#include <mbari/const.h>
#include <X11/Intrinsic.h>
#include <Xm/Xm.h>
#include <Xm/TextF.h>
#include <Xm/PushB.h>
#include <X11/Xc/Xc.h>
#include "rov.h"
#include "tiburon.h"
#include "ibc.h"
#include "alarm.h"
#include <controlDM.h>
#include "rdmif.h"

typedef enum {JOY_DB_X = 0, JOY_DB_Y, JOY_DB_Z, JOY_DB_HDG} JoyDbDir;

typedef enum { SPEED, THRUST } joystickCmdMode;

typedef struct				/********************************/
{					/* Struct for range checked textF*/
    Position	tf_x;			/* X Position of TextField	*/
    Position	tf_y;			/* Y Position of TextField	*/
    Int32	tf_min;			/* Minimum accepted value	*/
    Int32	tf_max;			/* Maximum accepted value	*/
    rovItem	*tf_item;		/* rovItem it refers to		*/
    Widget	tf_widget;		/* TextField widget		*/
    Widget	tf_button;		/* "OK" pushbutton widget	*/
} miscTextField;			/********************************/

#define SENSOR_ITEM_WIDTH	365
#define SENSOR_INFO_LEFT_POS	50
#define SENSOR_INFO_RT_POS	70


/********************************/
/*	External Functions	*/
/********************************/

Extern Void	createItems( rovItem **ipp, TimeoutStruct *tp );
Extern Void	startTimeout( TimeoutStruct *tp );
Extern Void	stopTimeout( TimeoutStruct *tp );
Extern Void	updateToggle( rovItem *rp );
Extern Widget	createIbcGroup( Widget parent, ibcItemSet *isp,
			        Dimension width, Int32 lpos, Int32 rpos );
Extern Void	createIbcItems( Reg ibcItemDesc *idp, char *dmprefix );
Extern Void	ibcStartTimeout( ibcItemDesc *idp, char *dmprefix );
Extern Void	ibcStopTimeout( ibcItemDesc *idp );
Extern Void	labelCreate( Widget parent, ibcItem *itm,
			     Int32 lpos, Int32 rpos );
Extern Void	updateIntLabel( ibcItem *itm );
Extern Void	updateFltLabel( ibcItem *itm );
Extern Void	updateEnumLabel( ibcItem *itm );
Extern Void	textFieldCreate( Widget parent, ibcItem *itm,
				 Int32 lpos, Int32 rpos );
Extern Void	updateNumTextField( ibcItem *itm );
Extern Void	modifyIntTextField( Widget w, ibcItem *itm, 
				    XmTextVerifyCallbackStruct *tvp );
Extern Void	acceptIntTextField( Widget w, ibcItem *itm, 
				    XmAnyCallbackStruct *cbp );


/********************************/
/*	External Data		*/
/********************************/

Extern XtAppContext	appcontext;	/* The application context	*/
Extern AppData		appdata;	/* Application-wide resources	*/
Extern Widget		joyGainSwitchToggle;
Extern Widget		joy50Button, joy20Button, joy10Button;
Extern Widget		joySpeedButton, joyThrustButton;
Extern Widget		sensorSetupScrolledWindow;
Extern char		*ibcAlarmStrings[];
Extern char		buff[];		/* Misc buffer used application-wide*/


/****************************************/
/*	Forward Function Declarations	*/
/****************************************/

Void		updateJoystickGain( rovItem *itm );
Void		updateJoystickSetupMode( rovItem *itm );
Void		updateJoystickDeadband( rovItem *itm );


/********************************/
/*	Module Local Data	*/
/********************************/

MLocal Nat32	joystickDbDir = 0;
MLocal Widget	joystickGainTextF, joystickDeadbandTextF;
MLocal MBool	setupUpdate = FALSE;

MLocal rovItem		joystickGainItem =
{ JOYSTICK_GAIN_DM, DM_NAT16, 1, FALSE, NO_ITEM, 0,
  &joystickGainTextF, updateJoystickGain, 0 };

MLocal rovItem		joystickModeItem =
{ JOYSTICK_MODE_DM, DM_ENUM, 1, FALSE, NO_ITEM, 0, NULLWP, 
  &updateJoystickSetupMode, 0 };

Global rovItem		joystickGainSwitchItem =
{ JOYSTICK_GAIN_SWITCH_DM, DM_MBOOL, 1, FALSE, NO_ITEM, 0,
  &joyGainSwitchToggle, updateToggle };

MLocal rovItem		joystickDeadbandItem =
{ TIBURON_DM_PREFIX "CONTROL.JOYSTICK_DEADBAND", DM_NAT16, 4, FALSE, NO_ITEM, 0,
  &joystickDeadbandTextF, updateJoystickDeadband, 0 };

MLocal rovItem		*setupItems[] =
{ &joystickGainItem, &joystickModeItem, &joystickGainSwitchItem, 
  &joystickDeadbandItem, NULLR };

MLocal TimeoutStruct	setupTimeoutStruct = 
{ &appdata.misc_update, 0, setupItems, 0, "Setup Screen", NULLF };

MLocal miscTextField	joyGainTextFieldStruct =
{ 28, 80, 0, 100, &joystickGainItem, NULLW, NULLW };

MLocal miscTextField	joyDeadbandTextFieldStruct =
{ 67, 80, 0, 50, &joystickDeadbandItem, NULLW, NULLW };


MLocal ibcItem	sensorItems[] =
{ { "Comp Min Value", TIBURON_DM_PREFIX COMP_SYSTEM_MIN_LEVEL_DM,
    DM_NAT16, 1, textFieldCreate, updateNumTextField, acceptIntTextField,
    modifyIntTextField, UP_CONSUME, 6, 0, NULL, 0, NULLW, NULLW, NULLW, 0, -1},
  { "Comp Max Value", TIBURON_DM_PREFIX COMP_SYSTEM_MAX_LEVEL_DM,
    DM_NAT16, 1, textFieldCreate, updateNumTextField, acceptIntTextField,
    modifyIntTextField, UP_CONSUME, 6, 0, NULL, 0, NULLW, NULLW, NULLW, 0, -1},
  { "Comp % Level", TIBURON_DM_PREFIX COMP_SYSTEM_LEVEL_PERCENT_DM,
     DM_NAT16, 1, labelCreate, updateIntLabel, NULLF, NULLF, UP_CONSUME, 0, 0,
     NULL, 0, NULLW, NULLW, NULLW, 0, -1},
  { "Comp Volume",  TIBURON_DM_PREFIX COMP_SYSTEM_LEVEL_VOLUME_DM,
    DM_FLT32, 1, labelCreate, updateFltLabel, NULLF, NULLF, UP_CONSUME, 0, 0,
    NULL, 0, NULLW, NULLW, NULLW, 0, -1},
  {"Comp Level Alarm", TIBURON_DM_PREFIX COMP_SYSTEM_LEVEL_ALARM_DM,
    DM_ENUM, 1, labelCreate, updateEnumLabel, NULLF, NULLF, UP_ALREADY_CONSUME,
    NUM_IBC_ALARMS, 0, ibcAlarmStrings, 0, NULLW, NULLW, NULLW, 0, -1},
  { "Comp Level Warn Thresh", TIBURON_DM_PREFIX COMP_SYSTEM_WARN_LEVEL_DM, 
    DM_NAT16, 1, textFieldCreate, updateNumTextField, acceptIntTextField, 
    modifyIntTextField, UP_CONSUME, 6, 0, NULL, 0, NULLW, NULLW, NULLW, 0, -1},
  { "Comp Level Alarm Thresh", TIBURON_DM_PREFIX COMP_SYSTEM_ALARM_LEVEL_DM,
    DM_NAT16, 1, textFieldCreate, updateNumTextField, acceptIntTextField, 
    modifyIntTextField, UP_CONSUME, 6, 0, NULL, 0, NULLW, NULLW, NULLW, 0, -1}
};

MLocal ibcItemSet  sensorItemSet = 
{ sensorItems, XtNumber(sensorItems), NULLW };

MLocal ibcItemDesc	sensorItemDesc =
{ {&sensorItemSet, NULLIS, NULLIS, NULLIS},
  &appdata.misc_update, 0, 0, 0 };


/************************************************************************/
/* Function    : setJoystickMode					*/
/* Purpose     : Callback for setting Joystick mode			*/
/* Inputs      : Widget ID, mode, callback struct			*/
/* Outputs     : None							*/
/************************************************************************/
    Void
setJoystickMode( Widget w, Int32 mode, XmToggleButtonCallbackStruct *cbs )
{
    if ( !cbs->set || (joystickModeItem.dmitem == NO_ITEM) )
	return;

    rdm_write_once( joystickModeItem.dmitem, (char *)&mode, sizeof(Int32) );

} /* setJoystickMode() */


/************************************************************************/
/* Function    : setJoystickGain					*/
/* Purpose     : Callback for setting Joystick Gain			*/
/* Inputs      : Widget ID, mode, callback struct			*/
/* Outputs     : None							*/
/************************************************************************/
    Void
setJoystickGain( Widget w, Int32 gain, XmToggleButtonCallbackStruct *cbs )
{
    Nat16	gain16;

    if ( !cbs->set || (joystickGainItem.dmitem == NO_ITEM) )
	return;

    gain16 = (gain > 100) ? 100 : gain;
    rdm_write_once( joystickGainItem.dmitem, (char *)&gain16, sizeof(Nat16) );

} /* setJoystickGain() */


/************************************************************************/
/* Function    : updateJoystickGain					*/
/* Purpose     : Update Joystick Gain TextField and ToggleButtons	*/
/* Inputs      : rovItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
updateJoystickGain( rovItem *itm )
{
    Nat16	val;

    setupUpdate = TRUE;
    rdm_read( itm->dmitem, (char *)&val, sizeof(Nat16) );

    sprintf( buff, "%u", val );
    XmTextFieldSetString( *itm->widget, buff );
    itm->value = val;

    XmToggleButtonSetState( joy50Button, val == 50, FALSE );
    XmToggleButtonSetState( joy20Button, val == 20, FALSE );
    XmToggleButtonSetState( joy10Button, val == 10, FALSE );
    setupUpdate = FALSE;

} /* updateJoystickGain() */


/************************************************************************/
/* Function    : updateJoystickSetupMode				*/
/* Purpose     : Update Joystick Mode					*/
/* Inputs      : rovItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
updateJoystickSetupMode( rovItem *ip )
{
    joystickCmdMode	mode;
    
    rdm_read( ip->dmitem, (char *)&mode, sizeof(mode) );

    if ( mode != ip->value )
    {
	XmToggleButtonSetState( joySpeedButton, mode == SPEED, FALSE );
	XmToggleButtonSetState( joyThrustButton, mode == THRUST, FALSE );
    }

    ip->value = mode;

} /* updateJoystickSetupMode() */


/************************************************************************/
/* Function    : updateJoystickDeadband					*/
/* Purpose     : Update Joystick Deadband				*/
/* Inputs      : rovItem pointer					*/
/* Outputs     : None							*/
/************************************************************************/
	Void
updateJoystickDeadband( rovItem *itm )
{
    Nat16	val[4];

    setupUpdate = TRUE;
    rdm_read( itm->dmitem, (char *)val, 4 * sizeof(Nat16) );

    sprintf( buff, "%u", val[joystickDbDir] );
    XmTextFieldSetString( *itm->widget, buff );
    setupUpdate = FALSE;

} /* updateJoystickDeadband() */


/************************************************************************/
/* Function    : setJoyDbDir						*/
/* Purpose     : Callback for setting Joystick Deadband Direction	*/
/* Inputs      : Widget ID, mode, callback struct			*/
/* Outputs     : None							*/
/************************************************************************/
    Void
setJoyDbDir( Widget w, Nat32 dir, XmToggleButtonCallbackStruct *cbs )
{
    if ( (cbs->set) && (dir <= JOY_DB_HDG) )
	joystickDbDir = dir;

    updateJoystickDeadband( &joystickDeadbandItem );

} /* setJoyDbDir() */


/************************************************************************/
/* Function    : modifyMiscTextField					*/
/* Purpose     : Callback when miscTextField is modified		*/
/* Inputs      : Widget, miscTextField ptr, call data			*/
/* Outputs     : None							*/
/************************************************************************/
    Void
modifyMiscTextField( Widget w, miscTextField *tp, 
		     XmTextVerifyCallbackStruct *tvp )
{

    Int32	len;
    int		c;

    if ( tvp->text->ptr == NULL )
	return;

    for ( len = 0; len < tvp->text->length; len++ )
    {
	c = tvp->text->ptr[len];
	if ( !isdigit(c) && 
	     ((c != '-') || (tvp->currInsert != 0) || (len != 0)) )
	    tvp->doit = False;
    }

    if ( !setupUpdate && tvp->doit && (!XtIsManaged(tp->tf_button)) )
	XtManageChild( tp->tf_button );

} /* modifyMiscTextField() */


/************************************************************************/
/* Function    : acceptMiscTextField					*/
/* Purpose     : Callback for "OK" pushbutton or <RETURN> in TextField	*/
/* Inputs      : Widget, miscTextField ptr, call data			*/
/* Outputs     : None							*/
/************************************************************************/
    Void
acceptMiscTextField( Widget w, miscTextField *tp, XmAnyCallbackStruct *acp )
{
    char	*p;
    Nat32	i;
    Nat16	val, dbval[4];
    Reg rovItem *rp;

    p = XmTextFieldGetString( tp->tf_widget );

    if ( (sscanf(p, "%d", &i) == 1) && (i >= tp->tf_min) && (i <= tp->tf_max) )
    {
	rp = tp->tf_item;

	if ( rp == &joystickDeadbandItem )
	{
	    rdm_read( rp->dmitem, (char *)dbval, 4 * sizeof(Nat16) );
	    dbval[joystickDbDir] = i;
	    rdm_write_once( rp->dmitem, (char *)dbval, 4 * sizeof(Nat16) );
	    updateJoystickDeadband( rp );
	}
	else
	{
	    val = i;
	    rdm_write_once( rp->dmitem, (char *)&val, sizeof(Nat16) );
	    updateJoystickGain( rp );
	}

	if ( XtIsManaged(tp->tf_button) )
	    XtUnmanageChild( tp->tf_button );
    }
    else if ( appdata.ring_bell )
	XBell( XtDisplay(w), 100 );

    XtFree( p );

} /* acceptMiscTextField() */


/************************************************************************/
/* Function    : createMiscTextF					*/
/* Purpose     : Creation Callback for Joystick Form			*/
/* Inputs      : Parent, miscTextField ptr				*/
/* Outputs     : TextField Widget					*/
/************************************************************************/
    Widget
createMiscTextField( Widget parent, miscTextField *tp )
{
    XmString	str;

    tp->tf_widget = XtVaCreateManagedWidget("joyTextField",
					    xmTextFieldWidgetClass, parent,
					    XmNtopAttachment, XmATTACH_POSITION,
					    XmNtopPosition, tp->tf_y,
					    XmNleftAttachment,XmATTACH_POSITION,
					    XmNleftPosition, tp->tf_x,
					    XmNcolumns, 4, XmNvalue, 0, NULL );

    XtAddCallback( tp->tf_widget, XmNmodifyVerifyCallback, 
		   (XtCallbackProc)modifyMiscTextField, tp );
    XtAddCallback( tp->tf_widget, XmNactivateCallback, 
		   (XtCallbackProc)acceptMiscTextField, tp );

    str = XmStringCreateSimple( "OK" );
    tp->tf_button = XtVaCreateWidget("joyOKButton", 
				     xmPushButtonWidgetClass, parent,
				     XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
				     XmNtopWidget, tp->tf_widget,
				     XmNleftAttachment, XmATTACH_WIDGET,
				     XmNleftWidget, tp->tf_widget,
				     XmNlabelString, str, NULL );
    XmStringFree( str );

    XtAddCallback( tp->tf_button, XmNactivateCallback, 
		   (XtCallbackProc)acceptMiscTextField, tp );

    return( tp->tf_widget );

} /* createMiscTextF() */


/************************************************************************/
/* Function    : createJoyForm						*/
/* Purpose     : Creation Callback for Joystick Form			*/
/* Inputs      : Widget, client data, call data				*/
/* Outputs     : None							*/
/************************************************************************/
    Void
createJoyForm( Widget w, XtPointer client_data, XmAnyCallbackStruct *cbs )
{
    joystickGainTextF = 
	createMiscTextField( w, &joyGainTextFieldStruct );

    joystickDeadbandTextF = 
	createMiscTextField( w, &joyDeadbandTextFieldStruct );

} /* createJoyForm() */


/************************************************************************/
/* Function    : selectSetup						*/
/* Purpose     : Callback to select the Setup screen			*/
/* Inputs      : Select Ptr						*/
/* Outputs     : None							*/
/************************************************************************/
    Void
selectSetup( Select *sp )
{
    startTimeout( &setupTimeoutStruct );
    ibcStartTimeout( &sensorItemDesc, NULL );

} /* selectSetup() */


/************************************************************************/
/* Function    : unselectSetup						*/
/* Purpose     : Callback to unselect the Setup screen			*/
/* Inputs      : Select Ptr						*/
/* Outputs     : None							*/
/************************************************************************/
    Void
unselectSetup( Select *sp )
{
    stopTimeout( &setupTimeoutStruct );
    ibcStopTimeout( &sensorItemDesc );

} /* unselectSetup() */


/************************************************************************/
/* Function    : initSetup						*/
/* Purpose     : Initialize function for Setup Screen			*/
/* Inputs      : None							*/
/* Outputs     : None							*/
/************************************************************************/
     Void
initSetup( Void )
{
    Reg Widget		w;

    createItems( setupItems, &setupTimeoutStruct );

    createIbcItems( &sensorItemDesc, NULL );

    createIbcGroup(sensorSetupScrolledWindow, &sensorItemSet,
		   SENSOR_ITEM_WIDTH, SENSOR_INFO_LEFT_POS, SENSOR_INFO_RT_POS);

    XtManageChild( sensorItemSet.widget );

} /* initSetup() */
