/****************************************************************************/
/* Copyright (c) 2014 MBARI                                                 */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
/* Summary  : Program to help setup the CARL system                         */
/* Filename : _carlTest.cc                                                  */
/* Author   :                                                               */
/* Project  :                                                               */
/* Version  : 1.0                                                           */
/* Created  : 12/12/2016                                                    */
/* Modified :                                                               */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/****************************************************************************/
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <process.h>
#include "CARL_IF.h"
#include "TimeIF.h"
#include "Syslog.h"
#include "System.h"

CARL_IF *carl;

struct Item {
   const char* name;
   char value[8];
   Boolean ok;
   Boolean (*func)(struct Item *i, CARL_IF*);
};

Boolean get_temp(struct Item *i, CARL_IF *c)
{
   float t, h, f, a;
   short l;
   c->get_env_data(&t, &h, &f, &a, &l);
   sprintf(i->value, "%-7.2f", t);
   return True;
}

Boolean get_h2o(struct Item *i, CARL_IF *c)
{
   float t, h, f, a;
   short l;
   c->get_env_data(&t, &h, &f, &a, &l);
   Boolean alarm = l > 0 || h > 30;
   char *h2o = alarm ? "no" : "OK!";
   sprintf(i->value, "%s", h2o);
   //printf("H2O is %s\n", i->value);

   return !alarm;
}

Boolean get_cam(struct Item *i, CARL_IF *c)
{
   Boolean on = c->is_camera_on();
   char *cam = on ? "OK!" : "no";
   sprintf(i->value, "%s", cam);
   //printf("CAM is %s\n", i->value);
   return on;
}

Boolean get_aja(struct Item *i, CARL_IF *c)
{
   Boolean on = c->aja_ready();
   char *aja = on ? "OK!" : "no";
   sprintf(i->value, "%s", aja);
   //printf("AJA is %s\n", i->value);
   return on;
}

Boolean get_ctd(struct Item *i, CARL_IF *c)
{
   Boolean on = c->is_ctd_on();
   char *ctd = on ? "OK!" : "no";
   sprintf(i->value, "%s", ctd);
   //printf("CTD is %s\n", i->value);
   return on;
}

Boolean get_lights(struct Item *i, CARL_IF *c)
{
   if (!i->ok)
   {
      short l = c->are_lights_on();
      i->ok = l % 100 > 0;
      char *lights = i->ok ? "OK!" : "no";
      sprintf(i->value, "%s", lights);
      //printf("Lights are %s\n", i->value);
   }
   return i->ok;
}

Boolean get_levels(struct Item *i, CARL_IF *c)
{
   if (!i->ok)
   {
      short l = c->are_lights_on();
      i->ok = l / 100 > 0;
      char *levels = i->ok ? "OK!" : "no";
      sprintf(i->value, "%s", levels);
      //printf("Levels are %s\n", i->value);
   }
   return i->ok;
}

Boolean get_media(struct Item *i, CARL_IF *c)
{
   if (!i->ok)
   {
      short m;
      c->available_media(&m);
      i->ok = m > 90;
      char *media = i->ok ? "OK!" : "no";
      sprintf(i->value, "%s", media);
      //printf("media are %s\n", i->value);
   }
   return i->ok;
}

Boolean get_iris(struct Item *i, CARL_IF *c)
{
   if (!i->ok)
   {
      char *iris = (i->ok = c->motor_action()) ? "OK!" : "no";
      sprintf(i->value, "%s", iris);
      //printf("Iris is %s\n", i->value);
   }
   return i->ok;
}

struct Item results[] = {
   {"Temp",   "", False, get_temp},
   {"H2O",    "", False, get_h2o},
   {"Cam",    "", False, get_cam},
   {"AJA",    "", False, get_aja},
   {"CTD",    "", False, get_ctd},
   {"Lights", "", False, get_lights},
   {"Levels", "", False, get_levels},
   {"Media",  "", False, get_media},
   {"Iris",   "", False, get_iris},
   {"Record", "no", False, NULL}
};

void banner();
int start_CARL();

