// C++ code Copyright (C) David R. Evans G4AMJ/NQ0I

#include <bdr.h>
#include <edr.h>
#include <gmdr.h>
#include <pdsdr.h>

// set internal variables to well defined states
void GMDR::_initialise(void)
{ _configuration_command = 0;
  _data = 0;
  _is_science = false;
  _binnable = false;
  _min_channel = 0;
  _max_channel = 0;
  _mode_command = 0;
  _n_sweeps = 0;
  _sc_mode = 0;
  _stati = 0;
  _sweep_duration = 0;
}

// default constructor
GMDR::GMDR(void)
{ _initialise();
}

// copy constructor
GMDR::GMDR(const GMDR& gmdr)
{ _configuration_command = gmdr._configuration_command;
  _is_science = gmdr._is_science;
  _min_channel = gmdr._min_channel;
  _max_channel = gmdr._max_channel;
  _mode_command = gmdr._mode_command;
  _n_sweeps = gmdr._n_sweeps;
  _sc_mode = gmdr._sc_mode;
  _sweep_duration = gmdr._sweep_duration;

// move the data
  if (gmdr._data) then
  { heap_check(_data = new GMDR_datum_struct [n_channels() * n_sweeps()]);
    for (int nr = 0; nr < n_channels() * n_sweeps(); nr++)
      _data[nr] = gmdr._data[nr];
  }

// and the stati
  if (gmdr._stati) then
  { heap_check(_stati = new GMDR_status_struct [n_sweeps()]);
    for (int nr = 0; nr < n_sweeps(); nr++)
      _stati[nr] = gmdr._stati[nr];
  }
}

// GMDR = bdr_record
void GMDR::operator=(const bdr_record& bdr)
{ if (_data) then
    delete [] _data;
  if (_stati) then
    delete [] _stati;
  _initialise();
  _is_science = true;
  _sc = bdr.sc();
  _time = bdr.time();

// a bdr has two sweeps, left then right
  _n_sweeps = 2;
// an entire record lasts for 48 seconds
  _sweep_duration = 24;
  
  _min_channel = bdr.min_valid_channel_nr();
  _max_channel = bdr.max_valid_channel_nr();
  _sc_mode = bdr.sc_mode();

// The mode and configuration command are unused in bdrs. Set them to
// nonzero values so that the gmdr does not report them as zero
  _configuration_command = 1;
  _mode_command = 1;

// in a GMDR, it is always true that sweeps are numbered from zero,
// as are data channels (internally). Externally, sweeps appear to
// be numbered from unity (to conform with all the other data types)
// and channel numbers are "real" PRA channel numbers

// move the data
  heap_check(_data = new GMDR_datum_struct [n_channels() * 2]);
  for (int sweep = 0; sweep < n_sweeps(); sweep++)
  { for (int channel = 0; channel < n_channels(); channel++)
    { _data[sweep * n_channels() + channel]._polarisation = sweep;
      _data[sweep * n_channels() + channel]._datum =
        bdr.datum(sweep + 1, _min_channel + channel);
    }
  }

// and the stati
  heap_check(_stati = new GMDR_status_struct [n_sweeps()]);
  for (sweep = 0; sweep < n_sweeps(); sweep++)
  { _stati[sweep]._pra_mode = prapollo;       // BDRs are always pollo
    _stati[sweep]._pra_submode = pollo;
  }
}

// GMDR = edr_record
void GMDR::operator=(const edr_record& edr)
{ if (_data) then
    delete [] _data;
  if (_stati) then
    delete [] _stati;
  _data = 0;
  _stati = 0;

  if (edr.record_type() != science) then
    _is_science = false;
  else
    *this = (science_edr_record)edr;
}

