/*===========================================================================
  Copyright (C) 1989-2009 European Southern Observatory (ESO)
 
  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., 675 Massachusetss Ave, Cambridge, 
  MA 02139, USA.
 
  Corresponding concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

/*+++++++++++++++++++++++++
.TYPE		Module
.NAME           tfget.c
.LANGUAGE       C
.CATEGORY       User interface
.ENVIRONMENT    TermWindows
.AUTHOR		Alan Richmond, Francois Ochsenbein 
.COMMENTS
       Here are Input Functions. These may apply on Fields,
       or Notes.
.VERSION 1.0	09-Jun-1989     Extracted from Proteus
.VERSION 1.1	24-Jul-1989     Interrupt can be used to leave a field unchanged

 090902		last modif
-------------------*/

#define	PM_LEVEL	LEVEL_TF

#define  PASCAL_DEF	0	/* Don't include Pascalisation 	*/

#include <stesodef.h>	/* Standard definitions	*/
#include <tform.h>	/* for form values	*/
#include <str.h>	/* String utilities	*/


extern int tx_display();

extern int ta_ret(), ta_error();

extern int tv_dim(), tv_supply(), tv_where(), tv_bell();

extern int tw_fill(), tw_attr(), tw_uattr(), tw_r(), tw_goto(), tw_rule();
extern int tw_st(), tw_uflag(), tw_chars(), tw_copw(), tw_flags();
extern int tw_uw(), tw_write(), tw_il(), tw_clear(), tw_dc();
extern int tw_nl(), tw_upw(), tw_uc(), tw_mvc(), tw_copy();
extern int tw_mrule(), tw_cus(), tw_gc2(), tw_close(), tw_cur();
extern int tw_home(), tw_tra(), tw_wa(), tw_agoto(), tw_mods();
extern int tw_cline(), tw_stopin(), tw_ms2(), tw_wf(), tw_awhere();
extern int tw_getc(), tw_helps();

extern int pm_enter(), pm_iexit(), pm_tr2(), pm_ed_i();
extern int pm_trace();

extern int eh_put1(), eh_clear(), eh_ed_as();

extern int tff_goto(), tff_convert(), tff_edit(), tff_display();
extern int tff_putnote(), tff_move(), tff_oshow();

extern int tf_update(), tf_show(), tf_active(), tf_opwd();
extern int tf_oshow(), tf_oclear(), tf_oset(), tf_opwd(), tf_nshow();


#define ShowError()	DisplayError(NULL_PTR(char))
#define ClearError()	ERR_CLEAR(),DisplayError(NULL_PTR(char))

#define FINISH	goto FIN

static	TFORM	*theform;	/* Shared with Value / Check	*/
static	WINDOW	*thewindow;	/* Shared with Value / Check	*/
static	TFIELD	*field;		/* Shared with Value / Check	*/

static  char	check_pic;	/* Flag to check number vs pic	*/
static unsigned short option;	/* Option Flag	*/
static 	char	*thestring = NULL_PTR(char);
static 	short	thestring_size;
static 	char	*saved = NULL_PTR(char);
static	ACHAR	init_attr = ' ';
static	TF_CHECK thecheck_fct;

/*======================================================================*/
/* 			Internal Routines				*/
/*======================================================================*/
static int prolog(form)
/*+++++++
.PURPOSE Set the static values theform field thewindow
.REMARKS Used in cunjunction with Mods2
.RETURNS OK (input is correct) / NOK (Bad input)
---------*/
	TFORM	*form;	/* IN: The Form Concerned	*/
{
  theform = form;
  tff_goto(theform, theform->ifield);
  field = theform->fields + theform->ifield;	/* Current Field   */
  thewindow = NULL_WINDOW;
  if (ischarField(field))	thewindow = field->value.window;
  if(thewindow)			thewindow->pos = 0;
  else				thewindow = theform->window;

  SetStopping(thewindow, _NORMAL_, "[");	/* Stop when Escape */

  return(OK);
}
	
