// C++ code Copyright (C) David R. Evans G4AMJ/NQ0I

// base class for interaction modes of MIDAS

#ifndef SMMODEH
#define SMMODEH

#include <config.h>

#include <t_array.h>

#include <binned_edr.h>
#include <data.h>
#include <gmdr.h>
#include <high_rate.h>
#include <set.h>
#include <surface.h>
#include <timeclass.h>

class operating_mode;

extern operating_mode* mode;

const int N_PLOT_MODES = 11;

enum { UNBINNED_SPECTRUM = 0,
		 BINNED_SPECTRUM,
		 RAWPLOT,
		 UNBINNED_TOMPLOT,
		 BINNED_TOMPLOT,
		 GS2_LOW_RES,
		 GS2_HIGH_RES };

const int MAX_SQUARE_SIZE = 256;

const timeclass one_day(0, 1, 0, 0, 0),
                one_minute(0, 0, 0, 1);

union timeint
{ timeclass* t;
  int i;
  timeint(timeclass& T) { t = &T; }
  timeint(int I) { i = I; }
};

// The following is necessary because compilers disagree on whether
// explicit scope qualifiers are necessary and even permitted for
// protected functions. GNU C++ does it wrongly.

#ifdef MSDOS
#define OPMODE &operating_mode::
#endif

#ifdef SUN
#define OPMODE
#endif

// on VM machines, there is no problem allocating as much space as we
// are likely to need on the stack. This is not true for DOS, where
// the large amount of stack space used by the array data_array in
// the routine _scale will cause a very rapid crash. Consequently, we
// define a class that works on the heap and emulates a 4D array of
// short ints.

/* class fourshort
{ int16** sip;
  int16 a, b, c, d;
  int _start_channel, _end_channel;

public:
  fourshort(const int, const int, const int, const int, const int, const int);
  ~fourshort(void);

  inline operator int(void)
    { return (sip ? 1 : 0); }
  int16& datum(const int, const int, const int, const int);
  inline int actual_start_channel(void)
	 { return _start_channel; }
  inline int actual_end_channel(void)
    { return _end_channel; }

}; */

class operating_mode
{

#ifdef MSWINDOWS
friend class midas_window;
#endif

protected:
  enum { fixed = 0, variable, jpl_phiex, pds_phiex, pds_browse,
         pds_bbrowse, pds };

  BIG_ARRAY(binned_edr) Binned_record;
  
  boolean To_file, Autoscale_tomplot, Next_called_implicitly;
  boolean Valid_data[256];
  boolean * Is_binned;
  volatile boolean Cancelled;

  data_file* Edr_f;

  float Version;

  float Step[201][2];

  GMDR Gmdr;

  high_rate_frame* High_rate_frame_p;

  int Brightness, Current_pra_mode, Current_sc_mode,
		Duration, End_channel, Filesize, File_record_length,
		File_type, Gs2_n_data, Gs2_n_strips, High_ignore_value,
		High_recall_value, High_res_channel,
		Low_ignore_value, Low_recall_value,
		N_tomplot_channels, Pol_contrast, Pol_intensity_threshold,
		Previous_edr_record_nr, Records_processed,
		Saturation, Spacecraft, Start_channel, Start_tomplot_channel,
		Tplotmode, Upper_square_value;

  int Pra_submodes_present[16], Sc_modes_present[N_SC_MODES];

  uint16 Sq_width, Sq_height;

  uint16 Background[201][2], Midground[201][2], Tomplot_dn_range[201][2];

  uint32 Filesize_in_bytes;

  timeclass End_time, Minimum_time, Maximum_time, Start_time;

  pds_phiex_frame* Gs2_frame_pds;

  phiex_frame* Gs2_frame_jpl;
  
  phiex_position Current_phiex_position, Last_phiex_position;
  
  scet_type Gs2_scet;

  set Binned_modes, Spectral_modes, Pds_browse_modes, Low_rate_modes,
		High_rate_modes, Pra_modes_present;
  set Equivalent_sc_modes[N_SC_MODES];

