/*===========================================================================
  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
===========================================================================*/

/*+++++++++++++++++++++++ XC interface module XCX +++++++++++++++++++++++
.LANGUAGE C
.IDENTIFICATION Module XCX
.AUTHOR         K. Banse 		ESO - Garching
.KEYWORDS       communication
.ENVIRONMENT    VMS and UNIX
.COMMENTS 
holds XCXINI, XCZINI,
      XCXOPN, XCZOPN,
      XCXSTA, XCXGFD,
      XCXCLO, XCXSTP
.REMARKS

.VERSION  [1.00] 940422: creation

 090414		last modif
----------------------------------------------------------------------------*/

#include <midas_def.h>
#include <xconndef.h>
#include <fsydef.h>

#include <stdlib.h>
#include <stdio.h>



static int startup = -1;

static char  lt[4] = "a  ";
static char  xbuf[] = "-geometry =80x25+500+500 -e inmidas";


/*

*/

int crea_xterm(flag,midasunit,host,display,midasvers)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
Execute the `xterm' which in turn starts up a Midas session
.RETURNS
   = 0; new Midas started
   = 1; Midas already running - just connect
--------------------------------------------------------*/

char  flag;		/* IN: Z or X if called from XCZINI or XCXINI */
char  *midasunit;	/* IN: unit of Midas session to connect to */
char  *host; 		/* IN: host, if network scokets sould be used,
			       else '\0'  */
char  *display;		/* IN: display where Midas session will run
			       in X terminology */
char  *midasvers;	/* IN: mode+version (release) of Midas session;
			       the first char. is used to indicate a parallel
                               session (=P) or not, the version begins at the
			       2. char. of this param. E.g. with "P96NOV" we
			       use version 96NOV in parallel; with " test" we
			       use version test in non-parallel mode */

{
int  jj, fp;

char  *middir, parallel, vstr[120], xspecs[80], wstr[240], method[8];



if (*host == '\0')                      /* local host */
   {
   jj = Mrunning(midasunit,0);		/* check if Midas already running */
   if (jj == 1) return (1);
   }



/* build up string for Unix command `xterm'  */

if (!(middir = getenv("MID_WORK")))
   {
   if (!(middir = getenv("HOME"))) return (-1);

   (void) strcpy(wstr,middir);
   (void) strcat(wstr,"/midwork");
   }
else
   (void) strcpy(wstr,middir);

(void) strcat(wstr,"/Midxterms.def");
fp = osaopen(wstr,0);			/* open for READ */

/*
printf("osaopen of %s = %d\n",wstr,fp);
*/

xspecs[0] = '\0';
if (fp > -1)				/* we found such a file */
   {
  read_loop:
   jj = osaread(fp,wstr,82);
   if (jj < 0) goto close_file;
   
   if (jj > 0)				/* we got something */
      {
      if ((wstr[0] = *midasunit) && (wstr[1] = *(midasunit+1)))
         {				/* Midas unit matches */
         jj = CGN_INDEXC(wstr,'=') + 1;
         if (jj > 2)
            {
            (void) strcpy(xspecs,&wstr[jj]); 
            goto close_file;
            }
         }
      }
   goto read_loop;

  close_file:
   (void) osaclose(fp);
   } 

if (xspecs[0] != '\0')
   {
   if (*display != '\0')
      (void) sprintf(vstr,"xterm %s -d %s ",xspecs,display);
   else
      (void) sprintf(vstr,"xterm %s ",xspecs);
   }
else
   {
   if (*display != '\0')
      (void) sprintf(vstr,"xterm -d %s ",display);
   else
      (void) strcpy(vstr,"xterm ");
   }

if (flag == 'X')
   (void) strcpy(method,"sockets");
else
   (void) strcpy(method,"files");
 
if (*host != '\0')
   (void) sprintf(wstr,"%s %s -j \"SET/BACKGR %s,remote\" %s",
                  vstr,xbuf,method,midasunit);
else
   (void) sprintf(wstr,"%s %s -j \"SET/BACKGR %s\" %s",
                  vstr,xbuf,method,midasunit);


