#include "histogrampage.h"

#include <functional>

#include "controllers/histogrampagecontroller.h"

#include "../plot/plotpropertieswindow.h"

#include "datawindow.h"

HistogramPage::HistogramPage(HistogramPageController* controller)
    : _controller(controller),
      _expander("Side bar"),
      _histogramTypeFrame("Histogram"),
      _totalHistogramButton("Total"),
      _rfiHistogramButton("RFI"),
      _notRFIHistogramButton("Not RFI"),
      _xxPolarizationButton("XX"),
      _xyPolarizationButton("XY"),
      _yxPolarizationButton("YX"),
      _yyPolarizationButton("YY"),
      _sumPolarizationButton("Sum"),
      _fitFrame("Fitting"),
      _fitButton("Fit"),
      _subtractFitButton("Subtract"),
      _fitLogarithmicButton("Log fit"),
      _fitAutoRangeButton("Auto range"),
      _functionFrame("Function"),
      _nsButton("N(S)"),
      _dndsButton("dN(S)/dS"),
      _deltaSEntry(),
      _staircaseFunctionButton("Staircase"),
      _normalizeButton("Normalize"),
      _plotPropertiesButton("Properties"),
      _dataExportButton("Data"),
      _slopeFrame("Slope"),
      _drawSlopeButton("Draw"),
      _drawSlope2Button("Draw2"),
      _slopeAutoRangeButton("Auto range"),
      _plotPropertiesWindow(nullptr) {
  _histogramTypeBox.append(_totalHistogramButton);
  _totalHistogramButton.set_active(true);
  _totalHistogramButton.signal_toggled().connect(
      sigc::mem_fun(*this, &HistogramPage::updatePlot));
  _histogramTypeBox.append(_rfiHistogramButton);
  _rfiHistogramButton.set_active(false);
  _rfiHistogramButton.signal_toggled().connect(
      sigc::mem_fun(*this, &HistogramPage::updatePlot));
  _histogramTypeBox.append(_notRFIHistogramButton);
  _notRFIHistogramButton.set_active(false);
  _notRFIHistogramButton.signal_toggled().connect(
      sigc::mem_fun(*this, &HistogramPage::updatePlot));

  _histogramTypeFrame.set_child(_histogramTypeBox);

  _sideBox.append(_histogramTypeFrame);

  _polarizationBox.append(_xxPolarizationButton);
  _xxPolarizationButton.set_active(false);
  _xxPolarizationButton.signal_toggled().connect(
      sigc::mem_fun(*this, &HistogramPage::updatePlot));
  _polarizationBox.append(_xyPolarizationButton);
  _xyPolarizationButton.set_active(false);
  _xyPolarizationButton.signal_toggled().connect(
      sigc::mem_fun(*this, &HistogramPage::updatePlot));
  _polarizationBox.append(_yxPolarizationButton);
  _yxPolarizationButton.set_active(false);
  _yxPolarizationButton.signal_toggled().connect(
      sigc::mem_fun(*this, &HistogramPage::updatePlot));
  _polarizationBox.append(_yyPolarizationButton);
  _yyPolarizationButton.set_active(false);
  _yyPolarizationButton.signal_toggled().connect(
      sigc::mem_fun(*this, &HistogramPage::updatePlot));
  _polarizationBox.append(_sumPolarizationButton);
  _sumPolarizationButton.set_active(true);
  _sumPolarizationButton.signal_toggled().connect(
      sigc::mem_fun(*this, &HistogramPage::updatePlot));

  _polarizationFrame.set_child(_polarizationBox);

  _sideBox.append(_polarizationFrame);

  _fitBox.append(_fitButton);
  _fitButton.signal_toggled().connect(
      sigc::mem_fun(*this, &HistogramPage::updatePlot));
  _fitBox.append(_subtractFitButton);
  _subtractFitButton.signal_toggled().connect(
      sigc::mem_fun(*this, &HistogramPage::updatePlot));
  _fitBox.append(_fitLogarithmicButton);
  _fitLogarithmicButton.signal_toggled().connect(
      sigc::mem_fun(*this, &HistogramPage::updatePlot));
  _fitBox.append(_fitAutoRangeButton);
  _fitAutoRangeButton.set_active(true);
  _fitAutoRangeButton.signal_toggled().connect(
      sigc::mem_fun(*this, &HistogramPage::onAutoRangeClicked));

  _fitBox.append(_fitStartEntry);
  _fitStartEntry.set_sensitive(false);
  _fitStartEntry.signal_activate().connect(
      sigc::mem_fun(*this, &HistogramPage::updatePlot));
  _fitBox.append(_fitEndEntry);
  _fitEndEntry.set_sensitive(false);
  _fitEndEntry.signal_activate().connect(
      sigc::mem_fun(*this, &HistogramPage::updatePlot));
  _fitBox.append(_fitTextView);

  _fitFrame.set_child(_fitBox);

  _sideBox.append(_fitFrame);

  _functionBox.append(_nsButton);
  _nsButton.signal_toggled().connect(
      sigc::mem_fun(*this, &HistogramPage::updatePlot));
  _functionBox.append(_dndsButton);
  _dndsButton.signal_toggled().connect(
      sigc::mem_fun(*this, &HistogramPage::updatePlot));
  _dndsButton.set_group(_nsButton);
  _nsButton.set_active(true);
  _functionBox.append(_deltaSEntry);
  _deltaSEntry.set_text("2");
  _deltaSEntry.signal_activate().connect(
      sigc::mem_fun(*this, &HistogramPage::updatePlot));
  _functionBox.append(_staircaseFunctionButton);
  _staircaseFunctionButton.signal_toggled().connect(
      sigc::mem_fun(*this, &HistogramPage::updatePlot));
  _functionBox.append(_normalizeButton);
  _normalizeButton.set_active(true);
  _normalizeButton.signal_toggled().connect(
      sigc::mem_fun(*this, &HistogramPage::updatePlot));

  _functionFrame.set_child(_functionBox);
  _sideBox.append(_functionFrame);

  _plotPropertiesButton.signal_clicked().connect(
      sigc::mem_fun(*this, &HistogramPage::onPlotPropertiesClicked));
  _sideBox.append(_plotPropertiesButton);

  _dataExportButton.signal_clicked().connect(
      sigc::mem_fun(*this, &HistogramPage::onDataExportClicked));
  _sideBox.append(_dataExportButton);

  _slopeBox.append(_slopeTextView);
  _drawSlopeButton.signal_toggled().connect(
      sigc::mem_fun(*this, &HistogramPage::updatePlot));
  _slopeBox.append(_drawSlopeButton);
  _drawSlope2Button.signal_toggled().connect(
      sigc::mem_fun(*this, &HistogramPage::updatePlot));
  _slopeBox.append(_drawSlope2Button);

  _slopeBox.append(_slopeAutoRangeButton);
  _slopeAutoRangeButton.set_active(true);
  _slopeAutoRangeButton.signal_toggled().connect(
      sigc::mem_fun(*this, &HistogramPage::onSlopeAutoRangeClicked));

  _slopeBox.append(_slopeStartEntry);
  _slopeStartEntry.set_sensitive(false);
  _slopeStartEntry.signal_activate().connect(
      sigc::mem_fun(*this, &HistogramPage::updatePlot));
  _slopeBox.append(_slopeEndEntry);
  _slopeEndEntry.set_sensitive(false);
  _slopeEndEntry.signal_activate().connect(
      sigc::mem_fun(*this, &HistogramPage::updatePlot));
  _slopeBox.append(_slopeRFIRatio);
  _slopeRFIRatio.set_text("1.0");
  _slopeRFIRatio.signal_activate().connect(
      sigc::mem_fun(*this, &HistogramPage::updatePlot));

  _slopeFrame.set_child(_slopeBox);
  _sideBox.append(_slopeFrame);

  _expander.set_child(_sideBox);

  append(_expander);

  _plotWidget.SetPlot(_controller->Plot());
  append(_plotWidget);
  _plotWidget.set_expand(true);

  _dataWindow = new DataWindow();

  _controller->Attach(this);
}