/*======================================================================*/
static int check(w, str, size)
/*+++++++
.PURPOSE Check Function for Input in Fields.
.REMARKS Used in cunjunction with Mods2
.RETURNS OK (input is correct) / NOK (Bad input)
---------*/
	WINDOW	*w;	/* IN: The Window	*/
	char	*str;	/* MOD: What the user typed	*/
	int	size;	/* IN: Size of str buffer	*/
{
	int	status;
	ACHAR	old_attr;
	
  ClearError();			/* Clear Any Error Message */

		/* First Check with Picture	*/

  status = OK;
  
  if (strcomp(str, saved) == 0)	/* No Modif	*/
  	FINISH;
  
  field->options |= _FIELD_MODIFIED;
  if (check_pic)
  {	if ((status = tff_convert(field, str)))	/* Correct	*/
		tff_edit(field);
  	else
  	{
	  	ERR_ED_STRING("Template is: ", field->picture);
		ShowError(), Bell();
		status = NOK;
	}
  }

		/* Check with All Functions	*/
  
  if (status && thecheck_fct)
  {
	old_attr = w->attr_init;	/* The init attribute was changed ... */
	w->attr_init = init_attr;
	if_not(status = (*thecheck_fct)(theform, str, size))
	{ 	if(ERR_GET())	ShowError(), Bell();  
		else		status = OK;
	}
	tf_update(theform);	/* Derive Values */
	w->attr_init = old_attr;
  }
	   
  FIN:
  return(status);
}

/*==========================================================================*/
static int Value ()
/*+++++++++++
.PURPOSE Allow user to modify the displayed field.
.REMARKS 
.RETURNS The status (see Mods2).
-------------*/
{
	int	status;

  init_attr = thewindow->attr_init;
  if (option & _FIELD_NOECHO)
	DeactiveWindow(thewindow);	/* Non-Echo field: don't display */
  else 	ActiveWindow(thewindow);

  if (thestring)			/* Get Complete Text 	*/
  {
	stripspaces(thestring);		/* Remove Trailing Spaces */
  	SetAttr(thewindow, field->attr);
  	saved = MEM_EXP(char, saved, ABSOLUTE(thestring_size));
  	strcopy(saved, thestring);
  	if (check_pic)				/* Only for tff_get	*/
		thewindow->attr_init = thewindow->attr, 
		SetAttr(thewindow, _NORMAL_); 
  	status = Mods2(thewindow, thestring, thestring_size, check); 
  	if (check_pic)				/* Only for tff_get	*/
		thewindow->attr_init = init_attr, 
		thewindow->attr      = init_attr;
  	if (status == _INTERRUPT_)	strcopy(thestring, saved);
  }
  else	status = GetKey2(thewindow);

  if (option & _FIELD_NOECHO)  	ActiveWindow(thewindow);

  return(status);
}

/*==========================================================================*/
static int default_action(form)
/*+++++++++++++++++
.PURPOSE Default Action to be executed if user didn't specify one.
.REMARKS Issues ERROR message with field name
.RETURNS NOK (Unknwon Field) / _EOF_ (QUIT field)
--------------------*/
	TFORM	*form;
{
	TFIELD	*field;
	int	status;

  status = NOK;
  field = form->fields + form->ifield;
  
  	/* Look for standard name:
  		EXIT  return _EOF_
  		Other return NOK
  	 */

  if (stucomp(field->name, "EXIT") == 0)	status = _EOF_;
  if (stucomp(field->name, "QUIT") == 0)	status = _EOF_;
  	 
  if (status == NOK)
  	ERR_ED_STRING("Ask to execute action: ", field->name);
  
  return(status);
}

/*==========================================================================*/
int tff_get (form)
/*+++++++++++++++++
.PURPOSE Input of One Field.
.RETURNS See Mods2
--------------------*/
	TFORM	*form;	/* MOD: The Form concerned 	*/
{
	int	len, status;
	char	*p;

  ENTER("tff_get");
	
  prolog(form);
  
  if(isactionField(field))	thestring = NULL_PTR(char),
  				thestring_size = 0,
  				option |= _FIELD_NOECHO;
  else
  {
  	thestring = field->string, thestring_size = field->string_size;
  	check_pic = 1;
  	option = field->options;
  	thecheck_fct = theform->check_fct;
  }

  status = Value();


  if_not(isactionField(field))		/* Fill with Blanks */
  {
  	len = strlen(field->string);
  	p   = field->string + len;
  	len = field->string_size - 1 - len;	/* Blanks to add */
  	strfill(p, len, ' ');
  }

  EXIT (status);
}

