/*  File: gnbkserver.c
 *  Author: Jean Thierry-Mieg (mieg@mrc-lmb.cam.ac.uk)
 *  Copyright (C) J Thierry-Mieg and R Durbin, 1992
 * -------------------------------------------------------------------
 * Acedb 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * or see the on-line version at http://www.gnu.org/copyleft/gpl.txt
 * -------------------------------------------------------------------
 * This file is part of the ACEDB genome database package, written by
 * 	Richard Durbin (MRC LMB, UK) rd@mrc-lmb.cam.ac.uk, and
 *	Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr
 *
 * Description:     Genbank indexing server
 *     a simple rpc daemon example
 *
 * Runs as a daemon if phase == 5
 * The server itself will disconnect after serverTimeOut seconds.
 *
 * If a time_out is set to 0 (zero) expiration is deactivated
 *
 * Exported functions:
 * HISTORY:
 * Last edited: Oct  9 10:36 2000 (edgrif)
 * Created: Wed Nov 25 12:26:06 1992 (mieg)
 * CVS info:   $Id: gnbkserver.c,v 1.8 2000/10/09 09:47:45 edgrif Exp $
 *-------------------------------------------------------------------
 */

static char* masterFile = 0 ;
#define DEFAULT_PORT 0x20000300

/* Time outs */
static int serverTimeOut = 600 ;

#define NON_GRAPHIC

#include "regular.h"
#include "array.h"
#include "call.h"
#include "mytime.h"
#include <signal.h>
#include "gnbk.h"

static FILE *out = NULL ;
static BOOL isDaemon = FALSE;
static  mytime_t last_t = 0 ;

/******************* INITIALISATION ***************************/
/**************************************************************/

void tStatus (void) { return ; } /* missing in the client */

void serverClose (void)
{ extern void closePortMap(void);
  
  if (!isDaemon) closePortMap();
  fprintf(out,"\n\n#### Server normal exit %s\n  A bientot \n\n",  timeShow(timeNow())) ;
  if (out && out!= stderr)
    filclose(out) ;
  gnbkClose () ;

  exit(EXIT_SUCCESS) ;
}

/**************************************************************/
  /* checkLife is called by alarm, 
   * but also after every query including from unauthorised clients
   */  

static void doTimeOut (int dummy)  /* dummy:  to please signal() prototypes */
{ 
  int dt ;
  mytime_t t = timeNow () ;


  if (serverTimeOut &&
      timeDiffSecs (last_t, t, &dt) &&
      10*dt > 9*serverTimeOut) 
    { fprintf(out,"// Reached timeout, server will shut down\n\n") ;
      serverClose () ;
    }
}

/****************** MAIN LOOP **********************/

Stack processQuery (char *question)
{ Stack s = 0 ;
  static int nTransactions = 0 ;
  extern Stack  gnbkQuery (char *question) ;

  alarm((unsigned int)0);

  nTransactions++ ;
  last_t = timeNow() ;	 
  s = gnbkQuery (question) ;
  fprintf (out, "Query %6d: %s %s :: %s\n",  nTransactions, 
	   timeShow (last_t), timeShow(timeNow()), question) ;

  alarm ((unsigned int)serverTimeOut) ;
  return s ;
}

/**************************************************/
/********* ACEDB non graphic Query Server  ********/
/**************************************************/

static void openOutFile (void)
{ char buf [12*1024] ;
  strcpy (buf, masterFile) ;
  strcat (buf, ".log") ;
        
  out = filopen (buf, 0, "a") ;
  if (!out)
    out = filopen (buf, 0, "w") ;
  if (!out)
    out = stderr ;
  setbuf (out, NULL) ;
  setbuf (stdout, NULL) ;
}

static void showBanner(u_long port)
{
  fprintf(out,"**** genbank network server: Version 0.0 ****") ;
  fprintf(out,"Authors: Jean Thierry-Mieg (CNRS, France) mieg@kaa.crbm.cnrs-mop.fr\n") ;
  fprintf(out,"         Ned Lamb (CNRS, France) ned@vega.crbm.cnrs-mop.fr\n") ;
  fprintf(out,"You may redistribute this program and database subject to the\n") ;
  fprintf(out,"conditions in the accompanying copyright file.  Anyone interested in\n") ;
  fprintf(out,"maintaining an up to date version should contact one of the authors\n") ;
  fprintf(out,"at the above email addresses.\n\n") ;

  
  fprintf(out," Master file: %s\n", masterFile) ;
  fprintf(out," Using port %lu to listen for clients\n",port);
  fprintf(out," The server will wait %d seconds for clients.\n",serverTimeOut);
}

