/*
 *  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/>.
 *  2018 Pierre Cabrera <pierre.cab@gmail.com>
 */

#ifndef _CONTROLSPOTPANEL_H_
#define _CONTROLSPOTPANEL_H_

#include <memory>

#include "../rtengine/coord.h"
#include "editcallbacks.h"
#include "threadutils.h"
#include "toolpanel.h"
#include "adjuster.h"

class ControlPanelListener
{
public:
    ControlPanelListener() {};
    virtual ~ControlPanelListener() {};

    virtual void resetToolMaskView() = 0;
    virtual void spotNameChanged(const Glib::ustring &newName) = 0;
};


class ControlSpotPanel:
    public ToolParamBlock,
    public AdjusterListener,
    public EditSubscriber,
    public FoldableToolPanel
{
public:
    /**
     * A SpotRow structure allows exchanges from and to ControlSpotClass
     */
    struct SpotRow {
        Glib::ustring name;
        bool isvisible;
        int prevMethod; // 0 = Normal, 1 = Excluding
        int shape; // 0 = Ellipse, 1 = Rectangle
        int spotMethod; // 0 = Normal, 1 = Excluding
        int sensiexclu;
        int structexclu;
        int shapeMethod; // 0 = Independent (mouse), 1 = Symmetrical (mouse), 2 = Independent (mouse + sliders), 3 = Symmetrical (mouse + sliders)
        int avoidgamutMethod;
        int locX;
        int locXL;
        int locY;
        int locYT;
        int centerX;
        int centerY;
        int circrad;
        int qualityMethod; // 0 = Standard, 1 = Enhanced, 2 = Enhanced + chroma denoise
        double transit;
        double transitweak;
        double transitgrad;
        double feather;
        double struc;
        double thresh;
        double iter;
        double balan;
        double balanh;
        double colorde;
        double colorscope;
        double avoidrad;
        bool hishow;
        bool activ;
        bool blwh;
        bool recurs;
        bool laplac;
        bool deltae;
        int scopemask;
        double denoichmask;
        bool shortc;
        int lumask;
        //bool savrest;
        int complexMethod; // 0 = Simple, 1 = Moderate, 2 = all
        int wavMethod; // 0 = D2, 1 = D4, 2 = D6, 3 = D10, 4 = D14
    };

    /**
     * An event type enumeration allows exchanges of spot panel event type from and to ControlSpotClass
     */
    enum eventType {
        None = 0,
        SpotCreation = 1,
        SpotDeletion = 2,
        SpotSelection = 3,
        SpotDuplication = 4,
        SpotAllVisibilityChanged = 5
    };

    // Constructor and management functions
    /**
     * Default constructor of ControlSpotPanel class
     */
    ControlSpotPanel();
    /**
     * Destructor of ControlSpotPanel class
     */
    ~ControlSpotPanel();
    /**
     * Implementation of setEditProvider function of toolpanel.h
     *
     * @param provider The EditDataProvider to be linked to the panel to manage curves
     */
    void setEditProvider(EditDataProvider* provider) override;
    /**
     * Setter for controlPanelListener
     *
     * @param cpl The ControlPanelListener to be linked to the panel
     */
    void setControlPanelListener(ControlPanelListener* cpl)
    {
        controlPanelListener = cpl;
    }
    /**
     * Getter of the event type raised by this panel
     *
     * @return The raised event type (refer to eventType enumeration)
     */
    int getEventType();
    /**
     * Getter of params of associated spot
     *
     * @param index The spot index to get params
     * @return A SpotRow structure containing params of associated spot
     */
    std::unique_ptr<SpotRow> getSpot(const int index);
    /**
     * Getter of spots number
     *
     * @return The number of spots in panel
     */
    int getSpotNumber();
    /**
     * Getter of selected spot index
     *
     * @return The index of selected spot in treeview (return -1 if no selected spot)
     */
    int getSelectedSpot();
    /**
     * Setter of selected spot
     *
     * @param index The index of spot to be selected
     * @return True if a spot corresponding to the index has been selected
     */
    bool setSelectedSpot(const int index);
    /**
     * Setter for mask preview active indicator
     *
     * @param ind True is mask preview is active
     */
    void setMaskPrevActive(bool ind)
    {
        maskPrevActive = ind;
    }
    /**
     * Getter for deltaE preview active
     *
     * @return True if preview deltaE is active
     */
    bool isDeltaEPrevActive();
    /**
     * Reset deltaE preview active state
     */
    void resetDeltaEPreview();

    // Control spot creation functions
    /**
     * Add a new spot (and its associated curve)
     *
     * @param newSpot A SpotRow structure containing new spot params
     */
    void addControlSpot(const SpotRow &newSpot);

    // Control spot delete function
    /**
     * Delete a spot (and its associated curve)
     *
     * @param id The id of the spot to be deleted
     */
    void deleteControlSpot(const int index);

    // Panel widgets management functions
    /**
     * Implementation of setDefaults function of toolpanel.h
     *
     * @param defParams ProcParams containing default values to set to the adjusters
     * @param pedited ParamsEdited containing default state values to set to the adjusters (not used because batch mode is deactivated for Locallab)
     */
    void setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override;
    /**
     * Enable or disable the interactions with panel widgets
     *
     * @param cond Condition to enable interactions
     */
    void setParamEditable(bool cond);
    /**
     * Reset expander collapse state to default one
     */
    void setDefaultExpanderVisibility();

    // Batch mode management
    // Note: Batch mode is deactivated for Locallab

private:
    // Cell renderer
    void render_name(Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter);
    void render_isvisible(Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter);

    void on_button_add();
    void on_button_delete();
    void on_button_duplicate();
    void on_button_rename();
    bool on_button_visibility(GdkEventButton* event);

    bool blockTreeviewSearch(GdkEventKey* event);
    bool onSpotSelectionEvent(GdkEventButton* event);

    void load_ControlSpot_param();

    void controlspotChanged();

    void prevMethodChanged();
    void shapeChanged();
    void spotMethodChanged();
    void shapeMethodChanged();
    void qualityMethodChanged();
    void avoidgamutMethodChanged();
   //void complexMethodChanged();
    void wavMethodChanged();

    void updateParamVisibility();

    void adjusterChanged(Adjuster* a, double newval) override;

    void hishowChanged();
    void activChanged();
    void blwhChanged();
    void recursChanged();
    void laplacChanged();
    void deltaeChanged();
    void shortcChanged();
    //void savrestChanged();

    void previewChanged();

    void disableParamlistener(bool cond);

    void addControlSpotCurve(Gtk::TreeModel::Row& row);
    void updateControlSpotCurve(const Gtk::TreeModel::Row& row);
    void deleteControlSpotCurve(Gtk::TreeModel::Row& row);
    void updateCurveOpacity(const Gtk::TreeModel::Row& selectedRow);
    CursorShape getCursor(int objectID, int xPos, int yPos) const override;
    bool mouseOver(int modifierKey) override;
    bool button1Pressed(int modifierKey) override;
    bool button1Released() override;
    bool drag1(int modifierKey) override;

    using ToolPanel::setDefaults;

    class ControlSpots:
        public Gtk::TreeModel::ColumnRecord
    {
    public:
        ControlSpots();

        Gtk::TreeModelColumn<bool> mouseover; // Used to manage spot enlightening when mouse over
        Gtk::TreeModelColumn<Glib::ustring> name;
        Gtk::TreeModelColumn<bool> isvisible;
        Gtk::TreeModelColumn<int> curveid; // Associated curve id
        Gtk::TreeModelColumn<int> prevMethod; // 0 = hide, 1 = show
        Gtk::TreeModelColumn<int> shape; // 0 = Ellipse, 1 = Rectangle
        Gtk::TreeModelColumn<int> spotMethod; // 0 = Normal, 1 = Excluding
        Gtk::TreeModelColumn<int> sensiexclu;
        Gtk::TreeModelColumn<int> structexclu;
        Gtk::TreeModelColumn<int> shapeMethod; // 0 = Independent (mouse), 1 = Symmetrical (mouse), 2 = Independent (mouse + sliders), 3 = Symmetrical (mouse + sliders)
        Gtk::TreeModelColumn<int> avoidgamutMethod;
        Gtk::TreeModelColumn<int> locX;
        Gtk::TreeModelColumn<int> locXL;
        Gtk::TreeModelColumn<int> locY;
        Gtk::TreeModelColumn<int> locYT;
        Gtk::TreeModelColumn<int> centerX;
        Gtk::TreeModelColumn<int> centerY;
        Gtk::TreeModelColumn<int> circrad;
        Gtk::TreeModelColumn<int> qualityMethod; // 0 = Standard, 1 = Enhanced, 2 = Enhanced + chroma denoise
        Gtk::TreeModelColumn<double> transit;
        Gtk::TreeModelColumn<double> transitweak;
        Gtk::TreeModelColumn<double> transitgrad;
        Gtk::TreeModelColumn<double> feather;
        Gtk::TreeModelColumn<double> struc;
        Gtk::TreeModelColumn<double> thresh;
        Gtk::TreeModelColumn<double> iter;
        Gtk::TreeModelColumn<double> balan;
        Gtk::TreeModelColumn<double> balanh;
        Gtk::TreeModelColumn<double> colorde;
        Gtk::TreeModelColumn<double> colorscope;
        Gtk::TreeModelColumn<double> avoidrad;
        Gtk::TreeModelColumn<bool> hishow;
        Gtk::TreeModelColumn<bool> activ;
        Gtk::TreeModelColumn<bool> blwh;
        Gtk::TreeModelColumn<bool> recurs;
        Gtk::TreeModelColumn<bool> laplac;
        Gtk::TreeModelColumn<bool> deltae;
        Gtk::TreeModelColumn<int> scopemask;
        Gtk::TreeModelColumn<int> denoichmask;
        Gtk::TreeModelColumn<bool> shortc;
        Gtk::TreeModelColumn<int> lumask;
        //Gtk::TreeModelColumn<bool> savrest;
        Gtk::TreeModelColumn<int> complexMethod; // 0 = Simple, 1 = mod, 2 = all
        Gtk::TreeModelColumn<int> wavMethod; // 0 = D2, 1 = D4, 2 = D6, 3 = D10, 4 = D14
    };

    class RenameDialog:
        public Gtk::Dialog
    {
    public:
        enum DialogButton {
            OkButton = 1,
            CancelButton = 2
        };

        RenameDialog(const Glib::ustring &actualname, Gtk::Window &parent);
        Glib::ustring get_new_name();

    private:
        Gtk::Entry* const newname_;
    };

    ControlSpots spots_;
    rtengine::ProcEvent EvLocallabavoidgamutMethod;

    // Child widgets
    Gtk::ScrolledWindow* const scrolledwindow_;
    Gtk::TreeView* const treeview_;
    sigc::connection treeviewconn_;
    Glib::RefPtr<Gtk::ListStore> treemodel_;

    Gtk::Button* const button_add_;
    sigc::connection buttonaddconn_;
    Gtk::Button* const button_delete_;
    sigc::connection buttondeleteconn_;
    Gtk::Button* const button_duplicate_;
    sigc::connection buttonduplicateconn_;

    Gtk::Button* const button_rename_;
    sigc::connection buttonrenameconn_;
    Gtk::Button* const button_visibility_;
    sigc::connection buttonvisibilityconn_;


    MyComboBoxText* const prevMethod_;
    sigc::connection prevMethodconn_;
    MyComboBoxText* const shape_;
    sigc::connection shapeconn_;
    MyComboBoxText* const spotMethod_;
    sigc::connection spotMethodconn_;
    MyComboBoxText* const shapeMethod_;
    sigc::connection shapeMethodconn_;
    MyComboBoxText* const qualityMethod_;
    sigc::connection qualityMethodconn_;
    //MyComboBoxText* const complexMethod_;
    //sigc::connection complexMethodconn_;
    MyComboBoxText* const wavMethod_;
    sigc::connection wavMethodconn_;
    MyComboBoxText* const avoidgamutMethod_;
	sigc::connection avoidgamutconn_;

    Adjuster* const sensiexclu_;
    Adjuster* const structexclu_;
    Adjuster* const locX_;
    Adjuster* const locXL_;
    Adjuster* const locY_;
    Adjuster* const locYT_;
    Adjuster* const centerX_;
    Adjuster* const centerY_;
    Adjuster* const circrad_;
    Adjuster* const transit_;
    Adjuster* const transitweak_;
    Adjuster* const transitgrad_;
    Adjuster* const feather_;
    Adjuster* const struc_;
    Adjuster* const thresh_;
    Adjuster* const iter_;
    Adjuster* const balan_;
    Adjuster* const balanh_;
    Adjuster* const colorde_;
    Adjuster* const colorscope_;
    Adjuster* const avoidrad_;
    Adjuster* const scopemask_;
    Adjuster* const denoichmask_;
    Adjuster* const lumask_;

    Gtk::CheckButton* const hishow_;
    sigc::connection hishowconn_;
    Gtk::CheckButton* const activ_;
    sigc::connection activConn_;
    Gtk::CheckButton* const blwh_;
    sigc::connection blwhConn_;
    Gtk::CheckButton* const recurs_;
    sigc::connection recursConn_;
    Gtk::CheckButton* const laplac_;
    sigc::connection laplacConn_;
    Gtk::CheckButton* const deltae_;
    sigc::connection deltaeConn_;
    Gtk::CheckButton* const shortc_;
    sigc::connection shortcConn_;
    //Gtk::CheckButton* const savrest_;
    //sigc::connection savrestConn_;

    MyExpander* const expTransGrad_;
    MyExpander* const expShapeDetect_;
    MyExpander* const expSpecCases_;
    MyExpander* const expMaskMerge_;

    Gtk::ToggleButton* const preview_;
    sigc::connection previewConn_;

    Gtk::Box* const ctboxshape;
    Gtk::Box* const ctboxshapemethod;
    Gtk::Box* const ctboxgamut;

    // Internal variables
    ControlPanelListener* controlPanelListener;
    int lastObject_;
    rtengine::Coord lastCoord_;
    bool nbSpotChanged_;
    bool selSpotChanged_;
    bool nameChanged_;
    bool visibilityChanged_;
    int eventType; // 0 = No event, 1 = Spot creation event, 2 = Spot deletion event, 3 = Spot selection event, 4 = Spot duplication event
    Gtk::Frame* const excluFrame;
    bool maskPrevActive;

    // Row background color
    Gdk::RGBA colorMouseover, colorNominal, colorMouseovertext;

    // Treeview mutex
    MyMutex mTreeview;
};

#endif // _CONTROLSPOTPANEL_H_
