#include "Data.hh"

#include <iostream>
#include <fstream>
#include <cassert>

using namespace std;

Data::Data(const std::string& filename) {
  // read data from file
  // return 1 if successful, 0 if otherwise

  m_name = filename;

  // open the file
  ifstream file(filename);

  // check if file opened correctly
  if (!file.is_open()) {
    throw "Error could not open file with name: " + filename;
  }

  int size = -1;
  file >> size;

  // read in data from file: m_siz+1 bin edges
  for (int i = 0; i < size + 1; i++) {
    double edge;
    file >> edge;
    m_bins.push_back(edge);
  }
  // read in data from file: m_siz bin contents
  for (int i = 0; i < size; i++) {
    double entries;
    file >> entries;
    m_data.push_back(entries);
  }

  for (int i = 0; i < size; i++) {
    double error;
    file >> error;
    m_error.push_back(error);
  }

  // done! close the file
  file.close();
};

int Data::checkCompatibility(const Data* in, int N) const {
  assert(in->size() == size());
  int fails = 0;

  for (int i = 0; i < size(); i++) {
    if (abs(in->measurement(i) - measurement(i)) > N * (in->error(i)
          + error(i))) {
      fails++;
    }
  }
  return fails;
}

double Data::chisquare(double (*f)(double)) const {
  double res = 0;
  for (unsigned int i = 0; i < size(); i++) {
    res += pow(measurement(i) - f(binCenter(i)), 2) / pow(error(i), 2);
  }
  return res / 52;
}

Data operator+(const Data& a, const Data& b) {

  assert(a.checkCompatibility(&b, 3) == 0);
  vector<double> avg_y;
  vector<double> avg_w;
  for (unsigned int i = 0; i < a.size(); i++) {
    double w1 = 1/(a.error(i) * a.error(i));
    double w2 = 1/(b.error(i) * b.error(i));
    avg_y.push_back((w1 * a.measurement(i) + w2 * b.measurement(i)) / (w1 + w2));
    avg_w.push_back(sqrt(1/(w1 + w2)));
  }
  Data d;
  d.m_bins = a.m_bins;
  d.m_data = avg_y;
  d.m_error = avg_w;
  return d;
}

void Data::assertSizes() { assert(m_data.size() + 1 == m_bins.size()); }