static void usage(void)
{
  messout ("Usage: gnbk {1 | 2 | 3 | 4} file [...] [-port <port> [ -timeout <t>]]") ;
  messout( "Example: gnbk 5 f1 f2 f3 -port 20000333 -timeout 600") ;
  messout( "port and timeout (in seconds) are needed only for phase 4 and 5") ;
  messout( "   Phase 1: clean the masterFile, produces masterFile.1") ;
  messout( "   Phase 2: creates the index file masterFile.idx") ;
  messout( "   Phase 3: runs as a simple c code on stdin/out") ;
  messout( "   Phase 4: runs as an rpc service on port in foreground") ;
  messout( "   Phase 5: runs as an rpc daemon") ;
  exit (EXIT_FAILURE) ;
}

/* main: process the command lines, 
   initialises the system
   launches simple run if phase < 4
   runs rpc foreground if phase = 4
   runs as a daemon if pahse = 5 
*/
int main (int argc, char **argv)
{
  char dummy[15] ;
  extern void wait_for_client (u_long port, BOOL isDaemon) ;
  u_long p, port = DEFAULT_PORT;
  int phase = 0 , n, t ;
  mytime_t t0 = timeNow () ;
  extern int gnbkMax(void) ;
  Array fileNames ;

  if (argc < 3)
    { messout ("Sorry, you gave only %d argument(s) on the command line.", argc - 1) ;
      usage() ;
    }

  /* phase directs the way the program is used */
  if (sscanf(argv[1], "%d", &phase) != 1 || phase < 1  || phase > 5)
    usage() ;

  /* masterFile is the name of the big file to be indexed */
  fileNames = arrayCreate (argc - 2, char*) ;
  for (n = 2 ; n < argc ; n++)
    { if (!strcmp(argv[n], "-port")) break ;
    array(fileNames, n-2, char*) = argv[n] ;
    }
  if (arrayMax(fileNames) < 1)
    usage() ;
  masterFile = array(fileNames,0,char*) ;
  if (!gnbkInit (phase, fileNames))
    usage () ;
  switch (phase)
    {
    case 4: case 5: break ;
    default:  /* run a  simple C code */    
      return(EXIT_SUCCESS) ;
    }


  /* else we need a port */
  if (argc > n && 
      strlen(argv[n]) < 12 &&
      sscanf(argv[n++],"%s",dummy) == 1 &&
      !strcmp(dummy,"-port") &&      
      sscanf(argv[n++],"%lu",&p) == 1)
    port = p;
  else 
    usage () ;

  /* we now parse the timeouts */
  if (argc > n && 
      strlen(argv[n]) < 12 &&
      sscanf(argv[n++],"%s",dummy) == 1 &&
      !strcmp(dummy,"-timeout") &&      
      (sscanf(argv[n++],"%d",&t) == 1) &&
      t >= 0)
    serverTimeOut = t;
  
  openOutFile() ;

  if (phase == 5)
    { isDaemon = TRUE;
      fprintf(out,"\n\n#### Server forked at %s,\n####         ready at %s\n#### indexing  %d entries\n", 
	      timeShow (t0), timeShow(timeNow()), gnbkMax() ) ;
      fprintf(out,"#### TimeOut: %d seconds\n",serverTimeOut) ;
    }
  else
    showBanner(port) ;

  last_t = timeNow() ;
  if (serverTimeOut)
    {
      signal (SIGALRM, doTimeOut) ;  
      alarm ((unsigned int)serverTimeOut) ;
    }

  wait_for_client(port, isDaemon) ;
  messcrash("gnbk network server error: main loop returned") ;

  /* SHOULD NEVER REACH HERE...                                              */
  return(EXIT_FAILURE) ;
}

/**************************************************/
/**************************************************/