parallel = *midasvers++;
if (parallel != '\0')
   {
   if (parallel == 'P')
      {
      if (*midasvers != '\0')
         (void) sprintf(vstr," -r %s -p &",midasvers);
      else
         (void) sprintf(vstr," -p &");
      }
   else
      (void) sprintf(vstr," -r %s &",midasvers);
   (void) strcat(wstr,vstr);
   }

else
   (void) strcat(wstr," &");

(void) oshcmd(wstr,(char *) 0, (char *) 0, (char *) 0);

return (0);
}
/*

*/

int XCZINI(midasunit,myunit,direc,display,midasvers,maxtim,cid)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
start a Midas session with unit `myunit' +
open a connection to MIDAS session with unit `midasunit' using files
.ALGORITHM
update structures XCONNECT, BKMIDAS
.REMARKS
~/midwork is used for storing the files used for communication
.RETURNS
   = 0; o.k.
   = 90; invalid input
   = -1; problems with file communication
   = -2; requested Midas session could not be started
   = -3; requested Midas session not "ready" after `maxtim' seconds
   = -90; invalid Midas unit given
--------------------------------------------------------*/

char  *midasunit;       /* IN: unit of Midas session to connect to */
char  *myunit;          /* IN: pseudo Midas unit of calling program */
char  *direc;           /* IN: directory for send/receive files
                                if = '\0', use MID_WORK directory */
char  *display;         /* IN: display where Midas session will run
                               in X terminology */
char  *midasvers;	/* IN: mode+version (release) of Midas session;
			       the first char. is used to indicate a parallel
                               session (=P) or not, the version begins at the
			       2. char. of this param. E.g. with "P96NOV" we
			       use version 96NOV in parallel; with " test" we
			       use version test in non-parallel mode */
int   maxtim;		/* IN: max. time (seconds) we wait until Midas session
                               is ready (maybe = 0) */
int   *cid;             /* OUT: connection id,
                                to be used in all other routines */

{
int  stat, jj;




jj = crea_xterm('Z',midasunit,"",display,midasvers);	/* no different host */


if (jj == 1)					/* Midas already running */
   stat = XCZOPN(midasunit,myunit,direc,cid);
else
   {						/* new Midas started */
   jj = Mrunning(midasunit,maxtim);
   if (jj < 1)
      {
      if (jj == -1)
         stat = -2;
      else
         stat = -3;
      }

   else
      stat = XCZOPN(midasunit,myunit,direc,cid);
   }

return (stat);
}
/*

*/

int XCXINI(midasunit,host,display,midasvers,maxtim,cid)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
Start up a Midas session (on same host!) with unit `midasunit' and 
version `midasvers', open a connection to that session using local or
network sockets depending on `host'
.ALGORITHM
Use routine Mrunning to check for running Midas session, use the Unix command
`xterm -e inmidas' to start up Midas.
in the network.
Update structures XCONNECT, BKMIDAS
.REMARKS
/tmp is used for internal storage
.RETURNS
   = 0; o.k.
   = -1; problems with socket communication
   = -2; requested Midas session could not be started
   = -3; requested Midas session not "ready" after `maxtim' seconds
   = -90; invalid Midas unit given
--------------------------------------------------------*/

char  *midasunit;	/* IN: unit of Midas session to connect to */
char  *host; 		/* IN: host, if network scokets sould be used,
			       else '\0'  */
char  *display;		/* IN: display where Midas session will run
			       in X terminology */
char  *midasvers;	/* IN: mode+version (release) of Midas session;
			       the first char. is used to indicate a parallel
                               session (=P) or not, the version begins at the
			       2. char. of this param. E.g. with "P96NOV" we
			       use version 96NOV in parallel; with " test" we
			       use version test in non-parallel mode */
int   maxtim;		/* IN: max. time (seconds) we wait until Midas session
                               is ready (maybe = 0) */
int   *cid;	 	/* OUT: connection id, 
				to be used in all other routines */


