/* 
 * RangeEditDialog.cpp - Rangefile editor dialog
 * Copyright (C) 2018, D Haley
 * 
 * This program 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.
 * 
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef RANGEEDITDIALOG_H
#define RANGEEDITDIALOG_H

#include <wx/wx.h>
#include <wx/image.h>

// begin wxGlade: ::dependencies
#include <wx/splitter.h>
#include <wx/listctrl.h>
#include <wx/notebook.h>
#include <wx/grid.h>
// end wxGlade


#include <map>
#include <set>
#include <string>

//#include "wx/checkedlistctrl.h"

#include "backend/plot.h"
#include "../mathglPane.h"

#include "backend/APT/abundanceParser.h"

class PendingRange
{
	private:
		//are the start/second entries valid?
		bool validStart,validEnd, validParent;
		//Start and end of the range
		float start,end;
		//Parent ion id
		size_t parentId;

		//Range file that "owns" this pending range
		RangeFile *rngPtr;
public:
		PendingRange(RangeFile *parentRange);
		//Obtain the range file that owns this pending range
		RangeFile *getRangePtr() const { return rngPtr;}

		//Set the end of the range
		void setEnd(float f) { end=f; validEnd=true;}
		
		//Set the Start of the range
		void setStart(float f) { start=f;validStart=true;}
		//Set the parent ion in the owning rangefile
		void setParentId(size_t v) {ASSERT(v < rngPtr->getNumIons()); parentId=v; validParent=true;}

		//Returns true if all the data set for the pending range is valid
		bool isFinished() const;

		//Applies the changes to the parent rangefile
		void commit();

		//obtain range start
		float getStart() const;
		//obtain range  end
		float getEnd() const;
		//obtain range parent ion name 
		std::string getIonName() const;
};

class PendingIon
{
	private:
		//Range file that will own the ion when added
		RangeFile *rngPtr;
			
		//Range colour
		RGBf colour;
		//Short and long names for this ion
		std::string shortName, longName;
		//True if these values have been set and are valid when commited to the rangefile
		bool validColour, validShortName,validLongName;
	public:
		PendingIon(RangeFile *r);
		
		RangeFile *getRangePtr() const { return rngPtr;}
		//Set the colour of the pending ion, and set validity
		void setColour(const RGBf &r);
		//Obtain a colour for the ion (the set if valid, or a default)
		RGBf getColour() const;
		//obtain the short name for the ion, or a default (may be empty)
		std::string getShortName() const;
		//Set the short name for the ion, and set validity
		void setShortName(const std::string &newName);

		//obtain the long name for the ion, or a default (may be empty)
		std::string getLongName() const;
		//Set the long name for the ion, and set validity
		void setLongName(const std::string &newName);

		//True if the ion is fully valid
		bool isFinished() const;
		
		//Commit the pending ion to the rangefile
		void commit() const;
};


class RangeEditorDialog: public wxDialog {
public:
    // begin wxGlade: RangeEditorDialog::ids
    // end wxGlade

    RangeEditorDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE);

private:
    bool haveSetTextFocus;
    // begin wxGlade: RangeEditorDialog::methods
    void set_properties();
    void do_layout();
    // end wxGlade
		
    std::map<int,size_t> listToPlotIDs;

    //Store the mapping between grid offsets and the 
    // ionID (2nd in pair) for the current range
    std::map<size_t,size_t > gridIonIds,gridRangeIds;

    //Currently selected range
    RangeFile *currentRange;

    //Map original range file filiter to new modified rangefile
    // modified rangefiles data is stored here
    std::map<const RangeFileFilter *, RangeFile> modifiedRanges;

    //Mapping of plot ID -> rangefile filter, for ranges that have their own parent
    std::map<size_t ,const RangeFileFilter*> plotToRangeFileMap;

    //Plots that exist, but do not have a range mapping
    std::set<size_t> ignoreList;
 
    //Mapping of plot ID -> rangefile 
    std::map<size_t, RangeFile> plotNewRanges;

    //Row value for range/ion entries that the user has not fully completed
    std::vector<PendingRange> incompleteRanges;
    std::vector<PendingIon> incompleteIons;
   
    //position in incomplete ion offset where the normal ranges/ions finish 
    // and the Pending(Range/Ion)s start.
    size_t incompleteRangeOffset,incompleteIonOffset;
    //Plot data that contains information about plots to show, and
    // through that the original range information
    PlotWrapper plotWrap;

    size_t lastFocused;

    //Blocker variable to allow functions to bail out
    // during programatically generated events
    bool programmaticEvent;
  

    AbundanceData abundanceData;

    void setCurrentRange(size_t forceSelected=-1);
    
    void generateListEntries();
    //Generate (and set) the current plot region data from stored rangefile info
    void generatePlotRegions();

    //Generate the list of overlays
    void generateOverlayList(const std::vector<OVERLAY_DATA> &overlays) ;

    //Rebuild the range entry grid
    void generateRangeEntries(size_t rowVisibleHint=(size_t)-1);
    //Rebuild the ion entry grid
    void generateIonEntries(size_t rowVisibleHint=(size_t)-1);
protected:
    // begin wxGlade: RangeEditorDialog::attributes
    wxListBox* listPlots;
    wxPanel* noteLeftPlots;
    wxGrid* gridRanges;
    wxGrid* gridIons;
    wxButton* btnRangeIonAdd;
    wxButton* btnRangeIonRemove;
    wxPanel* noteLeftRanges;
    wxCheckBox* checkShowOverlay;
    wxTextCtrl* textOverlayCmpnt;
    wxCheckListBox* listOverlay;
    wxPanel* noteLeftOverlay;
    wxNotebook* notebookLeft;
    wxPanel* panelSplitLeft;
    MathGLPane* plotPanel;
    wxButton* btnOK;
    wxButton* btnCancel;
    wxPanel* panelSplitRight;
    wxSplitterWindow* splitVertical;


    void setRangeReady();
    // end wxGlade

    DECLARE_EVENT_TABLE();

public:
    virtual void OnListPlots(wxCommandEvent &event); // wxGlade: <event_handler>
    virtual void OnGridRangesCellChange(wxGridEvent &event); // wxGlade: <event_handler>
    virtual void OnGridRangeClick(wxGridEvent &event); // wxGlade: <event_handler>
    virtual void OnGridIonClick(wxGridEvent &event); // wxGlade: <event_handler>
    virtual void OnGridRangesEditorShown(wxGridEvent &event); // wxGlade: <event_handler>
    virtual void OnGridIonsEditorShown(wxGridEvent &event); // wxGlade: <event_handler>
    virtual void OnGridIonsCellChange(wxGridEvent &event); // wxGlade: <event_handler>
    virtual void OnBtnRangeIonAdd(wxCommandEvent &event); // wxGlade: <event_handler>
    virtual void OnBtnRangeIonRemove(wxCommandEvent &event); // wxGlade: <event_handler>
    virtual void OnCheckShowOverlay(wxCommandEvent &event); // wxGlade: <event_handler>
    virtual void OnBtnOK(wxCommandEvent &event); // wxGlade: <event_handler>
    virtual void OnBtnCancel(wxCommandEvent &event); // wxGlade: <event_handler>
    virtual void OnSashVerticalDClick(wxSplitterEvent &event); // wxGlade: <event_handler>
    virtual void OnListOverlayCheck(wxCommandEvent &event);
    virtual void OnListOverlayKeyDown(wxListEvent &event);
    virtual void OnTextOverlay(wxCommandEvent &event);
    virtual void OnTextOverlayEnter(wxCommandEvent &event);
    virtual void OnTextOverlaySetFocus(wxFocusEvent &event);
    void onPlotUpdate();
    void setPlotWrapper(const PlotWrapper &p);
  
    //Obtain a pointer to the modified range. The pointer is only valid for the lifetime of the dialog
    void getModifiedRanges(std::map<const RangeFile *, const RangeFile *> &modRanges) const;

    virtual ~RangeEditorDialog();

}; // wxGlade: end class


#endif // RANGEEDITDIALOG_H
