#ifndef AOFLAGGER_GUI_RFIGUIMENU_H_
#define AOFLAGGER_GUI_RFIGUIMENU_H_

#include "../structures/timefrequencydata.h"

#include <giomm/actionmap.h>
#include <giomm/menu.h>
#include <giomm/simpleaction.h>

#include <glibmm/variant.h>

#include <gtkmm/box.h>
#include <gtkmm/button.h>
#include <gtkmm/drawingarea.h>
#include <gtkmm/image.h>
#include <gtkmm/menubutton.h>
#include <gtkmm/separator.h>
#include <gtkmm/togglebutton.h>
#include <gtkmm/popovermenubar.h>

#include <string>
#include <vector>

class RFIGuiMenu {
 public:
  RFIGuiMenu(Gio::ActionMap& actions);

  Gtk::PopoverMenuBar& Menu() { return _menuBar; }
  Gtk::Box& Toolbar() { return _toolbar; }

  // File
  sigc::signal<void()> OnOpen;
  sigc::signal<void(std::size_t)> OnOpenRecent;
  sigc::signal<void()> OnSaveBaselineFlags, OnExportBaseline, OnClose, OnQuit,
      OnAbout;

  // View
  sigc::signal<void()> OnViewMode, OnViewData, OnViewStrategy, OnViewTimePlot,
      OnImagePropertiesPressed, OnToggleFlags, OnHightlightPressed;
  sigc::signal<void()> OnZoomFit, OnZoomIn, OnZoomOut, OnZoomSelect;
  sigc::signal<void()> OnShowStats;

  // Strategy
  sigc::signal<void()> OnExecutePythonStrategy, OnExecuteLuaStrategy,
      OnStrategyNewEmpty, OnStrategyNewTemplate, OnStrategyNewDefault,
      OnStrategyOpen;
  sigc::signal<void(std::string)> OnStrategyOpenDefault;
  sigc::signal<void()> OnStrategySave, OnStrategySaveAs;

  // Plot
  sigc::signal<void()> OnPlotDistPressed;
  sigc::signal<void()> OnPlotLogLogDistPressed;
  sigc::signal<void()> OnPlotMeanSpectrumPressed;
  sigc::signal<void()> OnPlotSumSpectrumPressed;
  sigc::signal<void()> OnPlotPowerSpectrumPressed;
  sigc::signal<void()> OnPlotFrequencyScatterPressed;
  sigc::signal<void()> OnPlotTimeMeanPressed;
  sigc::signal<void()> OnPlotTimeScatterPressed;
  sigc::signal<void()> OnPlotSingularValuesPressed;

  // Browse
  sigc::signal<void()> OnLoadPrevious;
  sigc::signal<void()> OnReloadPressed;
  sigc::signal<void()> OnLoadNext;
  sigc::signal<void()> OnGoToPressed;
  sigc::signal<void()> OnLoadLongestBaselinePressed;
  sigc::signal<void()> OnLoadShortestBaselinePressed;
  sigc::signal<void()> OnLoadMedianBaselinePressed;

  // Simulate
  sigc::signal<void()> OnOpenTestSetA;
  sigc::signal<void()> OnOpenTestSetB;
  sigc::signal<void()> OnOpenTestSetC;
  sigc::signal<void()> OnOpenTestSetD;
  sigc::signal<void()> OnOpenTestSetE;
  sigc::signal<void()> OnOpenTestSetF;
  sigc::signal<void()> OnOpenTestSetG;
  sigc::signal<void()> OnOpenTestSetH;
  sigc::signal<void()> OnOpenTestSetNoise;

  sigc::signal<void()> OnAddStaticFringe;
  sigc::signal<void()> OnAdd1SigmaFringe;
  sigc::signal<void()> OnSetToOne;
  sigc::signal<void()> OnSetToI;
  sigc::signal<void()> OnSetToOnePlusI;
  sigc::signal<void()> OnAddCorrelatorFault;
  sigc::signal<void()> OnAddNaNs;
  sigc::signal<void()> OnMultiplyData;

  sigc::signal<void()> OnSimulate;