/*==========================================================================*/
int tff_mods (form, str, size, check_fct)
/*+++++++++++++++++
.PURPOSE Input in One Field.
.RETURNS See Mods2
--------------------*/
	TFORM	*form;	/* MOD: The Form concerned 	*/
	char	*str;	/* MOD: The text to be modified by the user */
	int	size;	/* IN: Size of the above	*/
	TF_CHECK check_fct;	/* IN: Check Function		*/
{
	int	status, old_attr, old_pos;

  ENTER("tff_mods");
	
  prolog(form);
  
  thestring = str;	thestring_size = -size;	/* FOR STRETCH */
  check_pic = 0;	option = 0;
  thecheck_fct = check_fct;

  status = DeactiveWindow(thewindow);
  old_attr = SetAttr(thewindow, field->attr);
  if (field->string_size)	
  	Fill(thewindow, ' ', field->string_size - 1);

  status = Value();
  
  stripspaces(thestring);
  old_pos = GetPosition(thewindow);
  tff_display(form, thestring);
  SetAttr(thewindow, old_attr);
  SetPosition(thewindow, old_pos);

  EXIT (status);
}

/*==========================================================================*/
int tff_nget(form, check_fct)
/*+++++++++++++++++
.PURPOSE Input of One Note
.RETURNS See Mods2
--------------------*/
	TFORM	*form;	/* MOD: The Form concerned 	*/
	TF_CHECK check_fct;	/* IN: Check Function	*/
{
	char	note[256];
	int	status;

  ENTER("tff_nget");
  
  prolog(form);
  
  if (field->note)	strncopy(note, sizeof(note), field->note);
  else			note[0]   = EOS;

  status = tff_mods(form, note, sizeof(note), check_fct);
  if (status >= 0)	tff_putnote(form, note);
  
  EXIT(status);
}
  
/*==========================================================================*/
int tf_get (form)
/*+++++++++++++++++
.PURPOSE Move in Form with Keys, get data typed in keys, Until EOF (^Z)
	or Special Keys (eg PF keys)
.RETURNS _EOF_ (Quit) / 0 (Normally Terminated) / _INTERRUPT_ / Other (See Mods2) 
--------------------*/
	TFORM	*form;	/* MOD: The Form concerned 	*/
{
	int	status, old_active;
	TF_FCT	fct;

  ENTER("tf_get");	
	
  /* ClearError();		/. Clear Any Error Message 	*/
  tf_show(form);		/* Write the Correct Fields 	*/
  old_active = tf_active(form, 1);	/* Be sure the Form is Active..	*/

  for (status = 0; status >= 0; )	/* For Ever Among Fields */
  {
	status = tff_get(form);

	if (status == _EOF_)		/* End */
  	{
  		if (theform->check_fct)
  		{
			tf_update(theform);	/* Derive Values */
			theform->avalue = NULL_PTR(int);
			if_not((*theform->check_fct)(theform, NULL_PTR(char), 0))
			{ 	if(ERR_GET())	{ShowError(), Bell(); continue; }
			}
  		}
		status = 0;
		break;
  	}

	if (status == 0)		/* Normal CR	*/
	{
		if (isactionField(field))	
		{ 	if_not(fct = field->value.action) fct = default_action;
			status = (*fct)(theform);
			if (ERR_GET())	ShowError(), Bell();  
			continue;
		}
		status = _ARROW(_RIGHT_);
	}
	if (is_ARROW(status))	tff_move(form, status|0x10), status = 0;
  }

	   
  tf_active(form, old_active);	/* Reset Active Status	*/
  EXIT (status);
}

