// C++ code Copyright (C) David R. Evans G4AMJ/NQ0I

#include <sm_batch_mode.h>

batch_mode* bmode;

// batch mode
batch_mode::batch_mode(const char* filename, const float rev) : file(0)
{ Version = rev;

// check that the file exists
  { FILE* fp = fopen(filename, "r");
    if (!(fp)) then
      fatal_error((DREstring)filename + " does not exist");
    fclose(fp);
  }

  heap_check(file = new ifstream);
  file->open(filename, ios::in);
  if (!(file->good())) then
    fatal_error(DREstring("Cannot open file: ") +  filename);

// The following must be called from the constructor of the derived
// class
//  _generate_command_list();
//  _initialise();
}

// default constructor used by vga constructor
batch_mode::batch_mode(void) : file(0)
{ // _initialise(); 
}

batch_mode::~batch_mode(void)
{ destroy(file); }

/*
void batch_mode::_generate_command_list(void)
{ // generate the list of known commands;
  known_commands += "!";
  dispatch_functions += &batch_mode::_batch_file_comment;

//  known_commands += "CALIBRATE";
//  dispatch_functions += &batch_mode::_calibrate;
  
  known_commands += "COMMENT";
  dispatch_functions += &batch_mode::_comment;

  known_commands += "ECHO";
  dispatch_functions += &batch_mode::_echo;

  known_commands += "INFILETYPE";
  dispatch_functions += &batch_mode::_infiletype;
 
// _open is overloaded, so we need the following trick
//  typedef int (batch_mode::*PMFSS)(DREstring&, DREstring&);

  known_commands += "OPEN";
  dispatch_functions += &batch_mode::_Open;

  known_commands += "PLOT";
  dispatch_functions += &batch_mode::_plot;
  
  known_commands += "PLOTMODE";
  dispatch_functions += &batch_mode::_plotmode;
  
  known_commands += "VERSION";
  dispatch_functions += &batch_mode::_version;

  known_commands += "EXIT";
  dispatch_functions += &batch_mode::_exit;
  
  known_commands += "SHOW";
  dispatch_functions += &batch_mode::_show;
  
  known_commands += "PLOTALL";
  dispatch_functions += &batch_mode::_plotall;  

  known_commands += "SET";
  dispatch_functions += &batch_mode::_set;

  known_commands += "VERBOSE";
  dispatch_functions += &batch_mode::_verbose_toggle;
 
  known_commands += "FIRST"; 
  dispatch_functions += &batch_mode::_first;
  
  known_commands += "NEXT";
  dispatch_functions += &batch_mode::_next;
}  */
  
// initialise things; this function is called from derived class
// constructors
void batch_mode::_initialise(void)
{ echo = false;
  _verbose = false;
//  if (Hardcopy_device) then
//    Pad = Hardcopy_device;
//  else
//    Pad = Screen_device;
  Duration = 61;
}

void batch_mode::_invalid_parameter(DREstring& c, DREstring& p)
{ error((DREstring)"invalid parameter `" + p +
        (DREstring)"' to command `" + c + (DREstring)"'");
}

// ! command
int batch_mode::_batch_file_comment(DREstring&, DREstring&)
{ return 0; }

// COMMENT command
int batch_mode::_comment(DREstring&, DREstring& p)
{ Comment = p;
  return 0;
} 

// ECHO command
int batch_mode::_echo(DREstring& c, DREstring& p)
{ glist valid_parms;

  valid_parms += "ON";
  valid_parms += "OFF";

  if (!p.length()) then
    p = "ON";
  p.toupper();
  switch (valid_string(p, valid_parms))
  { case 0 : _invalid_parameter(c, p);
    case 1 : echo = true;
             break;
    case 2 : echo = false;
             break;
  }
  return 0;
}

// EXIT command
int batch_mode::_exit(DREstring&, DREstring&)
{ exit(0);
  return 0;
}

// FIRST command
int batch_mode::_first(DREstring&, DREstring&)
{ operating_mode::first();
  return 0;
}

// INFILETYPE command
int batch_mode::_infiletype(DREstring& c, DREstring& p)
{ glist valid_parms;

  valid_parms += "JPL_PHIEX";
  valid_parms += "PDS_PHIEX";
  valid_parms += "FIXED";
  valid_parms += "VARIABLE";
  valid_parms += "BROWSE";
  valid_parms += "BBROWSE";

  p.toupper();
  switch (valid_string(p, valid_parms))
  { case 0 : _invalid_parameter(c, p);
    case 1 : File_type = jpl_phiex;
             break;
    case 2 : File_type = pds_phiex;
             break;
    case 3 : File_type = fixed;
             break;
    case 4 : File_type = variable;
             break;
    case 5 : File_type = pds_browse;
             Current_sc_mode = browse;
             break;
    case 6 : File_type = pds_bbrowse;
             Current_sc_mode = browse;
             break;
  }
  return 0;
}