{
int  stat, jj;




jj = crea_xterm('X',midasunit,host,display,midasvers);
if (jj == 1) return (XCXOPN(midasunit,host,cid));


if (*host != '\0')			/* remote host */
   return (XCXOPN(midasunit,host,cid));
    

jj = Mrunning(midasunit,maxtim);	/* wait `maxtim' seconds */
if (jj < 1)				/* on local host */
   {
   if (jj == -1)
      stat = -2;
   else
      stat = -3;
   return (stat);
   }
else
   return (XCXOPN(midasunit,host,cid));

}
/*

*/

int XCXOPN(midasunit,host,cid)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
open a connection to MIDAS session with unit `midasunit' using sockets
.ALGORITHM
use sockets to communicate with a Midas session on same host or another host
in the network;
update structures XCONNECT, BKMIDAS
.REMARKS
/tmp is used for internal storage
.RETURNS
   = 0; o.k.
   = -1; problems with socket communication
   = -90; invalid Midas unit given
   = -92; Midas session `midasunit' not existing
--------------------------------------------------------*/

char  *midasunit;	/* IN: unit of Midas session to connect to */
char  *host;		/* IN: host where Midas session is running
				if = '\0', local host */
int   *cid;	 	/* OUT: connection id, 
				to be used in all other routines */

{
register int  nr;
int  stat, jj;


/*  check `startup' */
 
if (startup == -1)
   {
   startup = 0;
   inxcon("OSX","");		/* init file names */
   }


if (*host != '\0')
   {
   char  wstr[100];

   jj = CGN_COPY(wstr,host);
   wstr[jj++] = ':';			/* build: host:unit */
   wstr[jj++] = midasunit[0];
   wstr[jj++] = midasunit[1];
   wstr[jj] = '\0';
   stat = msetup(1,wstr,"no",lt,"sockets");
   }
else
   stat = msetup(1,midasunit,"no",lt,"sockets");

if (stat == 0)
   {
   for (nr=0; nr<MAX_BACK; nr++)
      {
      if ((BKMIDAS[nr].UNIT[0] == midasunit[0]) &&
          (BKMIDAS[nr].UNIT[1] == midasunit[1]))
         {
         *cid = nr;
         goto next_step;
         }
      }
   stat = -90;
   }

else
   {
   if (stat == 4)
      {
      stat = -1;
      if (*host == '\0')	/* if same host, check */
         {			/* if Midas `midasunit' exists */
         jj = Mrunning(midasunit,0);
         if (jj == -1) stat = -92;	/* Midas session is not running */
         }
      }
   else if (stat == 34)
      stat = -90;
   }
startup = -1;			/* reset `startup' */


next_step:
if (lt[0] < 'z')		/* dummy backgr. char. */
   lt[0] ++;
else
   lt[0] = 'a';

return (stat);
}	
/*

*/

int XCXCLO(cid)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
close connection
.ALGORITHM
synchronous disk I/O
.RETURNS
   = 0; o.k.
   = -1; problems with socket/ communication
   = -90; invalid input to this interface
--------------------------------------------------------*/

int   cid;

{
int  stat;

char  munit[2];


if ((cid < 0) || (cid >= MAX_BACK) || (BKMIDAS[cid].UNIT[0] == ' '))
   return (-90);

munit[0] = BKMIDAS[cid].UNIT[0];
munit[1] = BKMIDAS[cid].UNIT[1];
startup = -1;

stat = msetup(0,munit,"no","no","no");		/* disconnect `munit' */

if ((stat == 4) || (stat == 5)) stat = -1;

return (stat);
}	

/*

*/