// GMDR = science_edr_record
void GMDR::operator=(const science_edr_record& sedr)
{ yield();
  if (_data) then
    delete [] _data;
  if (_stati) then
    delete [] _stati;

  _initialise();
  _is_science = true;
  if (!sedr.vim()) then
    _binnable = true;
  _sc = sedr.sc();
  _time = sedr.time();

  _configuration_command = sedr.configuration_command();
  _n_sweeps = sedr.n_sweeps();
  _min_channel = sedr.min_valid_channel_nr();
  _max_channel = sedr.max_valid_channel_nr();
  _mode_command = sedr.mode_command();
  _sc_mode = sedr.sc_mode();
  _sweep_duration = sedr.sweep_duration();

// move the data
  heap_check(_data = new GMDR_datum_struct [n_channels() * n_sweeps()]);
  for (int sweep = 0; sweep < n_sweeps(); sweep++)
  { for (int channel = 0; channel < n_channels(); channel++)
    { const int index = sweep * n_channels() + channel;
      if (index < 0) then
	fatal_error("");
      if (index >= n_channels() * n_sweeps()) then
	fatal_error("");

      GMDR_datum_struct& datum = _data[sweep * n_channels() + channel];

      datum._polarisation =
        sedr.polarisation(sweep + 1, _min_channel + channel);
      datum._datum =
        sedr.datum(sweep + 1, _min_channel + channel);
    }
  }

// and the stati
  heap_check(_stati = new GMDR_status_struct [n_sweeps()]);
  for (sweep = 0; sweep < n_sweeps(); sweep++)
  { GMDR_status_struct& status = _stati[sweep];

    status._pra_mode = sedr.pra_mode(sweep + 1);
    status._pra_submode = sedr.pra_submode(sweep + 1);
    status._frequency = sedr.frequency(sweep + 1);
// if we are in GS-8, then there is fixlo frequency info available
    if (sc_mode() == gs8) then
      status._fixlo_frequency = sedr.fixlo_frequency(sweep + 1);
  }
}

// GMDR = pdsdr
void GMDR::operator=(const pdsdr_record& pdsdr)
{ yield();
  destroy_array(_data);
  destroy_array(_stati);

  _initialise();
  _is_science = true;
  _sc = pdsdr.sc();
  _time = pdsdr.time();

  _configuration_command = pdsdr.sc_configuration_command();
  _n_sweeps = 1;
  _min_channel = 3;
  _max_channel = 200;
  _mode_command = pdsdr.sc_mode_command();
  _sc_mode = pdsdr.sc_mode();
  _sweep_duration = pdsdr.record_duration();

// move the data
  heap_check(_data = new GMDR_datum_struct [198]);
  for (int sweep = 0; sweep < 1; sweep++)
  { for (int channel = 0; channel < 198; channel++)
    { GMDR_datum_struct& datum = _data[channel];

// assume regular, toggling POLLO mode (for now)
      byte tsense, tpol3 = (pdsdr.pol3() == 'L' ? 0 : 1);
      const int tchannel = channel + 3;
      
      tsense = (ODD(tchannel) ? tpol3 : 1 - tpol3);
      if (tchannel >= 131) then
        tsense = 1 - tsense;
      
        datum._polarisation = tsense;
        datum._datum =
          pdsdr.datum(channel);
    }
  }

// and the stati
  heap_check(_stati = new GMDR_status_struct [1]);
  for (sweep = 0; sweep < 1; sweep++)
  { GMDR_status_struct& status = _stati[sweep];

    status._pra_mode = pdsdr.pra_mode();
    status._pra_submode = pdsdr.pra_submode();
    status._frequency = pdsdr.frequency();
// if we are in GS-8, then there is fixlo frequency info available
    if (sc_mode() == gs8) then
      status._fixlo_frequency = pdsdr.fixlo_frequency();
  }
}

// what is the polarisation of a sample?
byte GMDR::polarisation(const int sweep, const int channel) const
{ return _data[(sweep - 1) * n_channels() + channel - _min_channel].
           _polarisation;
}

// what is the value of a sample?
uint16 GMDR::datum(const int sweep, const int channel) const
{ return _data[(sweep - 1) * n_channels() + channel - _min_channel].
           _datum;
}