// NEXT command
int batch_mode::_next(DREstring&, DREstring&)
{ next();
  return 0;
}

// OPEN command
int batch_mode::_Open(DREstring&, DREstring& p)
{ _open(p);
  return 0;
}

// PLOT command
int batch_mode::_plot(DREstring&, DREstring& p)
{ if (_file_not_open()) then
    return -1;

  switch (Tplotmode)
  { case GS2_LOW_RES : _plot_full_frame(); break;
    case UNBINNED_SPECTRUM :
    case RAWPLOT :
// read the start plot time
      int tyear, tday, thour, tmin;
      const int n_params = sscanf((char*)(const char*)p, "%d %d %d %d",
                                                   &tyear,
                                                   &tday,
                                                   &thour,
                                                   &tmin);
      if (n_params != 4) then
      { error((DREstring)"incorrect number of parameters ("
             + DREstring10(n_params) + (DREstring)") to PLOT command");
        return -1;
      }

// do the plot
    Start_time = timeclass(tyear, tday - 1, thour, tmin);
    End_time = Start_time + timeclass(0, 0, 0, Duration);
    if (Start_time < 0) then
      End_time = Start_time - 1;

// if we are doing a rawplot, then year is a record_nr
    if (_plot_function == &operating_mode::_rawplot) then
      Start_time = timeclass(_first_after(Start_time));

    if (End_time >= 0) then
      do_plot(Start_time, End_time);
    else
      next();
  }
  return 0;
}

// PLOTMODE command
int batch_mode::_plotmode(DREstring& c, DREstring& p)
{ glist valid_parms;

  valid_parms += "GS2LOW";

  p.toupper();
  switch (valid_string(p, valid_parms))
  { case 0 : _invalid_parameter(c, p);
    case 1 : Tplotmode = GS2_LOW_RES;
             break;
  }
  return 0;
}

// PLOTALL command
int batch_mode::_plotall(DREstring&, DREstring&)
{ plotall();
  return 0;
}

// PRINT command
int batch_mode::_print(DREstring&, DREstring&)
{ operating_mode::_print(); 
  return 0;
}

/*
// SET command
int batch_mode::_set(DREstring& c, DREstring& p)
{ enum {QUERY = 1, DURATION, SCMODE, PRAMODE, STARTCHANNEL, ENDCHANNEL,
        PLOTMODE, FILETYPE, DISPLAY, PRINTER};

  glist valid_parms;

  valid_parms += "?";			// must be first
  valid_parms += "DURATION";
  valid_parms += "SCMODE";
  valid_parms += "PRAMODE";
  valid_parms += "STARTCHANNEL";
  valid_parms += "ENDCHANNEL";
  valid_parms += "PLOTMODE";
  valid_parms += "FILETYPE";
  valid_parms += "DISPLAY";
  valid_parms += "PRINTER";

  int subcommand_number;
  DREstring subcommand;
  const int space_position = find(p, " ");

  if (space_position) then
    subcommand = subDREstring(p, 1, space_position - 1).toupper();
  else
    subcommand = p.toupper();
  if (!(subcommand_number = valid_string(subcommand, valid_parms))) then
    error((DREstring)"in _set(DREstring&, DREstring&) : command " + c +
          (DREstring)" " + p + (DREstring)" unknown");

  switch (subcommand_number)
  { case QUERY :
             { DREstring command_list;
               for (int n = 2; n <= valid_parms.length(); n++)
               { command_list += (DREstring)(char*)valid_parms[n];
                 command_list += "\r\n";
               }
               error((DREstring)"\r\nvalid subcommands are: \r\n" + command_list);
               break;
             }
    case DURATION :
             Duration = atoi(subDREstring(p, space_position + 1));
             verbose((DREstring)"Plot duration now " + DREstring(Duration, 10));
             break;
    case SCMODE :
             _set_scmode(subDREstring(p, space_position + 1));
             break;
    case PRAMODE :
             _set_pramode(subDREstring(p, space_position + 1));
             break;
    case STARTCHANNEL :
             Start_channel = atoi(subDREstring(p, space_position + 1));
             verbose((DREstring)"Start channel now " + DREstring(Start_channel, 10));
             break;
    case ENDCHANNEL :
             End_channel = atoi(subDREstring(p, space_position + 1));
             verbose((DREstring)"End channel now " + DREstring(End_channel, 10));
             break;
    case PLOTMODE :
             _set_plotmode(subDREstring(p, space_position + 1));
             break;
    case FILETYPE :
             _infiletype((DREstring)"SET FILETYPE",
                         subDREstring(p, space_position + 1));
             break;
    case DISPLAY :
             _set_display(subDREstring(p, space_position + 1));
             break;
    case PRINTER :
             _set_printer(subDREstring(p, space_position + 1));
             break;

  }
  return 0;
} */

