/*********************************************************************************
 **
 ** Test program for smart sampler.
 **
 ** For now, just kick off gulper and cluster servers and smartSampler
 ** driver, then we just loop through user commands, let them fire the
 ** gulpers (direct), check the gulper state (direct), and check the
 ** next gulper to be fired (through smartsamplerserver).  Meanwhile,
 ** the clusterserver should be updating along the way, so as time
 ** progresses the smartsampler should be doing stuff based on that.
 **
 *********************************************************************************/
#include <signal.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "Syslog.h"
#include "System.h"
#include "GulperIF.h"
#include "ClusterIF.h"
#include "SmartSamplerIF.h"

#define NGULPERS 10

void signalHandler(int signalNo);

pid_t smartSamplerPID = -1;
pid_t gulperPID = -1;
//pid_t clusterPID = -1;
pid_t seabirdPID = -1;
pid_t hs2PID = -1;
pid_t isusPID = -1;

void checkkill(pid_t pidIn){if(pidIn != -1)kill(pidIn,SIGTERM);}
void signalHandler(int signalNo)
{
  checkkill(smartSamplerPID);
  checkkill(gulperPID);
  //  checkkill(clusterPID);
  checkkill(seabirdPID);
  checkkill(hs2PID);
  checkkill(isusPID);
  kill(0, SIGQUIT);
  exit(0);
}


pid_t startServer(const char *name){
  pid_t myPID;
  char arg[128];

  strcpy(arg,"");
  if(!strcmp(name,"gulperServer")){
    // Hardcode some serial args I found in the SerialDeviceTest code.
    strcat(arg," -serial /dev/ser1,9600,8,EVEN,1");
  }

  Syslog::write("Starting %s with arg %s...\n",name,arg);
  if ( (myPID = System::spawn(name,arg)) == -1)
    {
      Syslog::write("System::spawn(%s) failed\n",name);
      exit(-1);
    }else{
    Syslog::write("%s PID = %d\n",name,myPID);
  }
  return(myPID);
}