HistogramPage::~HistogramPage() {
  delete _plotPropertiesWindow;
  delete _dataWindow;
}

void HistogramPage::updatePlot() {
  _controller->SetDrawXX(_xxPolarizationButton.get_active());
  _controller->SetDrawXY(_xyPolarizationButton.get_active());
  _controller->SetDrawYX(_yxPolarizationButton.get_active());
  _controller->SetDrawYY(_yyPolarizationButton.get_active());
  _controller->SetDrawSum(_sumPolarizationButton.get_active());

  _controller->SetAutomaticFitRange(_fitAutoRangeButton.get_active());
  _controller->SetFitStart(atof(_fitStartEntry.get_text().c_str()));
  _controller->SetFitEnd(atof(_fitEndEntry.get_text().c_str()));
  _controller->SetFitLogarithmic(_fitLogarithmicButton.get_active());

  _controller->SetAutomaticSlopeRange(_slopeAutoRangeButton.get_active());
  _controller->SetSlopeStart(atof(_slopeStartEntry.get_text().c_str()));
  _controller->SetSlopeEnd(atof(_slopeEndEntry.get_text().c_str()));
  _controller->SetSlopeRFIRatio(atof(_slopeRFIRatio.get_text().c_str()));
  double deltaS = atof(_deltaSEntry.get_text().c_str());
  if (deltaS <= 1.0001) deltaS = 1.0001;
  _controller->SetDeltaS(deltaS);

  _controller->SetDrawTotal(_totalHistogramButton.get_active());
  _controller->SetDrawFit(_fitButton.get_active());
  _controller->SetDrawSubtractedFit(_subtractFitButton.get_active());
  _controller->SetDrawSlope(_drawSlopeButton.get_active());
  _controller->SetDrawSlope2(_drawSlope2Button.get_active());
  _controller->SetDrawRFI(_rfiHistogramButton.get_active());
  _controller->SetDrawNonRFI(_notRFIHistogramButton.get_active());

  _controller->SetDerivative(_dndsButton.get_active());
  _controller->SetStaircase(_staircaseFunctionButton.get_active());
  _controller->SetNormalize(_normalizeButton.get_active());
  _controller->SetDeltaS(atof(_deltaSEntry.get_text().c_str()));
}