  // Data
  sigc::signal<void()> OnVisualizedToOriginalPressed;
  sigc::signal<void()> OnKeepRealPressed;
  sigc::signal<void()> OnKeepImaginaryPressed;
  sigc::signal<void()> OnKeepPhasePressed;
  sigc::signal<void()> OnUnrollPhaseButtonPressed;

  sigc::signal<void()> OnKeepStokesIPressed;
  sigc::signal<void()> OnKeepStokesQPressed;
  sigc::signal<void()> OnKeepStokesUPressed;
  sigc::signal<void()> OnKeepStokesVPressed;
  sigc::signal<void()> OnKeepRRPressed;
  sigc::signal<void()> OnKeepRLPressed;
  sigc::signal<void()> OnKeepLRPressed;
  sigc::signal<void()> OnKeepLLPressed;
  sigc::signal<void()> OnKeepXXPressed;
  sigc::signal<void()> OnKeepXYPressed;
  sigc::signal<void()> OnKeepYXPressed;
  sigc::signal<void()> OnKeepYYPressed;

  sigc::signal<void()> OnStoreData;
  sigc::signal<void()> OnRecallData;
  sigc::signal<void()> OnSubtractDataFromMem;
  sigc::signal<void()> OnClearOriginalFlagsPressed;
  sigc::signal<void()> OnClearAltFlagsPressed;

  sigc::signal<void()> OnTemporalAveragingPressed;
  sigc::signal<void()> OnSpectralAveragingPressed;
  sigc::signal<void()> OnPredictResidual;

  // Segmentation
  sigc::signal<void()> OnSegment;
  sigc::signal<void()> OnCluster;
  sigc::signal<void()> OnClassify;
  sigc::signal<void()> OnRemoveSmallSegments;

  // Toolbar signals (some are already covered)
  sigc::signal<void()> OnTogglePolarizations;
  sigc::signal<void()> OnToggleImage;
  sigc::signal<void()> OnSelectImage;

  sigc::signal<void(unsigned)> openTestSet;

  bool OriginalFlagsActive() const { return _tbOriginalFlags.get_active(); }
  bool AlternativeFlagsActive() const {
    return _tbAlternativeFlags.get_active();
  }

  void SetOriginalFlagsActive(bool originalFlags) {
    _tbOriginalFlags.set_active(originalFlags);
  }
  void SetAlternativeFlagsActive(bool alternativeFlags) {
    _tbAlternativeFlags.set_active(alternativeFlags);
  }

  bool ShowPPActive() const { return _tbDisplayPP.get_active(); }
  bool ShowPQActive() const { return _tbDisplayPQ.get_active(); }
  bool ShowQPActive() const { return _tbDisplayQP.get_active(); }
  bool ShowQQActive() const { return _tbDisplayQQ.get_active(); }

  bool ViewTimePlot() const {
    bool value;
    view_time_plot_action_->get_state(value);
    return value;
  }

  void SetShowPPActive(bool active) { _tbDisplayPP.set_active(active); }
  void SetShowPQActive(bool active) { _tbDisplayPQ.set_active(active); }
  void SetShowQPActive(bool active) { _tbDisplayQP.set_active(active); }
  void SetShowQQActive(bool active) { _tbDisplayQQ.set_active(active); }

  void SetShowPPSensitive(bool sensitive) {
    _tbDisplayPP.set_sensitive(sensitive);
  }
  void SetShowPQSensitive(bool sensitive) {
    _tbDisplayPQ.set_sensitive(sensitive);
  }
  void SetShowQPSensitive(bool sensitive) {
    _tbDisplayQP.set_sensitive(sensitive);
  }
  void SetShowQQSensitive(bool sensitive) {
    _tbDisplayQQ.set_sensitive(sensitive);
  }

  void SetZoomToFitSensitive(bool sensitive) {
    _tbZoomFit.set_sensitive(sensitive);
  }
  void SetZoomOutSensitive(bool sensitive) {
    _tbZoomOut.set_sensitive(sensitive);
  }
  void SetZoomInSensitive(bool sensitive) {
    _tbZoomIn.set_sensitive(sensitive);
  }

  void SetPreviousSensitive(bool sensitive) {
    _tbPrevious.set_sensitive(sensitive);
  }
  void SetNextSensitive(bool sensitive) { _tbNext.set_sensitive(sensitive); }
  void SetReloadSensitive(bool sensitive) {
    _tbReload.set_sensitive(sensitive);
  }