bool handle_one_command(SmartSamplerIF *smartSampler,GulperIF *gulper){
  GulperIF::gs10 gu_state;
  int id1,id2;
  char *token,buf[256],obuf1[32],obuf2[32];
  char *helpStr = "Valid commands are:\n"
    "   help   - Help\n"
    "   suspend dtNum - Suspend the given DT.\n"
    "   resume dtNum  - Undo suspension.\n"
    "   reset dtNum  - Reset state.\n"
    "   dtstate dtNum - cause state dump for a given dt.\n"
    "   allocate gnum dtnum  - (re)allocate a gulper.\n"
    "   state  - print the gulper state (both from Gulper and SmartSampler), call dtDumpState for dt state.\n"
    "   last - print info on last gulper fired (by SmartSampler).\n"
    "   fire gnum - Fire a gulper directly from this test program.\n"
    "   ssfire gnum - Fire a gulper directly by SmartSampler command.\n"
    "   quit   - Quit.\n";
  Syslog::write("SmartSamplerTest> ");
  if (gets(buf) == 0) return(true);  // Some error occurred

  if ( !strncmp(buf, "help", 4) || !strncmp(buf, "Help", 4) || 
       !strncmp(buf, "" , 1) ){
    Syslog::write("%s",helpStr);

  }else if (!strncmp(buf, "suspend", 7 )){
    token = strtok(buf, " \t");
    token = strtok(0, " \t");
    id1 = atoi(token);
    smartSampler->dtSuspend((short)id1);
    Syslog::write("Suspend requested for DT %d\n", id1);

  }else if (!strncmp(buf, "resume", 6 )){
    token = strtok(buf, " \t");
    token = strtok(0, " \t");
    id1 = atoi(token);
    smartSampler->dtResume((short)id1);
    Syslog::write("Resume requested for DT %d\n", id1);

  }else if (!strncmp(buf, "reset", 5 )){
    token = strtok(buf, " \t");
    token = strtok(0, " \t");
    id1 = atoi(token);
    smartSampler->dtReset((short)id1);
    Syslog::write("Reset requested for DT %d\n", id1);

  }else if (!strncmp(buf, "dtstate", 7 )){
    token = strtok(buf, " \t");
    token = strtok(0, " \t");
    if(strlen(token) > 0){
      id1 = atoi(token);
      Syslog::write("Dumping state of DT number %d:",id1);
      smartSampler->dtDumpState(id1);
    }

  }else if (!strncmp(buf, "allocate", 8 )){
    token = strtok(buf, " \t");
    token = strtok(0, " \t");
    id1 = atoi(token);
    if( id1 < 0 || id1 >= NGULPERS ){
      Syslog::write("Illegal gulper number %d\n", id1);
    }else{
      token = strtok(0, " \t");
      id2 = atoi(token);
      smartSampler->gulperAllocate((short)id1,(short)id2);
      Syslog::write("Requested allocation of gulper %d to DT %d\n", id1, id2);
    }

  }else if (!strncmp(buf, "fire", 4 )){
    token = strtok(buf, " \t");
    token = strtok(0, " \t");
    id1 = atoi(token);
    if( id1 < 0 || id1 >= NGULPERS ){
      Syslog::write("Illegal gulper number %d\n", id1);
    }else{
      gulper->fireGulper((long)id1);
      Syslog::write("Fire request for gulper %d\n", id1);
    }

  }else if (!strncmp(buf, "ssfire", 6 )){
    token = strtok(buf, " \t");
    token = strtok(0, " \t");
    id1 = atoi(token);
    if( id1 < 0 || id1 >= NGULPERS ){
      Syslog::write("Illegal gulper number %d\n", id1);
    }else{
      smartSampler->gulperFire(id1);
      Syslog::write("Fire request for gulper %d through SmartSampler direct firing mechanism\n", id1);
    }

  }else if (!strncmp(buf, "last", 4 )){
    short gnum;
    double gt;
    smartSampler->gulperLastFired(&gt,&gnum);
    // Need to fix gulperLastFired!
    Syslog::write("Last gulper fired was number %d at %.2f\n",gnum,gt);

  }else if (!strncmp(buf, "state", 5 )){
    SmartSamplerIF::GulperInfoArrayType gs;
    Syslog::write("Dumping system state:");
    gulper->state(gu_state);
    smartSampler->gulperState(gs);
    for(id1=0; id1<NGULPERS; id1++ )
      {
	switch (gu_state[id1]){
	case GulperIF::Ready:
	  strcpy(obuf1,"Ready");
	  break;
	case GulperIF::Used:
	  strcpy(obuf1,"Used");
	  break;
	default:
	  strcpy(obuf1,"Unknown!");
	  break;
	}
	switch (gs[id1].curstate){
	case SmartSamplerIF::Free:
	  strcpy(obuf2,"Free");
	  break;
	case SmartSamplerIF::Allocated:
	  strcpy(obuf2,"Allocated");
	  break;
	case SmartSamplerIF::Fired:
	  strcpy(obuf2,"Fired");
	  break;
	default:
	  strcpy(obuf2,"Unknown!");
	  break;
	}
	Syslog::write("Gulper%d: gulper state=%s, ss gulper state=%s, DT=%d, time=%.2f.", 
		      id1, obuf1,obuf2,(int)gs[id1].dtid,(double)gs[id1].time);
      }
    Syslog::write("Dumping state of all DT's:");
    smartSampler->dtDumpState();

  }else if ( !strncmp(buf, "q", 1 ) || !strncmp(buf, "Q", 1 ) ){
    return(false);

  }else{
    Syslog::write(" Error: Command unrecognized.\n %s", helpStr);
  }

  return(true);
}



int main(int argc, char **argv)
{
  SmartSamplerIF *smartSampler;
  GulperIF *gulper;

  signal(SIGQUIT, signalHandler);
  signal(SIGSEGV, signalHandler);

  gulperPID = startServer("gulperServer");
  //  clusterPID = startServer("clusterServer");
#ifndef SELF_TEST
  seabirdPID = startServer("simCTD");
  hs2PID = startServer("simHydroscat");
  isusPID = startServer("simIsus");
#endif
  smartSamplerPID = startServer("smartSamplerServer");

  //
  // Now get a handle to the server IF
  //
  try {
    smartSampler = new SmartSamplerIF("SmartSampler");
  }
  catch (Exception e) 
  {
    Syslog::write(
        "smartSamplerTest -- Caught exception on creation of SmartSamplerIF:%s\n",
		  e.msg);
    exit( -1 );
  }

  //
  // Now get a handle to the Gulper IF
  //
  try {
    gulper = new GulperIF("Gulper");
  }
  catch (Exception e) 
    {
      Syslog::write("smartSamplerTest -- Caught exception on creation of GulperIF:%s\n",
		    e.msg);
      exit( -1 );
    }

  while (handle_one_command(smartSampler,gulper)){}

  // Just wait for termination signal
  signalHandler(0);
  return 0;
}

