// C++ code Copyright (C) David R. Evans G4AMJ/NQ0I

#include <sm_sunview_mode.h>

#include <menu.h>

sunview_mode* imode;

const colour black(0, 0, 0),
	     red(255, 0, 0),
	     green(0, 255, 0),
	     blue(0, 0, 255),
	     yellow(255, 255, 0),
	     magenta(255, 0, 255),
	     cyan(0, 255, 255),
	     white(255, 255, 255);

extern const int LOWEST_CHANNEL_IN_LOW_BAND,
                 MAX_ABOVE_FOREGROUND,
                 MAX_BELOW_BACKGROUND,
                 MAX_SQUARE_SIZE;

extern const int N_TEXT_PANEL_ITEMS;

// a really 'orrible kludge is needed because of the fact the when the
// button notify procs are called, they aren't called with an object.
// There are other ways of handling this (e.g. static functions), but
// all in all the alternatives are even worse

#define RECURSE(function) \
  if (this != imode) \
  { imode->function(); \
    return; \
  } 

// constructor
sunview_mode::sunview_mode(const double rev_nr) :
  midas_icon("/home/evans/C/midas.icon")
{ base_frame.label(centre("MIDAS " + DREstring(rev_nr, 3.2), 70))
            .icon(midas_icon);

// Point the hardcopy device to the laserwriter
  Hardcopy_device = &lw;

// create the panels
    button_panel = new panel(base_frame);
    text_panel = new panel(base_frame);
    sub_button_panel = new panel(base_frame);

    frame_cmap = colourmap(base_frame, "frame_cmap", 2);
    button_panel_cmap = colourmap(*button_panel, "frame_cmap", 2);

    set_colour(frame_cmap, 0, yellow);
    set_colour(frame_cmap, 1, blue);

    text_panel->height(30).y(88);
    sub_button_panel->height(30).y(125);

    Monitor = base_frame;
    Monitor = 7;
    Pad = &Monitor;
    button_panel->width(671);
    _create_panel_items();

    Monitor.cmap(colourmap(Monitor.canv().pixwin(), "canvas_cmap", 8));

// set the colourmap to match the Pascal 8-colour map
  set_colour(Monitor.cmap(), 0, black);
  set_colour(Monitor.cmap(), 1, red);
  set_colour(Monitor.cmap(), 2, green);
  set_colour(Monitor.cmap(), 3, blue);
  set_colour(Monitor.cmap(), 4, yellow);
  set_colour(Monitor.cmap(), 5, magenta);
  set_colour(Monitor.cmap(), 6, cyan);
  set_colour(Monitor.cmap(), 7, white);
 
  sub_button_panel_item[0] = new button(*sub_button_panel,
                                        "BRIGHTNESS",
                                        &sunview_mode::brightness);
  sub_button_panel_item[1] = new button(*sub_button_panel, "SATURATION",
                                        &sunview_mode::saturation);
  sub_button_panel_item[2] = 0;

  button_panel->fit_height();
  base_frame.fit_height().fit_width();
  
  sub_button_panel->paint();
  button_panel->paint();
}

// destructor
sunview_mode::~sunview_mode(void)
{ }

// private functions

void sunview_mode::_change_1(void)
{ RECURSE(_change_1)
  if (!(text_panel->caret_on_item(3))) then
    text_panel->advance_caret();
  else
  { text_panel->advance_caret();
    sscanf(text_panel_item[0]->value(), "%d", &Start_channel);
    sscanf(text_panel_item[1]->value(), "%d", &End_channel);
    sscanf(text_panel_item[2]->value(), "%d", &Duration); 
    _clear_text_panel();
  }
}

void sunview_mode::_change_2(void)
{ RECURSE(_change_2)
  if (!(text_panel->caret_on_item(3))) then
    text_panel->advance_caret();
  else
  { text_panel->advance_caret();
    sscanf(text_panel_item[0]->value(), "%d", &Start_tomplot_channel);
    sscanf(text_panel_item[1]->value(), "%d", &N_tomplot_channels);
    sscanf(text_panel_item[2]->value(), "%d", &Duration);
    if ((Start_tomplot_channel + N_tomplot_channels - 1) > 200) then
      error("Invalid lowest frequency channel"); 
    _clear_text_panel();
  }
}