// SHOW command
int batch_mode::_show(DREstring& c, DREstring& p)
{ glist valid_parms;

  valid_parms += "SCMODES";
  valid_parms += "TIMES";
  valid_parms += "PRAMODES";
  valid_parms += "SCMODE";
  valid_parms += "PRAMODE";
  valid_parms += "DURATION";

  p.toupper();
  switch (valid_string(p, valid_parms))
  { case 0 : _invalid_parameter(c, p);
    case 1 : _show_sc_modes();
             break;
    case 2 : _show_range();
             break;
    case 3 : _show_pra_modes();
             break;
    case 4 : _show_sc_mode();
             break;
    case 5 : display_status((DREstring)"Current PRAMODE is : " +
                  _pra_mode_name[Current_pra_mode]);
             break;
    case 6 : display_status((DREstring)"Duration is : " + DREstring10(Duration));
             break;
  }
  return 0;
}

// VERBOSE command
int batch_mode::_verbose_toggle(DREstring& c, DREstring& p)
{ glist valid_parms;

  valid_parms += "ON";
  valid_parms += "OFF";

  if (!p.length()) then
    p = "ON";
  p.toupper();
  switch (valid_string(p, valid_parms))
  { case 0 : _invalid_parameter(c, p); 
    case 1 : _verbose = true; break;
    case 2 : _verbose = false; break;
  } 
  return 0;
}

// VERSION command
int batch_mode::_version(DREstring&, DREstring&)
{ display_status((DREstring)"MIDAS version : " + DREstring(Version, 5.2));
  return 1;
}

// read the file
void batch_mode::_parse_command_line(void)
{// istream& input = *file;
//  while ((input >> command_line).good())

// get the command word
//  {
//  if (!command_line.length()) then
//      return;

    const int space_position = find(command_line, " ");
//    DREstring command;
    int command_number;

    if (echo) then
      echo_command(command_line);

    if (space_position) then
      _current_command = subDREstring(command_line, 1,
                                      space_position - 1).toupper();
    else
      _current_command = command_line.toupper();

    if (!(command_number = valid_string(_current_command,
                                        known_commands))) then
      fatal_error((DREstring)"Unknown command: " + _current_command);

// execute the command, passing the remainder of the command line
//    DREstring parameters;
    if (space_position) then
      _current_parameters = subDREstring(command_line,
                                         space_position + 1);

//    typedef int (batch_mode::*PMFSS)(DREstring&, DREstring&);
    _current_dispatch_function = dispatch_functions[command_number];

//    (this->*_dispatch_function)(command, parameters);
//  }
}

int batch_mode::valid_string(DREstring& test, glist& possible)
{ int rv = 0;
  for (int n = 1; (n <= possible.length() && !rv); n++)
    rv = (test == (DREstring)(char*)possible[n]);
  if (rv) then 
    rv = n - 1;
  return rv;
}

/*
int batch_mode::valid_string(DREstring& test, list<DREstring>& possible)
{ int rv = 0;
  cout << "Testing DREstring validity of : " << test << "\n";
  cout << possible.length() << "\n";
  for (int k = 1; k <= possible.length(); k++)
  cout << possible[k] << "\n";
  
  for (int n = 1; (n <= possible.length() && !rv); n++)
  { cout << test << "|" << possible[n] << "|" << (test == possible[n]) << "\n";
    rv = (test == possible[n]);
  }
  if (rv) then
    rv = n - 1;
  return rv;
} */

void batch_mode::display_status(DREstring& msg)
{ cout << "Status : " << msg << "\n"; }