Boolean progress()
{
   Boolean thumbs_up = True;
   int i, n_items = sizeof(results)/sizeof(struct Item);

   printf("\n\n\t=====================================================================================================\n");
   printf("\t");
   for (i = 0; i < n_items; i++)
   {
      printf("| %-7s", results[i].name);
   }
   printf("|\n\t");
   
   for (i = 0; i < n_items; i++)
   {
      if (results[i].func)
      {
         Boolean r = (*results[i].func)(results+i, carl);
         thumbs_up = thumbs_up && r;
      }

      printf("| %-7s", results[i].value);
   }
   printf("|\n\t=====================================================================================================\n");
   return thumbs_up;
}

int main( int argc, char **argv )
{

   // First, let's kick-off the CARL server which in turn starts the
   // KiPro and Modtronix driver
   //
   int pid_c;
   if ( (0 > ( pid_c = start_CARL() )) )
      return(pid_c);
   else
      printf("carlServer: %d\n", pid_c);



   // Connect to the server
   //
   int error = 1;

   try {
      carl = new CARL_IF("CARLServer");
      error = 0;
   }
   catch (Exception e) {
      fprintf(stderr, "Caught exception: %s\n", e.msg);
   }
   catch (...) {
      fprintf(stderr, "Caught some exception...\n");
   }

   if (error)
    return error;

   sleep(5);

   // Banner and initial results
   // 
   banner();
   progress();
   sleep(2);

   // Turn on camera bus and recorder
   // 
   printf("\nPower to camera and recorder -- Recorder normally takes about 40 seconds to boot up\n");
   carl->camera_bus_on();
   carl->recorder_on();
   sleep(5);
   progress();

   // Check lights
   // 
   printf("\nCheck light switches -- Have someone see if the lights are on\n");
   carl->camera_lights_on();
   carl->light_level(10);
   progress();
   sleep(5);
   progress();

   carl->camera_lights_off();
   
   // Turn on ctd
   // 
   printf("\nPower to ctd...\n");
   carl->ctd_on();
   sleep(5);
   progress();

   // Home the iris
   // 
   printf("\nHome the iris...\n");
   carl->iris_control(CARL_IF::Home, 0);
   sleep(3);
   progress();
   sleep(10);
   progress();

   // Move the iris
   // 
   printf("\nMove the iris...\n");
   carl->iris_control(CARL_IF::FStop, 561);
   sleep(5);
   progress();
   sleep(12);
   progress();

   sleep(10);
   printf("\nRecorder should be up by now...\n");
   progress();

   while (!carl->aja_ready())
   {
      sleep(2);
      printf("\nRecorder not responding...\n");
   }
   progress();

   sleep(5);
   carl->set_clipname("");
   carl->start_recording();
   sleep(3);
   Boolean good_2_go = carl->is_recording();
   carl->stop_recording();
   if (good_2_go) sprintf(results[9].value, "OK!");

   printf("\nSyncing recorder clock...\n");
   carl->sync_time();
   sleep(15);
   // Are we good to go?
   // 
   sleep(5);
   progress();
   sleep(2);

   for (int i = 0; i < 10; i++)
   {
      if (good_2_go && progress())
         printf("\nCARL is good to go!\n");
      else
         printf("\nCARL still has some issues\n");
   sleep(2);
   }

   sleep(15);

   printf("\nDone!\n");

   kill(pid_c, SIGTERM);
   exit(0);

//   carl->sync_time();
//   carl->data_mode();
   carl->record_mode();

   Syslog::write("OK, LEAVING!!!\n");
   // Signal all children
   kill(0, SIGTERM);

   return 0;
}

void banner()
{
  printf("==================================================\n");
  printf("=====            CARL Setup Program          =====\n");
  printf("==================================================\n");
}

int start_CARL()
{
   printf("\tStarting CARLServer...\n");

   char *program = "carlServer";

   char errorBuf[256];
   char buf[256];
 
   pid_t pid;
 
   switch ((pid = fork())) {
     
   case 0:
      // In child
      // Execute driver program
      execlp(program, program, (char *)0);

      sprintf(errorBuf, 
         "Task::spawnServer() - exec() of \"%s\" failed", program);

      perror(errorBuf);
 
      break;

   case -1:
      perror("Task::spawnServer() - fork() failed");
      return -1;
   }

   return pid;
}