void HistogramPage::onPlotPropertiesClicked() {
  if (_plotPropertiesWindow == nullptr) {
    _plotPropertiesWindow =
        new PlotPropertiesWindow(_controller->Plot(), "Plot properties");
    _plotPropertiesWindow->OnChangesApplied =
        std::bind(&HistogramPage::Redraw, this);
  }

  _plotPropertiesWindow->present();
}

void HistogramPage::onDataExportClicked() {
  _dataWindow->present();
  updateDataWindow();
}

void HistogramPage::SetSlopeFrame(const std::string& str) {
  _slopeTextView.get_buffer()->set_text(str);

  if (_slopeAutoRangeButton.get_active()) {
    double minRange = _controller->SlopeStart(),
           maxRange = _controller->SlopeEnd();
    std::stringstream minRangeStr, maxRangeStr;
    minRangeStr << minRange;
    maxRangeStr << maxRange;
    _slopeStartEntry.set_text(minRangeStr.str());
    _slopeEndEntry.set_text(maxRangeStr.str());
  }

  if (_fitAutoRangeButton.get_active()) {
    std::stringstream minRangeStr, maxRangeStr;
    minRangeStr << _controller->FitStart();
    maxRangeStr << _controller->FitEnd();
    _fitStartEntry.set_text(minRangeStr.str());
    _fitEndEntry.set_text(maxRangeStr.str());
  }
}

void HistogramPage::updateDataWindow() {
  if (_dataWindow->get_visible()) _dataWindow->SetData(_controller->Plot());
}
