#include "aoqplotwindow.h"

#include "controllers/antennapagecontroller.h"
#include "controllers/aoqplotcontroller.h"
#include "controllers/baselinepagecontroller.h"
#include "controllers/blengthpagecontroller.h"
#include "controllers/frequencypagecontroller.h"
#include "controllers/histogrampagecontroller.h"
#include "controllers/tfpagecontroller.h"
#include "controllers/timepagecontroller.h"

#include <limits>

#include <giomm/simpleactiongroup.h>

#include <gtkmm/messagedialog.h>

#include "../structures/msmetadata.h"

#include "../quality/histogramtablesformatter.h"
#include "../quality/histogramcollection.h"
#include "../quality/statisticscollection.h"

#include "baselineplotpage.h"
#include "blengthplotpage.h"
#include "frequencyplotpage.h"
#include "histogrampage.h"
#include "summarypage.h"
#include "timefrequencyplotpage.h"

AOQPlotWindow::AOQPlotWindow(AOQPlotController* controller)
    : _controller(controller), _activeSheetIndex(-1), page_menu_button_() {
  set_default_icon_name("aoqplot");
  page_menu_button_.set_icon_name("open-menu-symbolic");
  std::shared_ptr<Gio::Menu> page_menu = Gio::Menu::create();
  page_menu->append("Baselines", "win.page_selection(0)");
  page_menu->append("Antennae", "win.page_selection(1)");
  page_menu->append("Baseline lengths", "win.page_selection(2)");
  page_menu->append("Time", "win.page_selection(3)");
  page_menu->append("Frequency", "win.page_selection(4)");
  page_menu->append("Time-frequency", "win.page_selection(5)");
  page_menu->append("Summary", "win.page_selection(6)");
  page_menu->append("Histograms", "win.page_selection(7)");

  auto actions = Gio::SimpleActionGroup::create();
  page_selection_ =
      Gio::SimpleAction::create_radio_integer("page_selection", 0);
  page_selection_->signal_change_state().connect(
      [this](const Glib::VariantBase& state) {
        const int value = static_cast<const Glib::Variant<int>&>(state).get();
        onChangeSheet(value);
      });
  actions->add_action(page_selection_);
  insert_action_group("win", actions);

  page_menu_button_.set_menu_model(page_menu);
  toolbar_.append(page_menu_button_);

  _vBox.append(toolbar_);

  _vBox.append(_statusBar);
  _statusBar.push(
      "Quality plot util is ready. Author: André Offringa "
      "(offringa@gmail.com)");
  _vBox.set_expand(true);
  set_child(_vBox);

  _openOptionsWindow.SignalOpen().connect(
      sigc::mem_fun(*this, &AOQPlotWindow::onOpenOptionsSelected));

  _controller->Attach(this);
}

void AOQPlotWindow::Open(const std::vector<std::string>& files) {
  _openOptionsWindow.ShowForFile(files);
}

void AOQPlotWindow::onOpenOptionsSelected(const std::vector<std::string>& files,
                                          bool downsampleTime,
                                          bool downsampleFreq, size_t timeCount,
                                          size_t freqCount,
                                          bool correctHistograms) {
  _controller->ReadStatistics(files, downsampleTime, downsampleFreq, timeCount,
                              freqCount, correctHistograms);
  _activeSheetIndex = -1;
  onChangeSheet(0);
  show();
}

void AOQPlotWindow::onStatusChange(const std::string& newStatus) {
  _statusBar.pop();
  _statusBar.push(newStatus);
}

void AOQPlotWindow::onChangeSheet(int selectedSheet) {
  if (selectedSheet != _activeSheetIndex) {
    if (plot_page_) _vBox.remove(*plot_page_);
    // In gtk 4, toggle buttons that are part of a group need to be disconnected
    // from the group before they are removed.
    auto* child = toolbar_.get_last_child();
    while (child != &page_menu_button_) {
      if (Gtk::ToggleButton* toggle = dynamic_cast<Gtk::ToggleButton*>(child);
          toggle) {
        toggle->unset_group();
      }
      toolbar_.remove(*child);
      child = toolbar_.get_last_child();
    }

    page_selection_->set_state(Glib::Variant<int>::create(selectedSheet));
    switch (selectedSheet) {
      case 0:
        _pageController.reset(new BaselinePageController());
        plot_page_.reset(new BaselinePlotPage(
            static_cast<BaselinePageController*>(_pageController.get())));
        SetStatus("Baseline statistics");
        break;
      case 1:
        _pageController.reset(new AntennaePageController());
        plot_page_.reset(new TwoDimensionalPlotPage(
            static_cast<AntennaePageController*>(_pageController.get())));
        SetStatus("Antennae statistics");
        break;
      case 2:
        _pageController.reset(new BLengthPageController());
        plot_page_.reset(new BLengthPlotPage(
            static_cast<BLengthPageController*>(_pageController.get())));
        SetStatus("Baseline length statistics");
        break;
      case 3:
        _pageController.reset(new TimePageController());
        plot_page_.reset(new TwoDimensionalPlotPage(
            static_cast<TimePageController*>(_pageController.get())));
        SetStatus("Time statistics");
        break;
      case 4:
        _pageController.reset(new FrequencyPageController());
        plot_page_.reset(new FrequencyPlotPage(
            static_cast<FrequencyPageController*>(_pageController.get())));
        SetStatus("Frequency statistics");
        break;
      case 5:
        _pageController.reset(new TFPageController());
        plot_page_.reset(new TimeFrequencyPlotPage(
            static_cast<TFPageController*>(_pageController.get())));
        SetStatus("Time-frequency statistics");
        break;
      case 6:
        _pageController.reset(new SummaryPageController());
        plot_page_.reset(new SummaryPage(
            static_cast<SummaryPageController*>(_pageController.get())));
        SetStatus("Summary");
        break;
      case 7:
        _pageController.reset(new HistogramPageController());
        plot_page_.reset(new HistogramPage(
            static_cast<HistogramPageController*>(_pageController.get())));
        SetStatus("Histograms");
        break;
    }

    _activeSheetIndex = selectedSheet;
    _controller->Initialize(_pageController.get(), selectedSheet != 5);
    plot_page_->SignalStatusChange().connect(
        sigc::mem_fun(*this, &AOQPlotWindow::onStatusChange));
    plot_page_->InitializeToolbar(toolbar_);
    plot_page_->set_expand(true);
    _vBox.insert_child_after(*plot_page_, toolbar_);
  }
}

void AOQPlotWindow::ShowError(const std::string& message) {
  dialog_ = std::make_unique<Gtk::MessageDialog>(*this, message, false,
                                                 Gtk::MessageType::ERROR);
  dialog_->show();
}