void sunview_mode::_change_3(void)
{ RECURSE(_change_3)
  if (!(text_panel->caret_on_item(3))) then
    text_panel->advance_caret();
  else
  { text_panel->advance_caret();
    sscanf(text_panel_item[0]->value(), "%d", &High_res_channel);
    sscanf(text_panel_item[1]->value(), "%d", &Gs2_n_data);
    sscanf(text_panel_item[2]->value(), "%d", &Gs2_n_strips); 
    _clear_text_panel();
  }
}

void sunview_mode::_clear_text_panel(void)
{ for (int n = 0; n < N_TEXT_PANEL_ITEMS; n++)
    text_panel_item[n]->clear();
  text_panel->caret_item(1);
}

void sunview_mode::_create_panel_items(void)
{ bin_button = new button(*button_panel, "BIN", &bin);
//  calibrate_button = new button(*button_panel);
//  (*calibrate_button).label_image(panel_button_image(calibrate_button->parent(), "CALIBRATE", 12, 0)).notify_proc(&calibrate);

// A Sunview idiocy forces the need for the next line
  button* dummy = new button(*button_panel);

  comment_button = new button(*button_panel, "COMMENT", &comment);
  change_button = new button(*button_panel, "CHANGE", &change);
  dump_button = new button(*button_panel, "DUMP", &dump);
  first_button = new button(*button_panel, "FIRST", &first);
  ignore_button = new button(*button_panel, "IGNORE", &ignore);
  init_button = new button(*button_panel, "INIT", &initialise);
  invert_button = new button(*button_panel, "INVERT", &invert);
  last_button = new button(*button_panel, "LAST", &last);
  next_button = new button(*button_panel, "NEXT", &next);
  open_button = new button(*button_panel, "OPEN", &open);
  plot_button = new button(*button_panel, "PLOT", &plot);
  plotall_button = new button(*button_panel, "PLOTALL", &plotall);
  plotrmdr_button = new button(*button_panel, "PLOTRMDR", &plotrmdr);
  print_button = new button(*button_panel, "PRINT", &print);
  printer_button = new button(*button_panel, "PRINTER", &printer);
  prior_button = new button(*button_panel, "PRIOR", &prior);
  recall_button = new button(*button_panel, "RECALL", &recall);
  replot_button = new button(*button_panel, "REPLOT", &replot);
  set_button = new button(*button_panel, "SET", &Set);
  show_button = new button(*button_panel, "SHOW", &show);

  delete dummy;

  button_panel->fit_height();

  for (int n = 0; n < N_TEXT_PANEL_ITEMS; n++)
  { text_panel_item[n] = new text_item(*text_panel);
    text_panel_item[n]->label_y(8);
  }
  _text_item_position(0, 200, 400, 600);
}

void sunview_mode::_destroy_sub_button_panel_item(const int n)
{ if (n == N_SUB_BUTTON_PANEL_ITEMS) then
  { for (int n1 = 0; n1 < N_SUB_BUTTON_PANEL_ITEMS; n1++)
    { if (sub_button_panel_item[n1]) then
      { delete sub_button_panel_item[n1];
	sub_button_panel_item[n1] = NULL;
      }
    }
  }
  else
  { if (sub_button_panel_item[n]) then
    { delete sub_button_panel_item[n];
      sub_button_panel_item[n] = NULL;
    }
  }
}

void sunview_mode::_display_in_window(const char* label,
                                          DREstring& msg, const colour fgc,
                                          const colour bgc)
{ frame temp_frame(base_frame);

  colourmap temp_cmap(temp_frame, "temp_cmap", 2);
  set_colour(temp_cmap, 0, bgc);
  set_colour(temp_cmap, 1, fgc);

  static char lbl[42];
  char* lbl_ptr = &(lbl[0]);
  DREstring ls(label);
  DREstring ls40 = left_fill(ls, 40);
  lbl_ptr = ls40;

  temp_frame.label(lbl_ptr).show_label(TRUE)
            .confirm(FALSE).inherit_colours(TRUE).below(*text_panel)
            .height(50);
  panel temp_panel(temp_frame);
  temp_panel.item_event_proc((void*)window_return)
            .background_proc((void*)window_return)
            .grab_all_input(TRUE)
            .consume_pick_event(WIN_NO_EVENTS)
            .consume_pick_event(WIN_MOUSE_BUTTONS);
  message msg_pi(temp_panel, msg);
  window_loop(temp_frame); 
  temp_panel.grab_all_input(FALSE);
}