  DREstring Comment, Current_file_name, Printer_name;
  
  surface* Pad, *Screen_device, *Hardcopy_device;
  
  struct time_index  
  { public:
      int n; 
      timeclass t; 
      time_index(void) : n(0), t(0) { }
  };

// A bug in gcc requires us _not_ to use a macro call to a template
// class when the type being passed is not a builtin or simple typedef.
// This appears to result from the fact that the compiler does not
// conform to r.7.1.3.

#ifdef __GNUC__
  big_array<struct time_index> Sorted_list;
#else
  BIG_ARRAY(time_index) Sorted_list;
#endif

  void _bin(void);
  void _bin(const int rec_nr);
  void _comment(DREstring&);
  void _execute_low_rate_plot_command(void);
  int _first_after(const timeclass &);
  int _last_before(const timeclass &);

// logical to physical mapping
  inline int _ltp(const int k)
    { return Sorted_list[k].n; }

  DREstring _pra_modes_string(void);
  DREstring _sc_modes_string(void);
  DREstring _time_range_string(void);

  timeclass _time_of_record(const int logical_rec_nr);
  
  virtual boolean _open(DREstring&);

  void _check_pad(DREstring&);
  boolean _file_not_open(void);
  boolean _modes_in_file(void);
  void _plot_full_frame(void);
  void _plot_gs2_hi_res(const phiex_position&, const int, const int);
  virtual void _pol_contrast(void)
   { }
  virtual void _pol_threshold(void)
   { }
  virtual void _popup(DREstring& title, DREstring& msg)
	 { display_status(title + ": " + msg); }
  int _pra_mode_fm_submode(int);
  int _rawplot(const timeint&, const timeint&);
  int _scale(timeclass&, timeclass&);
  void _title(DREstring&);
  int _tomplot(const timeint&, const timeint&);
  boolean _valid(const uint16);
  void _x_axis(void);
  void _y_axis(void);
  virtual void verbose(DREstring&) = 0;  

  typedef int (operating_mode::*PMFTITI)(const timeint&, const timeint&);
  PMFTITI _plot_function;

  void _print(void)
    { Pad->print(); }

  inline void _show_pra_modes(void)
    { if (!_file_not_open()) then
		  _popup((DREstring)"PRA MODES", _pra_modes_string());
    }
  inline void _show_sc_modes(void)
    { if (!_file_not_open()) then
		  _popup((DREstring)"SC MODES", _sc_modes_string());
    }
  inline void _show_time_range(void)
    { if (!_file_not_open()) then
	_popup((DREstring)"TIME RANGE", _time_range_string());
    }

public:
  operating_mode(void);
  virtual ~operating_mode(void);

// the commands -- In a fully C++ environment, these would all be virtual.
// Unfortunately, in the current release of the C++ spec, one cannot
// find the absolute address of a virtual function. In the sunview_mode
// class such addresses have to be passed to the (C) notifier. Therefore
// we simply override these functions in derived classes. It is inelegant,
// but the only way to get the job done.

  void initialise(void); 
  void first(void);
  void last(void);
  int next(void);
  void plotall(void);
  void plotrmdr(void);
  void print(void);
  int prior(void);
  void replot(void);
  
// other functions
  virtual void clear_status(void) = 0;
  int display_spectral(const timeint&, const timeint&);
  virtual void display_status(DREstring&) = 0;
  int do_plot(const timeint&, const timeint&);
  virtual void error(DREstring&) = 0;
  virtual void busy(DREstring& msg);
  virtual void unbusy(void)
    { display_status((DREstring)""); }
  virtual void information(const char* cp)
    { ::information(cp); }

  int file_percentage(void) const;

  virtual void display_progress(const int n)
	 { display_status(DREstring10(n) + (DREstring)"%"); }
  virtual void undisplay_progress(void)
    { display_status((DREstring)""); }
};

#endif