/*
void batch_mode::error(DREstring message)
{ cerr << message << "\n";
  exit(-2);
}

void batch_mode::_set_display(DREstring& display_type)
{ glist valid_parms;
  
#if defined(LASERJET) || defined(LASERWRITER)
  valid_parms += "PRINTER";
#endif 
#ifdef LASERJET
  valid_parms += "PCLFILE";
#endif
#ifdef LASERWRITER
  valid_parms += "PSFILE";
#endif
  
  enum { INVALID = 0,
#if defined(LASERJET) || defined(LASERWRITER)
         DISPLAY_PRINTER,
#endif
#ifdef LASERJET
         DISPLAY_PCLFILE,
#endif
#ifdef LASERWRITER
         DISPLAY_PSFILE,
#endif
       };

  display_type.toupper();
  switch(valid_string(display_type, valid_parms))
  { case INVALID : error((DREstring)"invalid display type : " + display_type);
#if defined(LASERJET) || defined(LASERWRITER)
    case DISPLAY_PRINTER : Pad = Hardcopy_device; To_file = false; break;
#endif
#ifdef LASERWRITER
    case DISPLAY_PSFILE : Pad = Hardcopy_device; To_file = true; break;
#endif
#ifdef LASERJET
    case DISPLAY_PCLFILE : Pad = Hardcopy_device; To_file = false; break;
#endif
  }
}

void batch_mode::_set_printer(DREstring& printer_type)
{ glist valid_parms;

#ifdef LASERJET
  valid_parms += "PCL";
#endif
#ifdef LASERWRITER
  valid_parms += "PS";
#endif
  valid_parms += "NONE";	// always valid, must be last

  enum { INVALID = 0,
#ifdef LASERJET
         PRINTER_PCL,
#endif
#ifdef LASERWRITER
         PRINTER_PS,
#endif
         PRINTER_NONE
       };

  printer_type.toupper();
  switch(valid_string(printer_type, valid_parms))
  { case INVALID : error((DREstring)"Invalid printer type : " + printer_type);
                   exit(-2);
#ifdef LASERJET
    case PRINTER_PCL : 
             break;
#endif
#ifdef LASWERWRITER
    case PRINTER_PS :
             break;
#endif
    case PRINTER_NONE :
             break;

  }


} */

void batch_mode::_set_scmode(DREstring& mode)
{ glist valid_parms;
  
  for (int i = 0; i <= 31; i++)
    valid_parms += (void*)(_sc_mode_name[i]);

  mode.toupper();
  int mode_nr;
  switch (mode_nr = valid_string(mode, valid_parms))
  { case 0 : fatal_error("Invaid scmode");
    default: Current_sc_mode = mode_nr - 1;
             verbose((DREstring)"Spacecraft mode now " + 
                     (DREstring)_sc_mode_name[Current_sc_mode]);
  }  
}

void batch_mode::_set_pramode(DREstring& mode)
{ glist valid_parms;
  
  for (int i = 0; i <= 6; i++)
    valid_parms += (void*)_pra_mode_name[i];

  mode.toupper();
  int mode_nr;
  switch (mode_nr = valid_string(mode, valid_parms))
  { case 0 : fatal_error("Invalid pramode");
    default: Current_pra_mode = mode_nr - 1;
             verbose((DREstring)"PRA mode now " + 
                     (DREstring)_pra_mode_name[Current_pra_mode]);
  }  
}

void batch_mode::_set_plotmode(DREstring& mode)
{ glist valid_parms;

  valid_parms += "RAWPLOT";
  valid_parms += "SPECTRUM";
  valid_parms += "GS2_LOW_RES";

  mode.toupper();
  switch (valid_string(mode, valid_parms))
  { case 0 : fatal_error((DREstring)"Invalid mode : " + mode);
    case 1 : Tplotmode = RAWPLOT;
             verbose((DREstring)"Tplotmode now " + DREstring10(Tplotmode) +
             (DREstring)"; RAWPLOT");
             _plot_function = &operating_mode::_rawplot;
             break;
    case 2 : Tplotmode = UNBINNED_SPECTRUM;
             verbose((DREstring)"Tplotmode now " + DREstring10(Tplotmode) +
             (DREstring)"; SPECTRUM");
             _plot_function = &operating_mode::display_spectral;
             break;
    case 3 : Tplotmode = GS2_LOW_RES;
             verbose((DREstring)"Tplotmode now " + DREstring10(Tplotmode) +
             (DREstring)"; GS2_LOW_RES");
             break;
  }
}

void batch_mode::_show_range(void)
{ if (!Edr_f) then
    fatal_error("No file open");
  else 
    display_status((DREstring)"TIME RANGE : " + _time_range_string());
}

void batch_mode::_show_sc_modes(void)
{ if (!Edr_f) then
    fatal_error("No file open");
  else
    display_status(_sc_modes_string());
}

void batch_mode::_show_pra_modes(void)
{ if (!Edr_f) then
    fatal_error("No file open");
  else
    display_status(_pra_modes_string());
}

void batch_mode::_show_sc_mode(void)
{ display_status((DREstring)"Current SCMODE is : " +
                  _sc_mode_name[Current_sc_mode]);
}