void sunview_mode::_plot_1(void)
{ RECURSE(_plot_1)
  if (!(text_panel->caret_on_item(4))) then
    text_panel->advance_caret();
  else
  { int temp;
    sscanf(text_panel_item[0]->value(), "%d", &temp);
    Start_time.year(temp);
    sscanf(text_panel_item[1]->value(), "%d", &temp);
    Start_time.day(temp - 1);
    sscanf(text_panel_item[2]->value(), "%d", &temp); 
    Start_time.hour(temp);
    sscanf(text_panel_item[3]->value(), "%d", &temp);
    Start_time.minute(temp);
    Start_time.second(0);
    _clear_text_panel();
    _execute_low_rate_plot_command();
  }
}

void sunview_mode::_plot_2(void)
{ RECURSE(_plot_2)
  if (!(text_panel->caret_on_item(2))) then
    text_panel->advance_caret();
  else
  { int high_res_line, high_res_datum;
    sscanf(text_panel_item[0]->value(), "%d", &high_res_line);
    sscanf(text_panel_item[1]->value(), "%d", &high_res_datum);
    _clear_text_panel();
  
    Current_phiex_position = phiex_position(high_res_line, high_res_datum);
    _plot_gs2_hi_res(Current_phiex_position, Gs2_n_data, Gs2_n_strips);

    _clear_text_panel();
  }
}

void sunview_mode::_pol_contrast(void)
{ Pol_contrast = _temp_slider("Contrast : ", Pol_contrast, 0, 20); }

void sunview_mode::_pol_threshold(void)
{ Pol_intensity_threshold = _temp_slider("threshold : ", Pol_intensity_threshold, 0, 255); }

void sunview_mode::_set_display(event& e)
{ menu set_display;

  set_display.DREstrings("SCREEN", "LASER", "PS FILE", NULL)
             .initial_selection(Pad == Screen_device ? 1 : 2);

  switch (set_display.show(*button_panel, e))
  { case 1 : Pad = Screen_device; To_file = false; break;
    case 2 : Pad = Hardcopy_device; To_file = false; break;
    case 3 : Pad = Hardcopy_device; To_file = true; break;
  }
}

void sunview_mode::_set_file_type(event& e)
{  menu set_menu;

  set_menu.DREstrings("FIXED", "VARIABLE", "JPL_PHIEX", "PDS_PHIEX", 
                      "PDS_BROWSE", "PDS_BBROWSE", "PDS", NULL)
          .initial_selection(File_type + 1);
  switch (set_menu.show(*button_panel, e))
  { case 1 : File_type = fixed; 
             text_panel_item[0]->value("").display_length(10)
                                .label("Record size : ")
                                .notify_proc(&_set_file_type_1);
             text_panel->caret_item(1);
             break;
    case 2 : File_type = variable; 
             break;
    case 3 : File_type = jpl_phiex; 
             break;
    case 4 : File_type = pds_phiex; 
             break;
    case 5 : File_type = pds_browse; 
             /* Current_sc_mode = browse; */ 
             break;
    case 6 : File_type = pds_bbrowse; 
             /* Current_sc_mode = browse; */ 
             break;
    case 7 : File_type = pds; 
             break;
  }
}

void sunview_mode::_set_file_type_1(void)
{ sscanf(text_panel_item[0]->value(), "%d", &File_record_length);
  _clear_text_panel();
}

