/*===========================================================================
  Copyright (C) 1995-2005 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 Massachusetts Ave, Cambridge, 
  MA 02139, USA.
 
  Correspondence 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
===========================================================================*/

/*++++++++++++++++++
.LANGUAGE	C
.TYPE		Module
.NAME		tbledit.c
.VERSION 0.0	17-Mar-1989:	First design
.VERSION 1.1	24-Nov-1989:	Corrected (FO)
.VERSION 1.2	12-Feb-1990:	Row boundary checking. JDP.
				Check if several commands are given, to speed up
.VERSION 1.3	28-Oct-1990: Just patch for new version.
.AUTHOR		Daniel Ponz, Francois Ochsenbein
.CATEGORY	Table Editor
.COMMENTS	Just here Field i/o
	*** The provisional implementation assumes the functions
		ClearError()		removes error text, if any
		ShowError(text)		shows error text
	*** Actions
		NEXTCOL  returned for `asking to move to next (right) col'
		PREVCOL  returned for `asking to move to previous (left) col'
		HOMECOL  returned for `asking to move to first (left) col'
		BAD_KEY  returned for unknown key
.ENVIRONMENT	MIDAS, TermWindows

.VERSION
051012		last modif

------------------------------------------------------------------------*/

#include <tw.h>				/* Window system	*/
#include <ok.h>				/* Just OK / NOK definitions */
#include <macrogen.h>			/* General purpose macros, e.g. MAX */
#include <str.h>			/* General string handling  */

#include <tbldef.h>	
#include <tfmdef.h>	
#include <tbledt.h>	
#include <tblfmt.h>	
#include <proto_tbl.h>

#include <stdio.h>


#define MAXEDT_ELEMENT	255	/* Maximal size for getting a single
				 * table element */
static char	buffer[MAXEDT_ELEMENT+1];
static char	buf_er[MAXEDT_ELEMENT+1];

static double variable[(MAXEDT_ELEMENT+7)/8];


/*========================================================================*/
int compute_col()
/*++++++++
.PURPOSE Compute the current column from cursor position
		in range [0, edt_nc]
.REMARKS Should be a general function ? should thecol be external
	(known to all edt functions) ?
.RETURNS The number
---------*/
{
	int	j, col1;

  GetCursor(data_subwindow, cursor_pos);
  col1 = cursor_pos[1];

  for (j=0; col1 > FMT[j].LAST; j++)	;

  return(j);
}

static int Edit(str)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Convert from Binary (in variable) to str
.REMARKS Used in cunjunction with ModsWithCheck
.RETURNS OK=1 (str is correct) / NOK=0 (Bad char)
------------------------------------------------------------------------*/
	char	*str;	/* OUT: Edited number	*/
{
  return (TCEEDC(edt_tid, (char *)variable, FMT[thecol].colno, str));
}

static int Convert(str) 
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Convert from Char to Binary
.REMARKS Used in conjunction with ModsWithCheck
.RETURNS 0 (NULL) / -1 (error) / positive number if OK 
------------------------------------------------------------------------*/
	char	*str;	/* IN: String to Convert	*/
{
	int	status, i;
	
  status = TCETRC(edt_tid, (char *)variable, FMT[thecol].colno, str);
  if (status)	status = -1;	/* Error */
  else 		status = *str;
  return(status);
}

/*========================================================================*/
static int check(w, str, size) 
/*++++++++++++++
.PURPOSE Check Function for Input of an Element
.REMARKS Used in cunjunction with ModsWithCheck
.RETURNS OK=1 (input is correct) / NOK=0 (Bad input)
.METHOD  Convert str to Binary (if not a char string!), tne convert back.
--------------*/
	WINDOW	*w;	/* IN: The Window	*/
	char	*str;	/* MOD: What the user typed	*/
	int	size;	/* IN: Size of str buffer	*/
{     
	char    temp[MAXEDT_ELEMENT+80];
	int	status;
        int    cur_col, cur_row;	
    
  status = -1;
  if (strcomp(buf_er,str) == 0)	status = -2;
  if (status == -1)		status = Convert(str);
  if (status == -1) {
	status = NOK; 
	ShowError(">>> Format Error"), Bell();
  }
  else {		/* Correct Entry. Modify underlying table	*/
    	SetAttr(w, _NORMAL_);	   /* Will be redisplayed correctly	*/
    	if (status >= 0) {	/* A modification of the value ... */
      		GetCursor(data_subwindow, cursor_pos);
       		cur_col = edt_column[compute_col()];
       		cur_row = edt_row[cursor_pos[0]];
       		if (cur_row <= 0 || cur_row > edt_narow) {
            		status = NOK;		/* check row boundaries */
              		ShowError(" Limit of the table ");
              		Bell();
              		return(status);
            	}
    		if (status == 0)  {	/* NULL value */
          		sprintf(temp,"Delete row %d, column %d", 
				cur_row,cur_col);
			TCEDEL(edt_tid, cur_row, cur_col);
 		}
       		else {
         		sprintf(temp,"Rewrite row %d, column %d, element %s ",
         		cur_row, cur_col, str);
        		TCEWRC(edt_tid, cur_row, cur_col, str);
		}
  		ShowError(temp);
  	}
    	if (status > 0) Edit(str); /* Converts back using Format 	*/
    	SetAttr(w, _NORMAL_);	   /* Will be redisplayed correctly	*/
  	status = OK;
  }

  return(status);
}

