/****************************************************************************/
/* Copyright (c) 2014 MBARI                                                 */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
/* Summary  : Menu-driven deck test program for the CARL system             */
/* Filename : _carlTest.cc                                                  */
/* Author   :                                                               */
/* Project  :                                                               */
/* Version  : 1.0                                                           */
/* Created  : 04/07/2015                                                    */
/* 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"

enum CARL_CMDS {
  EXIT = 0,
  LIGHTS_ON,
  LIGHTS_OFF,
  LIGHTS_CHECK,
  CTD_ON,
  CTD_OFF,
  CTD_CHECK,
  RECORD_MODE,
  DATA_MODE,
  MODE_CHECK,
  TIME_SYNC,
  GET_TC,   
  RECORD,   
  STOP,
  STOP_CHECK,       
  AVAIL_MEDIA,
  CLIPNAME,   
  RECORDER_ON,
  RECORDER_OFF,
  RECORDER_CHECK,
  CAMERA_ON,   
  CAMERA_OFF,
  CAMERA_CHECK,  
  LIGHT_LEVEL,
  EZHOME,
  EZAUTOFS,
  EZFSTOP,
  EZHALT,
  ENVDATA
};


struct cmd_s
{
  char *name;
  char code;
};

static struct cmd_s cmds[] = {
  {"Exit (No, really. It works now.)", EXIT},                 {"Camera on", CAMERA_ON},           \
  {"Camera off", CAMERA_OFF},     {"Camera Check", CAMERA_CHECK},     \
  {"Recorder on", RECORDER_ON},   {"Recorder off", RECORDER_OFF},     \
  {"Recorder Check", RECORDER_CHECK},   {"Lights on", LIGHTS_ON},     \
  {"Lights off", LIGHTS_OFF},     {"Lights Check", LIGHTS_CHECK},     \
  {"Light levels", LIGHT_LEVEL},  {"CTD on", CTD_ON},                 \
  {"CTD off", CTD_OFF},           {"CTD Check", CTD_CHECK},           \
  {"Record Mode", RECORD_MODE},   {"Data Mode", DATA_MODE},           \
  {"Mode Check", MODE_CHECK},     {"Time Sync", TIME_SYNC},           \
  {"Get Timecode", GET_TC},       {"Start Recording", RECORD},        \
  {"Stop Recording", STOP},       {"Stop Check", STOP_CHECK},         \
  {"Available Media", AVAIL_MEDIA},{"Set the Clip Name", CLIPNAME},   \
  {"Home the Iris", EZHOME},      {"Set Iris to an FStop", EZFSTOP},  \
  {"Auto Iris", EZAUTOFS},    {"Get Env Data", ENVDATA}
};

void banner();
int menu_choice(char menu = 0);
int start_CARL();

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
   //
   CARL_IF *carl;
   int error = 0;

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

   if (error)
    return error;

   printf("CARL Server initializing. Please hold...\n");
   sleep(5);

   banner();
   int menu = 1;
   int cmd = menu_choice(menu);
   // Run the menu-loop until exit requested
   //
   int keep_going = 1;
   while (keep_going)
   {
      int ans;
      short int am = 92;
      short int level, alarm;
      float tc = 54000.2387543;
      CARL_IF::Clipname clipname;
      CARL_IF::Status carl_status;
      float temp, humidity, fwd, aft;

      menu = 0;
      switch (cmd)
      {
         case EXIT:
            printf("\nExiting...\n\n");
            kill(pid_c, SIGKILL);
            return 0;
            break;

         case CAMERA_ON:
            printf("| Camera on...   \n");
            carl->camera_bus_on();
            break;

         case CAMERA_OFF:
            printf("| Camera off...   \n");
            carl->camera_bus_off();
            break;

         case CAMERA_CHECK:
            ans = 0;
            if (carl->is_camera_on()) ans = 1;
            printf("\n| Camera check...   %d\n\n", ans);
            break;

         case RECORDER_ON:
            printf("| Recorder on...   \n");
            carl->recorder_on();
            break;

         case RECORDER_OFF:
            printf("| Recorder off...   \n");
            carl->recorder_off();
            break;

         case RECORDER_CHECK:
            ans = carl->aja_ready() ? 1 : 0;
            printf("\n| Recorder check...   %d\n\n", ans);
            break;

         case LIGHTS_ON:
            printf("| Lights on...   \n");
            carl->camera_lights_on();
            break;

         case LIGHTS_OFF:
            printf("| Lights off...   \n");
            carl->camera_lights_off();
            break;

         case LIGHTS_CHECK:
            ans = carl->are_lights_on();
            printf("| Lights check...%d   \n", ans);
            break;

         case LIGHT_LEVEL:
            printf("| Set Light level...   \n");
            printf("|\n| Enter a level (from 0 to 100) > " );
            gets(clipname);
            printf("%s\n", clipname);
            level = atoi(clipname);
            if (level >= 0 && level <= 100)
               carl->light_level(level);
            else
            printf("|\n| Invalid level: %d\n ", level );
            
            break;

         case CTD_ON:
            printf("| CTD on...   \n");
            carl->ctd_on();
            break;

         case CTD_OFF:
            printf("| CTD off...   \n");
            carl->ctd_off();
            break;

         case CTD_CHECK:
            ans = carl->is_ctd_on();
            printf("\n| CTD check...   %d\n", ans);
            break;

         case RECORD_MODE:
            printf("| Ki Pro to Record Mode... \n");
            carl->record_mode();
            break;

         case DATA_MODE:
            printf("| Ki Pro to Data Mode...   \n");
            carl->data_mode();
            break;

         case MODE_CHECK:
            printf("| Mode check...   \n");
            break;

         case TIME_SYNC:
            printf("| Sync MVC time with Ki Pro...   \n");
            carl->sync_time();
            break;

         case GET_TC:
            printf("| Getting Ki Pro Timecode...   \n");
            carl->get_timecode(&tc);
            printf("| Timecode: %.3f   \n", tc);
            break;

         case RECORD:
            printf("| Recording...   \n");
            carl->start_recording();
            break;

         case CLIPNAME:
            printf("| Set Clip Name...   \n");
            printf("|\n| Enter a name (no name == date & time) > " );
            gets(clipname);
            printf("%s\n", clipname);
            carl->set_clipname(clipname);
            break;

         case STOP:
            printf("| Stopping...   \n");
            carl->stop_recording();
            break;

         case STOP_CHECK:
            printf("| Stop check...   \n");
            printf("| Recording? : %d   \n", carl->is_recording());
            break;

         case AVAIL_MEDIA:
            printf("| Getting available media...   \n");
            carl->available_media(&am);
            printf("| Available media: %d   \n", am);
            break;

         case EZHOME:
            printf("| Home the iris motor...   \n");
            carl->iris_control(CARL_IF::Home, 0);
            break;

         case EZAUTOFS:
            printf("| Set Light level...   \n");
            printf("|\n| Enter a level (0, or a value from 1.25 to 3.80) > " );
            gets(clipname);
            printf("%s\n", clipname);
            temp = atof(clipname);
            if (temp >= 0.0 && temp <= 3.8)
               carl->auto_iris(temp);
            else
              printf("|\n| Invalid level: %.2f\n ", temp );
            
            break;

         case EZFSTOP:
            printf("| Set the FStop...   \n");
            printf("|\n| Enter a coded FStop (e.g., 82 for 2nd 8 position) > " );
            gets(clipname);
            printf("%s\n", clipname);
            carl->iris_control(CARL_IF::FStop, atoi(clipname));
            break;

         case ENVDATA:
            printf("| Getting environmental data...   \n");
            carl->get_env_data(&temp, &humidity, &fwd, &aft, &alarm);
            printf("| Temp: %.2f\tHumidity: %.2f\tFwd H2O: %.2f\tAft H2O:%.2f\tH2O Alarm: %.2f\n",
               temp, humidity, fwd, aft, alarm);
            break;

         case -2:
            menu = 1;
            break;

         default:
            printf("| Unrecognized command!    \n|\n");
            break;
      }
      cmd = menu_choice(menu);
   }

   return 0;

   printf("Get recorder time from CARL\n");
   TimeIF::TimeSpec ts;
   carl->recorder_time(&ts);
   printf("Recorder time: seconds = %ld, nano = %ld\n", ts.seconds, ts.nanoSeconds);

   sleep(3);

   printf("Turn lights on\n");
   carl->camera_lights_on();

   sleep(5);

   printf("Turn lights off\n");
   carl->camera_lights_off();
   
   sleep(45);

//   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 Test App\n");
  printf("|\n");
}

int menu_choice(char menu)
{
  // Print the menu if instructed
  // 
  if (menu)
  {
    printf("| Choose from the following: \n");
    for (int jj = 0; jj < sizeof(cmds)/sizeof(struct cmd_s); jj++)
    {
      printf("|  %2d) %s\n", jj+1, cmds[jj].name);
    }
  }
  printf("|\n| Your menu choice > " );

  char response[32];
  char *c = gets(response);

  // Got a response?
  //
  if (strlen(response) > 0)
  {
    int choice = atoi(response);

    // Valid response? Return the code
    // 
    if (choice <= sizeof(cmds)/sizeof(struct cmd_s) && choice > 0)
      return cmds[choice-1].code;
  }
  else
    return -2;

  return -1;
}

int start_CARL()
{
   printf("Starting 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;
}