int XCXSTA(cid)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
check status of background Midas
.ALGORITHM
use `outmail'
.RETURNS
return status
   = 0; background Midas idle
   = 1; background Midas busy
   = -1; problems with socket/file communication
   = -90; invalid input to this interface
--------------------------------------------------------*/

int   cid;              /* IN: connection id */

{
int  stat, retstat[2];

char  wstr[8];                  /* just placeholder */


if ((cid < 0) || (cid >= MAX_BACK) || (BKMIDAS[cid].UNIT[0] == ' '))
   return (-90);


stat = outmail(3,wstr,cid,retstat);
if ((stat == 4) || (stat == 5)) stat = -1;

return (stat);
}

/*

*/

int XCXGFD(cid,fd)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
get file descriptor of socket used in communication with background Midas
.ALGORITHM
.RETURNS
return status
   = 0; all o.k.
   = -1; problems with socket communication
   = -90; invalid input to this interface
--------------------------------------------------------*/

int   cid;              /* IN: connection id */
int  *fd;		/* OUT: file descr. of used socket */

{
int  kk, gd;


if ((cid < 0) || (cid >= MAX_BACK) || (BKMIDAS[cid].UNIT[0] == ' '))
   return (-90);

kk = ClientInfo(BKMIDAS[cid].CHAN,&gd);
if (kk == 0)
   {
   *fd = gd;
   return (0);
   }
else
   return (-1);
}

/*

*/

int XCZOPN(midasunit,myunit,direc,cid)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
open a connection to MIDAS session with unit `midasunit' using files
.ALGORITHM
update structures XCONNECT, BKMIDAS
.REMARKS
~/midwork is used for storing the files used for communication
.RETURNS
   = 0; o.k.
   = 90; invalid input
   = -1; problems with file communication
   = -90; invalid Midas unit given
   = -92; Midas session `midasunit' not existing
--------------------------------------------------------*/

char  *midasunit;       /* IN : unit of Midas session to connect to */
char  *myunit;          /* IN : pseudo Midas unit of calling program */
char  *direc;		/* IN : directory for send/receive files 
                                if = '\0', use MID_WORK directory */
int   *cid;             /* OUT: connection id,
                                to be used in all other routines */

{
register int  nr;
int  stat, jj;

char *middir, wstr[240];


/*  check `startup' */

if (startup == -1)
   {
   if (*direc == '\0')
      {
      if (!(middir = getenv("MID_WORK")))
         {					/* use default: ~/midwork */
         if (!(middir = getenv("HOME"))) return (-99);

         jj = (int) strlen(middir);
         if (jj > 230) return (-99);

         (void) strcpy(wstr,middir);
         (void) strcat(wstr,"/midwork/");
         }
      else
         {					/* use MID_WORK directly */
         jj = (int) strlen(middir);
         if (jj > 238) return (-99);

         (void) strcpy(wstr,middir);

         if (wstr[jj-1] != FSY_DIREND)		/* we need xyz../ as dirspec */
            {
            wstr[jj++] = FSY_DIREND;
            wstr[jj] = '\0';
            }
         }
      }

   else
      {						/* use specified directory */
      jj = (int) strlen(direc);
      if (jj > 238) return (90);

      jj = CGN_COPY(wstr,direc);

#if vms
#else
      if (wstr[jj-1] != FSY_DIREND)		/* we need xyz../ as dirspec */
         {
         wstr[jj++] = FSY_DIREND;
         wstr[jj] = '\0';
         }
#endif
      }

   inxcon(myunit,wstr);         /* init file names */
   startup = 0;
   }


/* check, if required Midas is actually running */

jj = Mrunning(midasunit,0);

if (jj == -1)
   stat = -92;

else
   {
   stat = msetup(1,midasunit,"no",lt,"files");
   if (stat == 0)
      {
      for (nr=0; nr<MAX_BACK; nr++)
         {
         if ((BKMIDAS[nr].UNIT[0] == midasunit[0]) &&
             (BKMIDAS[nr].UNIT[1] == midasunit[1]))
            {
            *cid = nr;
            goto next_step;
            }
         }
      stat = 90;
      }
   else 
      {
      if (stat == 34)
         stat = -90;
      else if (stat == -2)
         stat = -1;
      }
   }

startup = -1;				/* error, so we reset */
return (stat);


next_step:
if (lt[0] < 'z')
   lt[0] ++;
else
   lt[0] = 'a';

return (0);
}
/*

*/

int XCXSTP(cid)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
stop connected Midas session + close connection
.ALGORITHM
use XCCSND + XCXCLO
.RETURNS
return status ( 0 = o.k )
--------------------------------------------------------*/

int   cid;

{
int  stat, retstat[2], n;


n = -1;
stat = XCCSND(cid,"clear/background 2; bye",n,retstat);
if (stat == 0)
   stat = XCXCLO(cid);
else
   (void) XCXCLO(cid);

return stat;
}

