/*===========================================================================
  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           tfpic.c
.LANGUAGE       C
.CATEGORY       User interface
.ENVIRONMENT    TermWindows
.AUTHOR		Francois Ochsenbein 
.COMMENTS
       Convert user input according to format.
       However, dates / times are assumed to start in 1980.
.VERSION 1.0	17-Feb-1989     Gathered here necessary conversions.
				Allow Date/time conversion
.VERSION 1.1	24-May-1989     Added NULL facility (edited as blanks)
			for INTEGER numbers only, flagged with a 
			UPPERCASE I in the SDF file.
.VERSION 2.0	08-Jun-1989: Removed from Proteus environment.

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

#define	PM_LEVEL	LEVEL_TF

#include <stdlib.h>

#include <midas_def.h>	

#define  PASCAL_DEF	0	/* Don't include Pascalisation 	*/
#include <stesodef.h>	/* Standard definitions	*/
#include <tform.h>	/* for form values	*/
#include <str.h>	/* String utilities	*/
#include <tra.h>	/* For tr_pic, etc	*/
#include <trtime.h>	/* For Time values	*/


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

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

extern int eh_ed_as(), ed_t(), ed_pic(), ed_fpic();

extern int tr_at(), tr_pic(), tr_fpic();



#define NULL1		-128	/* NULL for integer*n */
#define NULL2		-32768	/* NULL for integer*n */
#ifdef __alpha
#define NULL4		(1u<<31)/* NULL for integer*n */
#else
#define NULL4		((unsigned long)1L<<31)/* NULL for integer*n */
#endif
#define NULLF		-1.5e38

#define		O_10years	(86400*3652)

#define FINISH	goto FIN

static double	real;		/* Shared variables */
static long	integer;

/*==========================================================================*/
int tff_convert (field, instr)
/*+++++++++++++++++
.PURPOSE Convert user supplied to internal number, using picture
.REMARKS Not all data types require conversion. Strings are filled with 
	blanks.
.RETURNS OK / NOK
--------------------*/
	TFIELD	*field;		/* MOD: The field to convert */
	char	*instr;		/* IN: user supplied value */
{
	char	*p;
	int	i, status;

  ENTER("tff_convert");		TRACE(instr);
	
  status = tff_check(field, instr);
  if (!status)		FINISH;

  i = strlen(instr);
	
  if (ischarField(field))			/* String */
  {
	field->options |= _FIELD_MODIFIED;
	if (i < field->string_size)
		status = OK;
	else	status = NOK, i = field->string_size-1;
	p = field->string, p += oscopy(p, instr, i);
	*p = EOS;
	
	if (field->type == _DTYPE_UPPER)	strupper(field->string);
	else if (field->type == _DTYPE_LOWER)	strlower(field->string);
	
	p += oscfill(p, field->string_size - i -1, ' ');
	*p = EOS; 			/* Fill With Blanks	*/
  }

  else if(isintField(field))	
  {	if (field->value.integer != integer)	
 		field->options |= _FIELD_MODIFIED;
 	field->value.integer = integer;
  }

  else if(isrealField(field))
  {	if (field->value.real != real)	
  		field->options |= _FIELD_MODIFIED;
  	field->value.real = real;
  }

  FIN:
  EXIT (status);
}

/*==========================================================================*/
int tff_check (field, instr)
/*+++++++++++++++++
.PURPOSE Check if a field contains a valid number
.REMARKS Checking performed only for Numeric Fields
.RETURNS OK / NOK
--------------------*/
	TFIELD	*field;		/* IN: The field concerned	*/
	char	*instr;		/* IN: user supplied value */
{
	int	i, status;


  ENTER("tff_check");
	
  i = strlen(instr);

  status = -1;		/* Default (bad) status, transformed */

  if (field->string_size == 0)	;	/* it's bad... */
  else if (isintField(field))	
  {	
	if (field->type&_DTYPE_TIME)	
	{	status = tr_at((char *)instr,i,&integer);
		if (field->type&_DTYPE_TIME80)	integer -= O_10years;
	}
	else	status = tr_pic((char *)instr, i, field->picture, &integer);

	if (status == 0)		/* BLANK Field */
		integer = field->value.intnull[1]; 
	else if (status > 0)
		integer	*= field->factor;
  }

  else if (isrealField(field))
  {
	status = tr_fpic (instr, i, field->picture, &real);
	if (status == 0)		/* BLANK Field */
		real = NULLF;
	else if (field->factor) 
		real *= field->factor;
  }
  else	status = 0;

  status = (status >= 0 ? OK : NOK);	/* Convert to OK / NOK */

  EXIT (status);
}

