// C++ code Copyright (C) David R. Evans G4AMJ/NQ0I

#ifndef HIGHRATEH
#define HIGHRATEH

// polhi express frame classes

// The format of high rate frame headers is described in an
// interoffice memo dated 22 August 1985 from J. L. Anderson
// to C. J. Hansen and R. L. Poynter

#include <defines.h>
#include <t_array.h>

#ifdef SUN
#include <magtape.h>
#endif

#include <math.h>
#include <stdio.h>
#include <iostream.h>

// define an abstract base class
class high_rate_frame
{
public:
  virtual int16 year(void) const = 0;
  virtual int16 day(void) const = 0;
  virtual octet hour(void) const = 0;
  virtual octet minute(void) const = 0;
  virtual octet second(void) const = 0;
  virtual octet sc(void) const = 0;
  virtual uint16 fds_integer(void) const = 0;
  virtual octet fds_fraction(void) const = 0;
  virtual uint16 datum(const int l, const int d, const int c) = 0;

  virtual double fds_count(void)
    { return (fds_integer() + (fds_fraction() / 100.0)); }
};

// note that line numbering is (externally) 0-799, datum numbering 0-399

// support classes
class scet_type
{ friend class phiex_frame;

  int16 _year, _day, _hour, _minute, _second;

public:
  void operator=(scet_type& s)
  { _year = s._year; 
    _day = s._day; 
    _hour = s._hour;
     _minute = s._minute;
    _second = s._second;
  }

  reveal(int16, year, _year);
  reveal(int16, day, _day);
  reveal(int16, hour, _hour);
  reveal(int16, minute, _minute);
  reveal(int16, second, _second);
};

class phiex_position
{ int _line, _datum;

  void _normalise(void);

public:
  phiex_position(const int line = 0, const int datum = 0) :
                                                   _line(line),
                                                   _datum(datum)
  { _normalise(); }

  phiex_position operator+(const int);
  phiex_position operator+(const phiex_position&);
  void operator+=(const int);
  void operator+=(const phiex_position&);
  inline phiex_position operator-(const int d)
    { return (*this + -d); }
  phiex_position operator-(const phiex_position&);
  inline void operator-=(const int d)
    { *this += -d; }
  void operator-=(const phiex_position&);

// Nick says that the Mac doesn't know how to do the following
#ifndef macintosh  
  inline phiex_position operator++(void)     // prefix
    { *this += 1;
      return *this;
    }
  inline phiex_position operator++(int)      // postfix
    { return (++*this); }
#endif
    
  inline boolean operator<(const phiex_position& p) const
    { return ((line() < p.line()) ||
              ((line() == p.line()) && (datum() < p.datum())));
    }

  inline boolean operator>(const phiex_position& p) const
    { return ((line() > p.line()) ||
              ((line() == p.line()) && (datum() > p.datum())));
    }

  reveal(int, line, _line);
  reveal(int, datum, _datum);
};

// derived classes
class phiex_frame : public high_rate_frame
{
protected:
  octet* _header;
  BIG_2_ARRAY(octet) _data;
  
  octet* _line;
  octet* _data_pair;

  void _swap_100_lines(void);

public:
  phiex_frame(void);
  phiex_frame(char*);
  
  virtual ~phiex_frame(void);

  phiex_frame(const phiex_frame&);
  
// return a line of data
  octet* line(const int n);
  octet* data_pair(const int ln, const int dn);
  inline octet* header(void) const 
    { return _header; }

// return a datum
  uint16 datum(const int, const int, const int);

  int read(FILE*);
  int read(const char*);
  
  int write(FILE*);
  int write(const char*);
 
#ifdef SUN
  int read(magtape&);
  inline int operator<<(magtape& tape) { return read(tape); }
#endif

  double fds_count(void) const;
  scet_type scet(void) const;
  octet sc(void) const;

  uint16 fds_integer(void) const;
  octet fds_fraction(void) const;
  
  inline int16 year(void) const 
    { return scet().year(); }
  inline int16 day(void) const 
    { return scet().day(); }
  inline octet hour(void) const 
    { return scet().hour(); }
  inline octet minute(void) const 
    { return scet().minute(); }
  inline octet second(void) const 
    { return scet().second(); }

// merge operators
  void operator+=(phiex_frame&);
  phiex_frame operator+(phiex_frame&);
};

class pds_phiex_frame : public high_rate_frame
{ 
public:
  uint32 ch[4];
  octet _bandwidth;
   
  octet _sc, _hour, _minute, _second, _fds_fraction;
  int16 _year, _day;
  uint16 _fds_integer;
  
  BIG_2_ARRAY(uint16) _data;

  void _calibrate(phiex_frame*);
//  short int& _ref_datum(const int l, const int d, const int c) const; 

  
public:
  pds_phiex_frame(phiex_frame*, const long int* channels,
                  int bandwidth = 200);
  pds_phiex_frame(void)  :  _data(800, 800)
    { }
  pds_phiex_frame(const pds_phiex_frame&);  
  inline virtual ~pds_phiex_frame(void)
    { }

  void operator=(const pds_phiex_frame&);
  
  int channel(int) const;
  inline int bandwidth(void) const 
    { return _bandwidth; }
  reveal(int16, year, _year);
  reveal(int16, day, _day);
  reveal(octet, hour, _hour);
  reveal(octet, minute, _minute);
  reveal(octet, second, _second);
  reveal(octet, sc, _sc);
  reveal(uint16, fds_integer, _fds_integer);
  reveal(octet, fds_fraction, _fds_fraction);

// 0 <= l < 800; 0 <= d < 400; 1 <= c < 3
  inline uint16 datum(const int l, const int d, const int c)
    { return _data.element(l, 2 * d + c - 1); }

  friend ostream& operator<<(ostream&, pds_phiex_frame&);
  friend istream& operator>>(istream&, pds_phiex_frame&);
  
  void write(FILE*);
  void read(FILE*);
  void read(const char*);
};

#endif