/*==========================================================================*/
int tf_oget (form, mask, ifset)
/*+++++++++++++++++
.PURPOSE Input of Options
.RETURNS OK
.REMARKS Non-echo fields can't be set... 
--------------------*/
	TFORM	*form;	/* MOD: The Form concerned 	*/
	int	mask;	/* IN: Mask to select option	*/
	int	ifset;	/* IN: How to display Selected	*/
{
	int	status, old_active;
	WINDOW	*old_help_window;
	static 	WINDOW *help_window = NULL_WINDOW;
	static	char	cc[] = {'@', ' ', 'A', 'C', 'Q',
		TW_cc_EOF, TW_cc_INT, TW_cc_HELP, TW_cc_UP, TW_cc_DOWN, 
		TW_cc_LEFT, TW_cc_RIGHT, TW_cc_NONE};
	static	char	*explain[sizeof(cc)-1] = {
		"Select", "Clear", "Select ALL", "Clear  ALL", "Quit ", 
		NULL_PTR(char)	};
	char	achar, do_show, do_arrow;
	short	ispwd;

  ENTER("tf_oget");
	
  ClearError();			/* Clear Any Error Message 	*/
  theform = form;
  
  ispwd = mask&_FIELD_NOECHO;
  if_not(ispwd)	tf_opwd(theform, mask);
  
  if_not(help_window)	
	help_window = OpenHelpWindow("How to Select",0, -25, cc, explain);
  achar = ifset;
  CursorTo(help_window, 0, 2); Write(help_window,&achar, 1);

  old_help_window = AttachHelpWindow(theform->window, help_window);
  
  old_active = tf_active(form, 0);	/* Be sure the Form is NOT Active..*/
  tf_oshow(form, mask, ifset);		/* Write the Correct Fields 	*/

  do_show = 1;				/* 1 means Show Complete Form	*/
  achar   = _RIGHT_;

  while(1)	/* For Ever Among Fields */
  {
	if(do_show)
	{	if_not(ispwd)	tf_opwd(theform, mask);
		do_show = 0, tf_oshow(form, mask, ifset);
	}
	do_arrow = 0;

  	tff_goto(theform, theform->ifield);
  	field = theform->fields + theform->ifield;	/* Current Field   */

	if (!ispwd)	while (field->options & _FIELD_NOECHO)
	{	Bell();
		if (theform->ifield == 0) 	achar = _RIGHT_;
		if (theform->ifield == (theform->nfields - 1)) 
						achar = _LEFT_;
		tff_move(theform, achar);
  		field = theform->fields + theform->ifield;
	}

  	TouchWindow(theform->window);

  	switch(status = GetKey(theform->window, &achar))
	{ case _EOF_:			FINISH;
	  case _STANDARD_:	achar = toupper(achar);
	  	if (achar == 'Q')	FINISH;
	  	if (achar == '\r')	do_arrow = 1, achar = _RIGHT_;
  		else if (achar == 'C')	do_show = 1, tf_oclear(theform, mask);
  		else if (achar == 'A')	do_show = 1, tf_oset  (theform, mask);
  		else if (achar == ' ')	do_show = 2, field->options &= ~mask,
  					 	do_arrow = 1, achar = _RIGHT_;
	  	else if (achar == ifset)do_show = 2, field->options |= mask,
	  					do_arrow = 1, achar = _RIGHT_;
		else	Bell();
  		break;
	  case _ARROW_:			do_arrow = 1;
  		break;
	  default:			Bell();
	}
	if (do_show == 2)	do_show = 0, tff_oshow(theform, mask, ifset);
	if (do_arrow)		tff_move(theform, achar);
  }

  FIN:
  tf_active(form, old_active);	/* Reset Active Status	*/
  RemoveHelpWindow(theform->window);
  AttachHelpWindow(theform->window, old_help_window);
  EXIT (OK);
}

/*==========================================================================*/
int tf_nget (form, fct)
/*+++++++++++++++++
.PURPOSE Move in Form to get Notes.
.RETURNS See Mods2
--------------------*/
	TFORM	*form;	/* MOD: The Form concerned 	*/
	TF_CHECK fct;	/* IN: The Check Function(form,str,size)*/
{
	int	status, old_active;

  ENTER("tf_nget");	
	
  /* ClearError();		/. Clear Any Error Message 	*/
  tf_nshow(form);		/* Write the Correct Notes	*/
  old_active = tf_active(form, 1);	/* Be sure the Form is Active..	*/

  while(1)	/* For Ever Among Fields */
  {
	status = tff_nget(form, fct);
	if (status < 0)	break;
	if (status == 0)		/* Normal CR	*/
		status = _ARROW(_RIGHT_);

	if (is_ARROW(status))	tff_move(form, status);
  }

		/* Check with All Functions	*/
  
  if ((status < 0) && (fct))
  {
	form->avalue = NULL_PTR(int);
	if_not(status = (*fct)(form, NULL_PTR(char), 0))
		ShowError(), Bell();
  }
	   
  tf_active(form, old_active);	/* Reset Active Status	*/
  EXIT (status);
}