void sunview_mode::_set_plot_mode(event& e)
{ menu mode;

  mode.DREstrings("Unbinned spectral scans", 
                  "Binned spectral scans",
                  "Raw DN scans", 
                  "Unbinned Tomplots", 
                  "Binned Tomplots",
	          "Low resolution GS-2",
	          "High resolution GS-2", NULL);
  mode.initial_selection(Tplotmode);

  switch (Tplotmode = mode.show(*button_panel, e) - 1)
  { case UNBINNED_SPECTRUM :
    { _plot_function = display_spectral;
      _destroy_sub_button_panel_item();
      sub_button_panel_item[0] = new button(*sub_button_panel, "BRIGHTNESS");
      sub_button_panel_item[0]->notify_proc(&sunview_mode::brightness);
      sub_button_panel_item[1] = new button(*sub_button_panel, "SATURATION");
      sub_button_panel_item[1]->notify_proc(&sunview_mode::saturation);
      break;
    }
    case RAWPLOT:
    { _plot_function = _rawplot;
      _destroy_sub_button_panel_item();
      break;
    }
    case UNBINNED_TOMPLOT:
    case BINNED_TOMPLOT : 
    { _plot_function = _tomplot;
      _destroy_sub_button_panel_item();
      sub_button_panel_item[0] = new button(*sub_button_panel, "RANGE");
      sub_button_panel_item[0]->notify_proc(&_tomplot_range);
      break;
    }
    case GS2_LOW_RES :
    case GS2_HIGH_RES :
    { _destroy_sub_button_panel_item();
      break;
    }
  }
  sub_button_panel->paint();
}

void sunview_mode::_set_pra_mode(event& e)
{ menu set_pra_mode;

  for (int i = 0; i <= 6; i++)
    set_pra_mode.DREstrings(_pra_mode_name[i], NULL);
  set_pra_mode.initial_selection(Current_pra_mode + 1);

  Current_pra_mode = set_pra_mode.show(*button_panel, e) - 1;
}

void sunview_mode::_set_sc_mode(event& e)
{ menu set_sc_mode;

  for (int i = 0; i <= 31; i++)
    set_sc_mode.DREstrings(_sc_mode_name[i], NULL);
  set_sc_mode.initial_selection(Current_sc_mode + 1);

  Current_sc_mode = set_sc_mode.show(*button_panel, e) - 1;
}

void sunview_mode::_show_pra_modes(void)
{ DREstring pra_modes_string;
  int pra_modes_present[8];

  for (int n = 0; n < 8; n++)
    pra_modes_present[n] = 0;

  for (n = 0; n < 16; n++)
    if (Pra_submodes_present[n]) then
      pra_modes_present[_pra_mode_fm_submode(n)]++;

// generate the list DREstring
  for (int i = 0; i <= 6; i++)
    if (pra_modes_present[i]) then 
      pra_modes_string += ((DREstring)_pra_mode_name[i] + " ");

  _display_in_window("PRA-MODES", pra_modes_string, black, white);
}

void sunview_mode::_show_range(void)
{ if (!Edr_f) then
    error("No file open");
  else 
    _display_in_window("TIME RANGE", _time_range_string(), black, white);
}

void sunview_mode::_show_sc_modes(void)
{ _display_in_window("SC-MODES", _sc_modes_string(), black, white); }

int sunview_mode::_temp_slider(DREstring& label,
                                   const int current_value,
                                   const int min_display,
                                   const int max_display)
{ const int EXTRA_SLIDER_WIDTH = 350;

  frame slider_frame(base_frame);
  slider_frame.no_confirm(TRUE).inherit_colours(TRUE).below(*sub_button_panel);
  panel slider_panel(slider_frame);
  slider_panel.consume_pick_event(WIN_MOUSE_BUTTONS);
  slider s(slider_panel);
  s.min_value(min_display).max_value(max_display).width(255)
   .value(current_value).notify_level(PANEL_DONE)
   .notify_proc(&window_return).label_string(label);
  slider_panel.fit_height();
  slider_frame.fit_height();
  slider_frame.width(max_display - min_display + EXTRA_SLIDER_WIDTH);
  slider_panel.paint();
// for some reason, changing colours renders the bar invisible
//  colourmap frame_cmap(slider_frame, "slider_cmap", 2);
//  colourmap slider_cmap(slider_panel, "slider_cmap", 2);
//  set_colour(slider_cmap, 0, colour(150, 100, 0));
//  set_colour(slider_cmap, 1, colour(150, 255, 100));
//  slider_panel.paint();
//  s.paint();
  window_loop((Frame)slider_frame);
  return s.value();
}

void sunview_mode::_text_item_position(const int p0, const int p1,
                                           const int p2, const int p3)
{ if (p0 != -1) then
    text_panel_item[0]->label_x(p0);
  if (p1 != -1) then
    text_panel_item[1]->label_x(p1);
  if (p2 != -1) then
    text_panel_item[2]->label_x(p2);
  if (p3 != -1) then
    text_panel_item[3]->label_x(p3);
}