/*========================================================================*/
int edt_edfield()
/*++++++++
.PURPOSE Edit any table element. What the user entered is checked.
	**** Note: EnableArrows(data_subwindow) and EnableKeypad(data_subwindow)
	is in effect (normally called after OpenWindow)
.RETURNS The action hit by the user. Can be just Return.
.REMARKS Process here only one element.
----------*/
{

	int	lencol;		/* Width of the current column	*/
	int	key_group;	/* The group of keys (_KEYPAD_, etc) */
	char	key_hit;	/* Explanation within key_group	*/
        int 	key1, key2;	/* input key(s)                 */
  	int	i;
  
	
  thecol = compute_col();	/* Just know the index in FMT tables */

  lencol = FMT[thecol].LAST - FMT[thecol].FIRST; 
  lencol = MIN(lencol, sizeof(buffer)-1);
  
	/* The acquisistion of the contents of the current column
	 * is made via TranslateWindow. Is there a better solution ? */

	/* Suppress cursor mouvements echo */
  DeactiveWindow(data_subwindow); 

  CursorTo(data_subwindow, cursor_pos[0], FMT[thecol].FIRST);
  TranslateWindow(data_subwindow, buffer, lencol);
  buffer[lencol] = '\0';
  for (i = lencol-1; i >= 0 && buffer[i] == ' '; buffer[i--] = '\0')   ;
  oscopy(buf_er,buffer,lencol+1);

  Input_Loop:
  SetAttr(data_subwindow, _REVERSE_);		
  
	/* Before asking for the input, check if some command
	 * was already typed in. Useless to repaint the screen... */

  if (CheckInput()){
	key_group = GetChar(&key_hit);
	if ( (key_group == _STANDARD_) && isprint(key_hit)) {
		UngetChar(&key_hit);
		goto Get_User_Input;
	}
	if (key_hit == '\r')	key_hit = EOS;
	buffer[0] = key_hit;
  	goto Execute_User_Input;
  }

	/* Ready now for Input. Buffer contains a copy of the
	 * element (in Character). It will be redisplayed in Reverse */

  Get_User_Input:
  ActiveWindow(data_subwindow);  

  key_group = ModsWithCheck(data_subwindow, buffer, lencol+1, check);

  Execute_User_Input:
  SetAttr(data_subwindow, _NORMAL_);	

	/* The result of Mods may be:
	 * _INTERRUPT_	: take the original (no modif) 
	 * _STANDARD_	: terminated by the Carriage Return
	 * 0		: We must look what was exactly the key via GetKey
	 * Other	: A special key was hit as the FIRST input
	 */

  switch(key_group)
  {
	case _INTERRUPT_:	
			ShowError("***INTERRUPT*** Hit Return");
  			oscopy(buffer,buf_er,lencol+1);
			goto Input_Loop;
	case _STANDARD_:	if (buffer[0]  && iscntrl(buffer[0])) 
				 {key_hit = buffer[0], buffer[0] = EOS; break;}
				return(NEXTFIELD);
	case 0:			key_group = GetKey(data_subwindow, &key_hit);
				break;
    	case _EOF_:		break; 
	default:		key_hit = buffer[0], buffer[0] = EOS;
				break;
  }

  if (key_group == _EOF_)	return(COMMAND);
  if (key_group == _STANDARD_)	key_group = 0;
  key1 = key_group<<8 | key_hit;

  key2 = 0;
	
	switch(tk_check(key1))
	{
	  case 0: return (BAD_KEY);	/* Doesn't map to an action */

	  case 2: key_group = GetKey(data_subwindow, &key_hit);
  		  key2      = key_group<<8 | key_hit;

	  case 1: return (tk_exec(key1, key2));
	}
  
 return(BAD_KEY);
}

/*========================================================================*/

int tbl_edit()
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
        Edit table  	
.KEYWORDS
  	Tables, Editor
.ALGORITHM

.RETURNS
        Status 0 OK - save table; -1 NOK - no save the table
------------------------------------------------------------------*/

{
	int	iend, old_direction, old_state;
	int	old_err;
	
	/* iteration on input */;

   TCOGET("display_errors", &old_err);	/* Don't Display */
   TCOSET("display_errors", 0);	/* Don't Display */
   while ((edt_action = edt_edfield()) != TERMINATE) 

   {                                    
                                        /* decide upon main actions */
      switch (edt_action) {

      case NEXTFIELD: 
	GetCursor(data_subwindow, cursor_pos);
      	thecol = compute_col();
      	if ((thecol+1 >= edt_nc) && (edt_column[edt_nc-1] >= edt_ncol))
   	{		/* Must go to First Column, next line */
		if (cursor_pos[0]+1 >= data_lines)	/* Must scroll */
      		{	old_direction = edt_advance;
      			edt_advance = TRUE;
      			iend = edt_row[edt_nr-1];
      			if (++iend > edt_narow)		/* End of Table */
      				edt_nextcol();
      			else	
			{	old_state = DeactiveWindow(editor_window);
				CursorHome(data_subwindow),
    				cursor_pos[0] = cursor_pos[1] = 0;
      				if (edt_column[0] > 1)	edt_leftpage();
      				edt_newpage();
      				CursorDown(data_subwindow, iend - edt_row[0]);
      				if (old_state) ActiveWindow(editor_window);
      			}
      			edt_advance = old_direction;
      		}
      		else	/* I don't have to scroll. However, verify */
      		{	if (edt_column[0] > 1)	edt_leftpage();
      			edt_nextline();
      		}
      	}
      	else	edt_nextcol();
	break;
      case INTERRUPT :  return (-1);                  
      case BAD_KEY:     edt_badkey();                 break; 
      case NEXTCOL:     edt_nextcol();                break;
      case COMMAND:     edt_command();  
                        if (edt_action == TERMINATE)  return (0);
                        break;
     }
   }
   TCOSET("display_errors", old_err);	/* Reset at its previous value */
   return (0);
}
