/*===========================================================================
  Copyright (C) 1995-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 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
===========================================================================*/
 
/*+++++++++++++++++++++++++++++++  PREPA  +++++++++++++++++++++++++++++++

.LANGUAGE     C

.IDENTIFICATION
MIDAS front end (main module prepa.c)
holds   intermail, main (terminal front end) module, init_here

.AUTHOR       K. Banse                   	ESO - Garching

.KEYWORDS     MIDAS front end

.ENVIRONMENT  VMS and UNIX

.PURPOSE
synchronize fore- and background processes; 
get the MIDAS command string + take action accordingly

.ALGORITHM
loop on command input from terminal and pass commands to MIDAS monitor
test for background activity and synchronize

we have our "own" connected MIDAS - commands are passed via calls of `prepx'

.RETURNS  nothing

.VERSION
 1.00		930125: pulled out from "old" prepa.c

 090429		last modif
------------------------------------------------------------------------*/
 

#include <fileexts.h>
#include <unistd.h>		/* Defines STDIN_FILENO */
#include <signal.h>
#ifndef SIGUSR1
#define SIGUSR1 30
#endif
#ifndef SIGUSR2
#define SIGUSR2 31
#endif
#ifndef STDIN_FILENO
#define STDIN_FILENO 0
#endif

#if vms				/* FO's TW stuff may be needed for VMS only */
#define TW_import 0
#include <tw.h>
#include <osterm.h>
#include <ok.h>
#endif
 
#include <osyparms.h>
#include <monitdef.h>
#include <midfront.h>
#include <fsydef.h>
 

static char   wstr[160];

int    is_a_tty;			/* Is this a terminal, (yes=1) */
/*

*/

void intermail()

{
osscatch(SIGUSR1,intermail);            /* reenable interrupt catching */

if (server.MODE == 2) return;           /* already in background mode ... */

if (TERM.INTENA != 1)
   {
   busymail();
   return;
   }

#if vms
if (TERM.FLAG == 1) SupplyInput("\r");
#endif

TERM.TIMEOUT = 2;


/* get current process id and send alarm signal to force timeout */

osssend(FRONT.PID,SIGALRM);

}

/*

*/

int main()
 