void sunview_mode::_tomplot_range(void)
{ RECURSE(_tomplot_range)
  _text_item_position(0, 200, 400);
  text_panel_item[0]->label("Channel_number : ").notify_proc(&_tomplot_range_1);
  text_panel_item[1]->label("Low value : ").notify_proc(&_tomplot_range_1);
  text_panel_item[2]->label("High value : ").notify_proc(&_tomplot_range_1);
  text_panel->caret_item(1);
}

void sunview_mode::_tomplot_range_1(void)
{ RECURSE(_tomplot_range_1)
  int channel_nr, n;
  uint16 temp_uint16;

  if (!(text_panel->caret_on_item(3))) then
    text_panel->advance_caret();
  else
  { char* cp0 = text_panel_item[0]->value();
    char* cp1 = text_panel_item[1]->value();
    char* cp2 = text_panel_item[2]->value();

    sscanf(text_panel_item[0]->value(), "%d", &channel_nr);
    Autoscale_tomplot = (channel_nr == -1);
    sscanf(text_panel_item[1]->value(), "%hu", &temp_uint16);
    if (!Autoscale_tomplot) then
    { if (channel_nr) then
        Tomplot_dn_range[channel_nr][0] = temp_uint16;
      else
        for (n = 3; n <= 200; n++)
          Tomplot_dn_range[n][0] = temp_uint16;
      sscanf(text_panel_item[2]->value(), "%hu", &temp_uint16); 
      if (channel_nr) then
        Tomplot_dn_range[channel_nr][1] = temp_uint16;
      else
        for (n = 3; n <= 200; n++)
          Tomplot_dn_range[n][1] = temp_uint16;
    }
    _clear_text_panel();
  }
}

// commands

void sunview_mode::brightness(void)
{ RECURSE(brightness)
  Brightness = _temp_slider("Brightness : ", Brightness, 0, 100);
}

/* void sunview_mode::calibrate(void)
{ RECURSE(calibrate)
  Calibrate = 1 - Calibrate;
  if (Calibrate) then
    (*calibrate_button).label_image(panel_button_image(calibrate_button->parent(), "NOCALIBRATE", 12, 0));
  else
    (*calibrate_button).label_image(panel_button_image(calibrate_button->parent(), "CALIBRATE", 12, 0));
  button_panel->paint();
} */

void sunview_mode::change(void)
{ RECURSE(change)
  switch (Tplotmode)
  { case UNBINNED_SPECTRUM : case BINNED_SPECTRUM :
    { _text_item_position(0, 200, 400);
      text_panel_item[0]->label("Start channel : ").notify_proc(&_change_1);
      text_panel_item[1]->label("End channel : ").notify_proc(&_change_1);
      text_panel_item[2]->label("Duration (min) : ").notify_proc(&_change_1);
      break;
    }
    case UNBINNED_TOMPLOT : case BINNED_TOMPLOT :
    { _text_item_position(0, 200, 400);
      text_panel_item[0]->label("Start channel : ").notify_proc(&_change_2);
      text_panel_item[1]->label("n channels : ").notify_proc(&_change_2);
      text_panel_item[2]->label("Duration(m) : ").notify_proc(&_change_2);
      break;
    }
    case GS2_HIGH_RES :
    { text_panel_item[0]->label("Ch (1/2/3) : ").notify_proc(&_change_3);
      text_panel_item[1]->label("n_points : ").notify_proc(&_change_3);
      text_panel_item[2]->label("n_strips : ").notify_proc(&_change_3);
      break;
    }
  }
  text_panel->caret_item(1);
}

void sunview_mode::comment(void)
{ RECURSE(comment)
  if (!*(text_panel_item[0]->label())) then
    text_panel_item[0]->label(" Comment : ").notify_proc(&comment);
   else
   { Comment = text_panel_item[0]->value();
     _clear_text_panel();
   }
}

void sunview_mode::saturation(void)
{ RECURSE(saturation)
  Saturation = _temp_slider("Saturation : ", Saturation, 0, 100);
}