  void SetSelectVisualizationSensitive(bool sensitive) {
    _tbSelectVisualization.set_sensitive(sensitive);
  }

  void SetRecentFiles(const std::vector<std::string>& recentFiles);

  void SetStrategyDefaults(const std::vector<std::string>& recentFiles);

  std::shared_ptr<Gio::Menu>& VisualizationMenu() {
    return _tfVisualizationMenu;
  }

  void BlockVisualizationSignals() { _blockVisualizationSignals = true; }
  void UnblockVisualizationSignals() { _blockVisualizationSignals = false; }

  void EnableRunButtons(bool sensitive);

  void ActivateDataMode() {
    view_mode_action_->set_state(Glib::Variant<int>::create(0));
  }
  void ActivateStrategyMode() {
    view_mode_action_->set_state(Glib::Variant<int>::create(1));
  }

 private:
  template <typename SigType>
  std::shared_ptr<Gio::SimpleAction> addItem(std::shared_ptr<Gio::Menu>& menu,
                                             const char* label,
                                             const std::string& action_name,
                                             const SigType& sig) {
    menu->append(label, "win." + action_name);
    return actions_.add_action(action_name, sig);
  }

  template <typename SigType>
  void addTool(Gtk::Button& tool, const SigType& sig, const char* label,
               const char* tooltip, const char* icon) {
    tool.set_label(label);
    tool.set_tooltip_text(tooltip);
    tool.set_icon_name(icon);
    tool.signal_clicked().connect(sig);
    _toolbar.append(tool);
  }

  void addTool(Gtk::MenuButton& tool, const char* label, const char* tooltip,
               const char* icon) {
    tool.set_label(label);
    tool.set_tooltip_text(tooltip);
    tool.set_icon_name(icon);
    _toolbar.append(tool);
  }

  void onTBModeData();
  void onTBModeStrategy();
  void onViewModeChanged(int state);

  std::shared_ptr<Gio::Menu> makeFileMenu();
  std::shared_ptr<Gio::Menu> makeViewMenu();
  std::shared_ptr<Gio::Menu> makeStrategyMenu();
  std::shared_ptr<Gio::Menu> makePlotMenu();
  std::shared_ptr<Gio::Menu> makeBrowseMenu();
  std::shared_ptr<Gio::Menu> makeSimulateMenu();
  std::shared_ptr<Gio::Menu> makeDataMenu();
  std::shared_ptr<Gio::Menu> makeSegmentationMenu();
  void makeToolbarActions();

  Gtk::PopoverMenuBar _menuBar;
  Gtk::Box _toolbar;

  std::shared_ptr<Gio::Menu> recent_files_menu_;
  std::shared_ptr<Gio::Menu> open_defaults_menu_;

  Gio::ActionMap& actions_;
  std::shared_ptr<Gio::SimpleAction> load_previous_;
  std::shared_ptr<Gio::SimpleAction> reload_data_;
  std::shared_ptr<Gio::SimpleAction> load_next_;
  std::shared_ptr<Gio::SimpleAction> execute_strategy_;
  std::shared_ptr<Gio::SimpleAction> execute_python_;

  // View menu
  std::shared_ptr<Gio::SimpleAction> view_mode_action_;
  std::shared_ptr<Gio::SimpleAction> view_time_plot_action_;

  // Toolbar
  Gtk::Button _tbOpen, _tbExecuteStrategy;
  Gtk::ToggleButton _tbModeData, _tbModeStrategy;
  Gtk::ToggleButton _tbOriginalFlags, _tbAlternativeFlags;
  Gtk::MenuButton _tbSelectVisualization;
  Gtk::Button _tbPrevious, _tbReload, _tbNext;
  Gtk::Button _tbZoomFit, _tbZoomIn, _tbZoomOut;
  Gtk::ToggleButton _tbDisplayPP, _tbDisplayPQ, _tbDisplayQP, _tbDisplayQQ;

  bool _inStrategyMode;
  bool _blockVisualizationSignals;

  std::shared_ptr<Gio::Menu> _tfVisualizationMenu;
};

#endif