{
int   pxflag, lwindow, kk, jj, iwa;
int   pxinfo[6];
int   cur_com, termflag, more_cmnds;
 
char  firstchar, *cpntr;
char  rmaind[200];




/*  first time activities here...  */
 
is_a_tty = isatty(STDIN_FILENO);        /* Is this is a terminal ? (yes=1) */

MID_TTINFO(&TERM.COLS,&TERM.LINES);	/* get initial terminal size */
cur_com = 0;  
more_cmnds = 0;

init_here(wstr,pxinfo);		/* initialize with `prepx' */
 

/*  startup by executing systemwide LOGIN procedure  */
 
pxflag = -3;			/* -3 tells the Monitor to do that */


#ifndef NO_READLINE
#else
printf
("\n*** No ncurses development library => no command line "
"editing in Midas...***\n\n");
#endif

login_job:

#if vms
(void) TTSET(0);                                /* close terminal settings */
iwa = prepx(pxflag,wstr,pxinfo);
(void) TTSET(1);                                /* set terminal settings */

#else
iwa = prepx(pxflag,wstr,pxinfo);
#endif


switch(iwa)
   {
  case -1:                              /* back from command BYE */
   moncnt = 0;
   (void) COM_WINDOW("WR",&cur_com);    /* save comnd-buf in midtempXY.prg */
   if (server.MODE != 0)
      inmail(9,rmaind,&iwa);		/* tidy up any outstanding mail */

#ifndef NO_READLINE
   free_cmd_list();		/* free the cmd_list allocated for readline */
   close_xhelp();		/* close socket with the GUI help */
#else
#if vms
   (void) TTSET(2);		/* close terminal */
#endif
#endif

   ospexit(0);                          /* and get the hell out of here...  */

  case 1:
   FRONT.COMCNT = 999;                  /* forces a CLEAR next time */
   break;

  case 2:
   (void) COM_WINDOW("RE",&cur_com);
   break;

  case 3:
   (void) COM_WINDOW("EXT",&cur_com);
   break;

  case 4:
   moncnt = pxinfo[0];
   (void) COM_WINDOW("WR",&cur_com);
   break;

  case 6:
#if vms
   TTSET(2);                            /* close terminal */
   TTINIT(1);                           /* reinitialize */
   TERM.EDITMODE = pxinfo[0];
#endif
   break;

  default:		/*  check if system + personal login.prg was o.k. */
   (void) SCKRDI("ERROR",3,2,&iwa,pxinfo,&kk,&jj);	/* still = 79? */
   if (pxinfo[0] != 0)
      {
      pxinfo[0] = 0;
      pxinfo[1] = 1;
      kk = 0;
      (void) SCKWRI("ERROR",pxinfo,3,2,&kk);
      SCTPUT("Warning: Your `login.prg' is incorrect...!");
      SCTPUT
      ("Execute it again via `@@ login' to get the relevant error messages");
      }
   goto main_loop;			/* login part finished */
   }

pxflag = 1;                             /* tell prepx that we continue */
goto login_job;


 
 
main_loop:   					/*
----------					*/

termflag = 0;			/* clear terminal_input_flag  */
lwindow = 1;			/* default to store in command window  */
 
if (FRONT.INTERM == 1)                  /* last time was an interrupt */
   {
   FRONT.INTERM = 0;                    /* reset mail_interrupt_flag */
   ERRORS.SYS = inmail(8,rmaind,&iwa);	/* it's the `file/int' mechanism */
   if (ERRORS.SYS != 0) goto mail_error;
   }

FRONT.COMCNT++;			/* increment command counter  */
if (FRONT.COMCNT > 999)
   {				/* reset FRONT.COMCNT + clear command window */
   (void) COM_WINDOW("CL",&iwa);	
   FRONT.COMCNT = 1;
   }

cpntr = FRONT.PROMPT + FRONT.PEND;		/* build prompt string */
(void) sprintf(cpntr,"%3.3d%c ",FRONT.COMCNT,FRONT.ENV);


if (more_cmnds > 0)			/* test, if several commans in line */
   {
   kk = break_line(&more_cmnds,rmaind);
   if (kk != -1) goto parsing;
   }

if (server.MODE != 0)                   /* If we are in background mode */
   {					/* look for input from clients */
   ERRORS.SYS = inmail(1,rmaind,&iwa);
   if (ERRORS.SYS != 0) goto mail_error;
   }

else
   {
   iwa = MYREAD();	 		/* wait for input from terminal */

   if (TERM.TIMEOUT == 2)               /* if there was a mail interrupt */
      {
      FRONT.INTERM = 1;                 /* so next time we know */
      ERRORS.SYS = inmail(1,rmaind,&iwa);	/* get input from clients */
      if (ERRORS.SYS != 0) goto mail_error;
      }
 
   else if (iwa == -1)
      {					/* a playback is finished */
      (void) prepx(-4,wstr,pxinfo);			/* tell Monitor */
      goto main_loop;
      }
   TERM.TIMEOUT = 0;
   }
 
 
ERRORS.OFFSET = FRONT.PEND + 5;

MID_TTINFO(&TERM.COLS,&TERM.LINES);	/* get current terminal size */
KIWORDS[OFF_LOG+9] = TERM.COLS;
KIWORDS[OFF_LOG+10] = TERM.LINES;

more_cmnds = 0;
kk = break_line(&more_cmnds,rmaind);
if (kk == -1)                           /* e.g. only RETURN key...  */
   {
   if (LINE.STR[0] == '!')
      {
      (void) MID_LOG('G',LINE.STR,LINE.LEN);	/* log comment line */
      FRONT.COMCNT--;                   /* and go for next command  */
      }
   else
      (void) COM_WINDOW("SH",&iwa);
   goto main_loop;
   }
 
/*

*/

/*  now parse terminal input */
 
parsing:
termflag++;				/* increment terminal_input_flag  */
moncnt = 0 ;				/* init moncnt */


/* now we do, what PARSE does on the server side */

for (kk=0; kk<LINE.LEN; kk++)
   {
   if (LINE.STR[kk] != ' ') goto step_2;
   }
goto main_loop;


step_2:
if ((LINE.STR[kk] == '$') && (LINE.STR[kk+1] == '$'))
   {
   TOKEN[0].STR[0] = '$';
   TOKEN[0].LEN = 1;
   moncnt = 1;
   }
else
   {
   moncnt = Parse3(kk);
   if (moncnt < 0)
      {
      if (lwindow != 0) (void) COM_WINDOW("AD",&cur_com);
      goto main_loop;		/* error message already displayed in PARSE */
      }
   }


firstchar = TOKEN[0].STR[0];			/* get 1. char. of 1. token */

 
/*  the commands QUIT or EXIT are caught already here ...   */

if ((firstchar == 'q') || (firstchar == 'Q') || 
    (firstchar == 'e') || (firstchar == 'E'))
   {
   CGN_UPSTR(TOKEN[0].STR);
   if ( (strcmp(TOKEN[0].STR,"QUIT") == 0) ||
        (strcmp(TOKEN[0].STR,"EXIT") == 0) )
      {						/* Yes. It's QUIT/EXIT  */
      LINE.LEN = CGN_COPY(LINE.STR,"BYE");	/* emulate a BYE  */
      goto parsing;
      }
   }



/*  see, if it's #, .#, #. or :  ( = old command)         */
/*  ---------------------------------------------         */

if (((firstchar >= '0') && (firstchar <= '9')) || 
    (firstchar == '.') ||
    (firstchar == ':')) 
   {
   if (unlikely(termflag > 20))			/* avoid infinite loops */
      {
      ERRORS.SYS = 5;
      goto error_1;
      }
   else
      {
      lwindow = 0;
      iwa = NUMBIZ(&cur_com);
      if (iwa == -1)
         goto main_loop;
      else if (iwa > 0)
         {
         if (iwa == 2) lwindow = 1;		/* edited comnds are stored */
         kk = REDOBIZ(iwa);
         if (kk == 0)
            goto main_loop;
         else
            {
            ERRORS.OFFSET = 0;
            kk = 0;
            (void) break_line(&kk,wstr);
            if (kk != 0) 
               {				/* update `rmaind' buffer */
               if (more_cmnds != 0)
                  (void) strcat(wstr,rmaind);
               (void) strcpy(rmaind,wstr);
               more_cmnds = 1;
               }
            goto parsing;
            }
         }
      }
   }


/*  store command in command window   */

if (lwindow != 0)
   {
   (void) COM_WINDOW("AD",&cur_com);
   lwindow = 0;				/* make sure we only store once  */
   if (firstchar == '+') goto main_loop;
   }

/*

*/

/*  prepare char. + int buffers for `prepx' call */
 
pxflag = 0;				/* normal call of prepx */

 
call_job:

#if vms
if (TERM.FLAG == 1)
   {
   (void) TTSET(0);				/* close terminal settings */
   iwa = prepx(pxflag,wstr,pxinfo);
   (void) TTSET(1);				/* set terminal settings */
   }
else
   {
   iwa = prepx(pxflag,wstr,pxinfo);
   }
#else

iwa = prepx(pxflag,wstr,pxinfo);
#endif

switch(iwa)
   {
  case -1:				/* back from command BYE */
   moncnt = 0;
   (void) COM_WINDOW("WR",&cur_com);	/* save comnd-buf in midtempXY.prg */
   if (server.MODE != 0)
      inmail(9,rmaind,&iwa);	/* tidy up any outstanding mail */

#ifndef NO_READLINE
   free_cmd_list();		/* free the cmd_list allocated for readline */
   close_xhelp();		/* close socket with the GUI help */
#else
#if vms
   (void) TTSET(2);		/* close terminal */
#endif
#endif

   ospexit(0);				/* and get the hell out of here...  */

  case 0:
   goto main_loop;			/* "normal" return from prepx */

  case 1:
   FRONT.COMCNT = 999;			/* forces a CLEAR next time */
   break;

  case 2:
   (void) COM_WINDOW("RE",&cur_com);
   break;

  case 3:
   (void) COM_WINDOW("EXT",&cur_com);
   break;

  case 4:
   moncnt = pxinfo[0];
   (void) COM_WINDOW("WR",&cur_com);
   break;

  case 5:
   FRONT.PP = CGN_OPEN(wstr,0);                /*  open for reading only  */
   if (FRONT.PP == -1)
      {
      FRONT.PLAYBACK = 0;
      ERRORS.SYS = 22;
      PREPERR("FSY",wstr," ");
      }
   else
      {
      char  str[120];

      (void) sprintf(str,"--- starting playback from: %s ---",wstr);
      SCTPUT(str);
      }
   goto main_loop;                   /* now read input from playback file */

  case 6:
#if vms
   TTSET(2);                            /* close terminal */
   TTINIT(1);                           /* reinitialize */
   TERM.EDITMODE = pxinfo[0];
#endif
   break;

  case 7:				/* playback aborted in Monitor */
   osaclose(FRONT.PP);
   goto main_loop;                   /* now read input from terminal */

  case 99:                              /* that's the end of a batch run */
   LINE.LEN = CGN_COPY(LINE.STR,"BYE");  
   goto parsing;                        /* emulate a BYE  */

  default:
   (void) printf("Prepa: We should never come here...\n\r");
 
   }

pxflag = 1;				/* tell prepx that we continue */
goto call_job;


/*    come here to display error messages      */

error_1:
if (ERRORS.INDEX == -1)
   PREPERR("MIDAS",LINE.STR," ");
else
   PREPERR("MIDAS",LINE.STR,TOKEN[ERRORS.INDEX].STR);
goto main_loop;                         /* look for next command   */

mail_error:
PREPERR("OSY",""," ");
goto main_loop;                         /* look for next command   */
}
/*

*/
 