/*==========================================================================*/
int tff_edit (field)
/*+++++++++++++++++
.PURPOSE Edit the numeric value connected with the current field into
	the associated string.
.REMARKS Field also filled with blanks
.RETURNS OK / NOK (Field cannot be edited)
--------------------*/
	TFIELD	*field;		/* IN: The field concerned	*/
{
	double	real;
	long	integer, round;

  ENTER("tff_edit");
	
  if (field->string_size == 0)	EXIT(NOK);

  round = field->factor / 2;
  
  if (isintField(field))	
  {
	integer = field->value.integer;

	if (field->value.intnull[0] == field->value.intnull[1])
		field->string[0] = EOS; 	/* There is a null value */
	else	/* Not a NULL value	*/
	{
		if (round)	
		   {
                   if (integer >= 0)
			integer = (integer + round) / field->factor;
		   else	integer = (integer - round) / field->factor;
                   }

		if (field->type&_DTYPE_TIME)
		{	if (field->type&_DTYPE_TIME80)	integer += O_10years;
			ed_t   (field->string, field->picture, integer);
		}
		else	ed_pic (field->string, field->picture, integer);
	}
  }
  else if (isrealField(field))
  {
	real	= field->value.real;
	if (real <= NULLF)
		field->string[0] = EOS; 	/* There is a null value */
	else	/* Not a NULL value	*/
	{   if (round)
               {
	   	if (real > 0)
		     real = (real + round) / field->factor;
	   	else real = (real - round) / field->factor;
               }
	    ed_fpic (field->string, field->picture, real);
	}
  }

  EXIT(OK);
}

/*==========================================================================*/
int tff_dset (field, parm)
/*+++++++++++++++++
.PURPOSE Set the datatype of a field (field->type), 
	according to parm (field->parm).
.RETURNS Length of Field / -1 (error)
--------------------*/
	TFIELD	*field;		/* MOD: The field concerned	*/
	char	*parm;		/* IN: Field Type		*/
{
	char	*p;
	int	status;

  ENTER("+tff_dset");
	
  p = parm;
  if_not(p) 	p = "c";
  status = 0;

  switch(*p)
  { case 'i': 		/* INTEGER WITH NULL	*/
	switch(atoi(p))
	{ case 1:  field->value.intnull[1] = NULL1;	break;
	  case 2:  field->value.intnull[1] = NULL2;	break;
	  default: field->value.intnull[1] = NULL4;	break;
	}
	field->type = _DTYPE_INT;	break;
    case 'd': case 'r': case 'D': case 'R':
	field->type = _DTYPE_DOUBLE;	break;
    case '*':		/* ACTION ROUTINE	*/
	field->type = _DTYPE_ACTION;	break;
    default:
    	ERR_ED_STRING("Bad Parameter for Field ", field->name);
    	status = -1;
    case EOS:
    case 'c': 
 	field->type = _DTYPE_STR;	break;
    case 'C':
	field->type = _DTYPE_UPPER;	break;
  }
  if ( (status == 0) && (*p))	status = atoi(++p);

	/* Look for Modifiers */

  while (isalnum(*p))	switch(*(p++))
  {
    case 't': 	field->type |= (_DTYPE_TIME|_DTYPE_TIME80);
			break;
    case 'T': 	field->type |= _DTYPE_TIME;
			break;
    case 'D':	field->options |= _FIELD_DISPLAY;	/* DISPLAY ONLY */
			break;
    case 'E':	field->options |= _FIELD_NOECHO;	/* No Echo	*/
			break;
    case 'M':	field->options |= _FIELD_COMPUTED;	/* No Echo	*/
			break;
    case 'R':	field->options |= _FIELD_RAW;		/* Issue as it is */
			break;
  }

	/* Look for scaling factor in the data type.
 	 *** Note *** there must be no blank ..
	*/

  if(*p == '/')	field->factor = atoi(++p);
  if	(!field->factor)
		ERR_ED_STRING("Zero Factor for Field ", field->name);

  EXIT(status);
}

/*==========================================================================*/
int tf_edit(form)
/*++++++++++++++
.PURPOSE Edit the MODIFIED and COMPUTED fields, i.e. conversion binary -> picture.
.RETURNS OK.
.REMARKS To edit effectively all fields, use tf_oset(form, _FIELD_MODIFIED)
---------------*/
	TFORM	*form;	/* IN: The form concerned	*/
{
	int	i;
	TFIELD	*field;

  ENTER("tf_edit");

  for (i = form->nfields, field = form->fields; --i >= 0; field++)
  {
	if(field->string_size == 0)	continue;
	if(field->options & (_FIELD_MODIFIED|_FIELD_COMPUTED))
		tff_edit(field);
  }

  EXIT (OK);
}