void sunview_mode::bin(void)
{ RECURSE(bin)
  operating_mode::_bin();
}

void sunview_mode::dump(void)
{ RECURSE(dump)
  if (!*(text_panel_item[0]->label())) then
    text_panel_item[0]->label("Dump file name : ").notify_proc(&dump);
  else
  { Pad->dump(text_panel_item[0]->value());
    _clear_text_panel();
  }
}

void sunview_mode::ignore(void)
{ RECURSE(ignore)
  Low_ignore_value = _temp_slider("Low ignore value : ",
                                  Low_ignore_value, 0, 255);
  High_ignore_value = _temp_slider("High ignore_value : ",
                                   High_ignore_value, 0, 255);
  for (int n = Low_ignore_value; n <= High_ignore_value; n++) 
    Valid_data[n] = false;
} 

void sunview_mode::invert(void)
{ RECURSE(invert)
  Pad->invert();
}

void sunview_mode::open(void)
{ RECURSE(open)
  if (!*(text_panel_item[0]->label())) then
    text_panel_item[0]->label("File : ").notify_proc(&sunview_mode::open);
  else
  { DREstring file_name = text_panel_item[0]->value();
    operating_mode::_open(file_name);
    _clear_text_panel();
  }
}

void sunview_mode::plot(void)
{ RECURSE(plot)
  switch (Tplotmode)
  { case GS2_LOW_RES : _plot_full_frame(); break;
    case GS2_HIGH_RES : 
    { text_panel_item[0]->label("Line : ").notify_proc(&_plot_2);
      text_panel_item[1]->label("Datum : ").notify_proc(&_plot_2);
      text_panel->caret_item(1);
      break;
    }
  };
  if (Tplotmode < GS2_LOW_RES) then
  { _text_item_position(0, 150, 300, 450);
    text_panel_item[0]->label("Year : ").notify_proc(&_plot_1);
    text_panel_item[1]->label("Day : ").notify_proc(&_plot_1);
    text_panel_item[2]->label("Hour : ").notify_proc(&_plot_1);
    text_panel_item[3]->label("Minute : ").notify_proc(&_plot_1);
    text_panel->caret_item(1);
  }
}

void sunview_mode::printer(void)
{ RECURSE(printer)
  if (!*(text_panel_item[0]->label())) then
    text_panel_item[0]->label("Printer name : ").notify_proc(&sunview_mode::printer);
  else
  { Printer_name = text_panel_item[0]->value();
    _clear_text_panel();
  }
}

void sunview_mode::recall(void)
{ RECURSE(recall)
  Low_recall_value = _temp_slider("Low recall value : ", Low_recall_value, 0, 255);
  High_recall_value = _temp_slider("High recall_value : ", High_recall_value, 0,
                             255);
  for (int n = Low_recall_value; n <= High_recall_value; n++) 
    Valid_data[n] = true;
} 

void sunview_mode::Set(void)
{ RECURSE(Set)
  menu set_menu;
  set_menu.DREstrings("PLOTMODE", "DISPLAY", "SCMODE", "PRAMODE", "FILE TYPE", NULL).initial_selection(MENU_DEFAULT);

  event e;
  switch (set_menu.show(*button_panel, e.code(MS_LEFT).x(set_button->x()).y(set_button->y())))
  { case 1 : _set_plot_mode(e); break;
    case 2 : _set_display(e); break;
    case 3 : _set_sc_mode(e); break;
    case 4 : _set_pra_mode(e); break;
    case 5 : _set_file_type(e); break;
  }
}

void sunview_mode::show(void)
{ RECURSE(show)
  menu show;

  show.DREstrings("SC MODES", "PRA MODES", "TIME RANGE", NULL);
  event e;
  switch (show.show(*button_panel, e.code(MS_LEFT).x(show_button->x()).y(show_button->y())))
  { case 1 : _show_sc_modes(); break;
    case 2 : _show_pra_modes(); break;
    case 3 : _show_range(); break;
  }
}

// non-command functions
void sunview_mode::display_status(DREstring& msg)
{ text_panel_item[0]->label_string(msg).paint(); 
}
 
void sunview_mode::error(DREstring message)
{ _display_in_window("ERROR", message, colour(255, 100, 150), white);
  _clear_text_panel();
}