void init_here(cp,ip)
char  *cp;
int   *ip;

{
int  fid, stat, jj;
register int  nr;



/*  get symbols DAZUNIT, MID_WORK */

OSY_GETSYMB("DAZUNIT",wstr,4);
FRONT.DAZUNIT[0] = wstr[0];
FRONT.DAZUNIT[1] = wstr[1];

stat = OSY_TRNLOG("MID_WORK",wstr,160,&jj);    /* Decode startup directory */
if ((stat != 0) || (jj > 160))
   {
   (void) printf
   ("we could not translate MID_WORK or MID_WORK > 160 char.\n\r");
   ospexit(1);
   }

#if vms
if (wstr[jj-1] != FSY_DISKEND)
   {
   if (wstr[jj-1] != FSY_DIREND)
      {
      wstr[jj++] = FSY_DIREND;
      wstr[jj] = '\0';
      }
   }
#else

if (wstr[jj-1] != FSY_DIREND)
   {
   wstr[jj++] = FSY_DIREND;
   wstr[jj] = '\0';
   }
#endif

(void) strcpy(FRONT.STARTUP,wstr);	/* save name of startup directory */

(void) strcpy(FRONT.PROMPT,"Midas ");	/* init prompt string  */
FRONT.PEND = 6;                         /* length of prompt + 1 */


/*  get PID + also store PID in file MIDASxy.PID  */

FRONT.PID = oshpid();			/*  get process id */
jj = CGN_COPY(wstr,FRONT.STARTUP);
(void) strcpy(&wstr[jj],"MIDAS  .PID");
wstr[jj+5] = FRONT.DAZUNIT[0];
wstr[jj+6] = FRONT.DAZUNIT[1];
fid = osaopen(wstr,1);
if (fid > 0)
   {

#if vms
   (void)sprintf(wstr,"%X",FRONT.PID);        /* we need PID in hexa ...  */

#else
   (void)sprintf(wstr,"%d",FRONT.PID);
#endif

   osawrite(fid,wstr,(int)strlen(wstr));
   osaclose(fid);
   }
else
   (void) printf("Could not build PID file MIDAS%c%c.PID\n\r",
          FRONT.DAZUNIT[0],FRONT.DAZUNIT[1]);

FRONT.PP = -1;
FRONT.PLAYBACK = 0;
FRONT.INTERM = 0;
FRONT.ENV = '>';

server.MODE = 0;
server.ECKO = 'N';

for (nr=0; nr<10; nr++)
   {
   OLDTOKEN[nr].STR[0] = '?';
   OLDTOKEN[nr].STR[1] = '\0';
   OLDTOKEN[nr].LEN = 1;
   }

(void) inxcon(FRONT.DAZUNIT,FRONT.STARTUP);   /* init communication stuff */

(void) prepx(-1,cp,ip);			/* init on server side (get keys in) */
KIWORDS[OFF_LOG+9] = TERM.COLS;		/* LOG(10,11) hold initial no. of */
KIWORDS[OFF_LOG+10] = TERM.LINES;	/* columns + lines */

TERM.FLAG = 0;				/* turn TW off  */
TERM.EDITMODE = 0;
TERM.INTENA = 0;


/*  for VMS check, if we use TermWindows (only in interactive mode)  */

#if vms
cbuf[0] = ' ';
(void) OSY_TRNLOG("TERMWIN",cbuf,3,&jj);
if (((cbuf[0] == 'y') || (cbuf[0] == 'Y')) && (KIWORDS[OFF_MODE+2] != 1))
   TERM.FLAG = 1;              /* turn TW on  */
#endif


(void) strncpy(FRONT.TITLE,cp,13);     /* (P) MIDAS version patch_level */
if (FRONT.TITLE[12] != ' ')
   FRONT.TITLE[13] = '\0';
else
   FRONT.TITLE[11] = '\0';
cp += 13;
(void) strncpy(FRONT.SYSTEM,cp,20);


/* create command buffer with 15 entries + init title for command list */

jj = 15;
(void) COM_WINDOW("INIT",&jj);

osscatch(SIGUSR1,intermail);      /* `intermail' for mail interrupts */

(void) TTINIT(ip[2]);			/* pass the header flag */
}
