// C++ code Copyright (C) David R. Evans G4AMJ/NQ0I

#include <math.h>

#include <binned_edr.h>
#include <gmdr.h>

// #define cr5	4

float binned_edr::pseudo_watts[256];
boolean binned_edr::valid_data[256];

// constructor
binned_edr::binned_edr(void) : binned_record(0),
			       polarisation_record(0),
			       l_data(0),
			       r_data(0)
{ }

// destructor
binned_edr::~binned_edr(void)
{ destroy_array(binned_record);
  destroy_array(polarisation_record);
  destroy_array(l_data);
  destroy_array(r_data);
}

void binned_edr::operator=(const binned_edr& be)
{ heap_check(binned_record = new byte [array_size]);
  heap_check(polarisation_record = new byte [array_size]);
  heap_check(l_data = new byte [array_size]);
  heap_check(r_data = new byte [array_size]);

  for (int n = 0; n < array_size; n++)
  { binned_record[n] = be.binned_record[n];
    polarisation_record[n] = be.polarisation_record[n];
    l_data[n] = be.l_data[n];
    r_data[n] = be.r_data[n];
  }
}

// bin the record. This only really makes sense if the GMDR was build
// from an sedr, but this is never checked
int binned_edr::operator=(const GMDR& gmdr)
{ heap_check(binned_record = new byte [array_size]);
  heap_check(polarisation_record = new byte [array_size]);
  heap_check(l_data = new byte [array_size]);
  heap_check(r_data = new byte [array_size]);

  int n[array_size], number[array_size][2];
  float power[array_size][2], sum[array_size];
  for (int c = 0; c < array_size; c++)
  { n[c] = number[c][0] = number[c][1] = 0;
    power[c][0] = power[c][1] = sum[c] = 0.0;
  }
  for (int s = 1; s <= gmdr.n_sweeps(); s++)
  { if  (gmdr.pra_mode(s) == prapollo) then
    { for (c = 3; c <= array_size; c++)
      { byte d = gmdr.datum(s,  c);  // note that a datum is an int16
        if (valid_data[d]) then
        { n[c - 1]++;
          float rd = pseudo_watts[d];
          sum[c - 1] += rd;
          const int tsense = gmdr.polarisation(s, c);
          number[c - 1][tsense]++;
          power[c - 1][tsense] += rd;
        }
      }
    }
  }
  for (c = 2; c < array_size; c++)
  { binned_record[c] = polarisation_record[c] = 0;
    if (n[c]) then
      binned_record[c] = (byte)((log(sum[c] / n[c]) * 100.0) + 0.5);
    if (number[c][0] && number[c][1]) then
    { for (int tsense = 0; tsense <= 1; tsense++)
        power[c][tsense] /= number[c][tsense];
      float polarisation_index = ((power[c][0] - power[c][1]) /
                                  (power[c][0] + power[c][1]));
      polarisation_record[c] = (byte)((polarisation_index) *
                                       127.0 + 127.0);
      l_data[c] = (byte)((log(power[c][0]) * 100.0) + 0.5);
      r_data[c] = (byte)((log(power[c][1]) * 100.0) + 0.5);
    }
  }
  return 1;				// all OK
}

// output the record
ostream& operator<<(ostream& out, binned_edr& param)
{ cout << "Binned record\n";
  cout << "      mB    PI\n";
  for (int n = 3; n <= 200; n++)
    cout << left_fill(DREstring(n, 10), 3) << 
            left_fill(DREstring(param.bdatum(n), 10), 6) <<
	    left_fill(DREstring(param.pdatum(n), 10), 5) << "\n";
  return out;
}

// binary write
void binned_edr::write(FILE* fp)
{ fwrite(binned_record, array_size, 1, fp);
  fwrite(polarisation_record, array_size, 1, fp);
  fwrite(l_data, array_size, 1, fp);
  fwrite(r_data, array_size, 1, fp);
}

// binary read
void binned_edr::read(FILE* fp)
{ if (!binned_record) then
  { heap_check(binned_record = new byte [array_size]);
    heap_check(polarisation_record = new byte [array_size]);
    heap_check(l_data = new byte [array_size]);
    heap_check(r_data = new byte [array_size]);
  }

  fread(binned_record, array_size, 1, fp);
  fread(polarisation_record, array_size, 1, fp);
  fread(l_data, array_size, 1, fp);
  fread(r_data, array_size, 1, fp);
}
