/* -*- C++ -*-
 *
 *  This file is part of RawTherapee.
 *
 *  Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
 *
 *  RawTherapee is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  RawTherapee is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with RawTherapee.  If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef _THRESHOLDADJUSTER_H_
#define _THRESHOLDADJUSTER_H_

#include "editedstate.h"
#include "guiutils.h"
#include "thresholdselector.h"
#include <gtkmm.h>

class ThresholdAdjuster;

/*
 * TODO: Maybe we could just send back the history string instead of the
 * individual values?
 */
class ThresholdAdjusterListener {

public:
    virtual ~ThresholdAdjusterListener() = default;
    // to be used by listener that has created a ThresholdAdjuster with with
    // single threshold and precision > 0
    virtual void adjusterChanged(ThresholdAdjuster *a, double newBottom,
                                 double newTop) = 0;
    // to be used by listener that has created a ThresholdAdjuster with with
    // double threshold and precision > 0
    virtual void adjusterChanged(ThresholdAdjuster *a, double newBottomLeft,
                                 double newTopLeft, double newBottomRight,
                                 double newTopRight) = 0;
    // to be used by listener that has created a ThresholdAdjuster with with
    // single threshold and precision == 0
    virtual void adjusterChanged(ThresholdAdjuster *a, int newBottom,
                                 int newTop) = 0;
    // to be used by listener that has created a ThresholdAdjuster with with
    // double threshold and precision == 0
    virtual void adjusterChanged(ThresholdAdjuster *a, int newBottomLeft,
                                 int newTopLeft, int newBottomRight,
                                 int newTopRight) = 0;
    virtual void adjusterChanged2(ThresholdAdjuster *a, int newBottomL,
                                  int newTopL, int newBottomR, int newTopR) = 0;
};

class ThresholdAdjuster: public Gtk::VBox {

protected:
    Gtk::HBox *hbox;
    Gtk::Label *label;
    ThresholdSelector tSelector;
    // MySpinButton* spin;
    Gtk::Button *reset;
    ThresholdAdjusterListener *adjusterListener;
    sigc::connection delayConnection;
    // sigc::connection spinChange;
    sigc::connection selectorChange;
    sigc::connection editedChange;
    double initialDefaultVal[4]; // default value at construction time
    EditedState editedState;
    EditedState defEditedState;
    Gtk::CheckButton *editedCheckBox;
    bool afterReset;
    bool blocked;
    bool addMode;
    bool separatedMode;
    int delay;

    double shapeValue(double a);
    void refreshLabelStyle();
    void initObject(Glib::ustring label, bool editedcb, bool compact = false);
    void sendToListener();

public:
    // Custom Threshold widget with 2 cursors (Top and Bottom) and a custom
    // curve provided by the instanciator, each cursor having his own range,
    // default value and precision
    ThresholdAdjuster(Glib::ustring label, double minValueBottom,
                      double maxValueBottom, double defBottom,
                      Glib::ustring labelBottom, unsigned int precisionBottom,
                      double minValueTop, double maxValueTop, double defTop,
                      Glib::ustring labelTop, unsigned int precisionTop,
                      ThresholdCurveProvider *curveProvider,
                      bool editedCheckBox = false, bool compact = false);
    // Simple Threshold widget with 2 linked sliders (0->1 or 1->0)
    ThresholdAdjuster(Glib::ustring label, double minValue, double maxValue,
                      double defBottom, double defTop, unsigned int precision,
                      bool startAtOne, bool editedCheckBox = false);
    // Simple Threshold widget with 4 linked sliders by pairs (0->1->0 or
    // 1->0->1)
    ThresholdAdjuster(Glib::ustring label, double minValue, double maxValue,
                      double defBottomLeft, double defTopLeft,
                      double defBottomRight, double defTopRight,
                      unsigned int precision, bool startAtOne,
                      bool editedCheckBox = false);

    ~ThresholdAdjuster() override;
    void setAdjusterListener(ThresholdAdjusterListener *alistener)
    {
        adjusterListener = alistener;
    }

    void setBgCurveProvider(ThresholdCurveProvider *provider);
    ThresholdSelector *getThresholdSelector() { return &tSelector; };

    template <typename T> rtengine::procparams::Threshold<T> getValue()
    {
        return tSelector.getPositions<T>();
    }
    void getValue(double &bottom, double &top);
    void getValue(double &bottomLeft, double &topLeft, double &bottomRight,
                  double &topRight);
    void getValue(int &bottom, int &top);
    void getValue(int &bottomLeft, int &topLeft, int &bottomRight,
                  int &topRight);
    void getValue(Glib::ustring &bottom, Glib::ustring &top);
    void getValue(Glib::ustring &bottomLeft, Glib::ustring &topLeft,
                  Glib::ustring &bottomRight, Glib::ustring &topRight);
    template <class T>
    void setValue(const rtengine::procparams::Threshold<T> &tValues)
    {
        tSelector.setPositions<T>(tValues);
    }
    void setValue(double bottom, double top);
    void setValue(double bottomLeft, double topLeft, double bottomRight,
                  double topRight);
    void setEnabled(bool enabled);
    template <typename T>
    void setDefault(const rtengine::procparams::Threshold<T> &tresh)
    {
        tSelector.setDefaults<T>(tresh);
    }
    void setDefault(double defBottom, double defTop);
    void setDefault(double defBottomLeft, double defTopLeft,
                    double defBottomRight, double defTopRight);
    void setEditedState(EditedState eState);
    EditedState getEditedState();
    void setDefaultEditedState(EditedState eState);
    void showEditedCB();
    void block(bool isBlocked) { blocked = isBlocked; }
    void setBgGradient(const std::vector<GradientMilestone> &milestones)
    {
        tSelector.coloredBar.setBgGradient(milestones);
    }
    void setBgColorProvider(ColorProvider *cp, int i)
    {
        tSelector.coloredBar.setColorProvider(cp, i);
    }
    void setUpdatePolicy(eUpdatePolicy policy)
    {
        tSelector.setUpdatePolicy(policy);
    }

    void setActive(bool b, bool t) { tSelector.setActive(b, t); }

    // void spinChanged ();
    void selectorChanged();
    bool notifyListener();
    void resetPressed(GdkEventButton *event);
    void editedToggled();
    Glib::ustring getHistoryString();
    void set_tooltip_markup(const Glib::ustring &markup);
    // this set_tooltip_text method is to set_tooltip_markup, and text can
    // contain markups
    void set_tooltip_text(const Glib::ustring &text);
};

#endif
