//  DataSelector.h
//
// Data Selection Widget
//
// March 2009: Tony Allen
//

#ifndef DATA_SELECTOR_H 
#define DATA_SELECTOR_H

#include <iostream>
#include <string>
#include <vector>

#include <QObject>
#include <QSplitter>
#include <QTextEdit>
#include <QPainter>
#include <QProgressBar>
#include <QDateTime>
#include <QInputDialog>
#include <QTimer>
#include <QListWidget>
#include <QFileInfo>
#include <QTreeWidget>
#include <QTreeWidgetItem>
#include <QMutex>
#include "qie_caa.h"
#include "qgu_qt4.h"
#include "qt_version.h"

#include "Viostream.h"
#include "QbTimeEditors.h"
#include "Xrefs.h"

#include "StringRep.h"

class DataSelectorWindow;

class DataSelectionListView;
class DataSelectionItem;

class DataBaseListView;
class DataBaseItem;
class AvailabilityWidget;

class DataFileListDialog;
class DB_Manager;

typedef enum LviType_e { LVI_FOLDER, LVI_VARIABLE }LviType;

class DataSelectionFilter:public QObject
{
    protected:
        bool eventFilter(QObject* object, QEvent* event)
        {
            return false;
        }
};

// container classes
// -----------------

// class dirListEntry
// ---------------------     list of files in dir and mod dates

class dirFileList
{
	public:
		dirFileList(){;}
		~dirFileList(){fileName.clear(); tFile.clear();}
		bool getFilesInDir(const char *target_dir);
		bool nameFound(string &fileN);
		vector <string> fileName;
		vector <QDateTime> tFile;
};


// class dataFetchEntry
// ---------------------     list of files in tivl and list of vars to get

class dataFetchEntry
{
	public:
		dataFetchEntry(){;}
		~dataFetchEntry(){fileList.clear(); toFetchList.clear();}
		void copyFrom(dataFetchEntry &entry);
		vector <string> fileList;
		vector <string> toFetchList;
};

typedef vector<dataFetchEntry> dataFetchList;

// class variableEntry
// ---------------------     name of variable and tivl 

class variableEntry
{
	public:
		variableEntry(){;}
		~variableEntry(){start.clear(); end.clear();}
		string variableName;
		vector <double> start;
		vector <double> end;
};

typedef vector<variableEntry> variableList;

// class mapEntry
// ---------------------     name of file and list of variable entries for it

class mapEntry
{
	public:
		mapEntry(){;}
		~mapEntry(){varList.clear();}
		string fileName;
		variableList varList;
};
typedef vector<mapEntry> mapList;

// class dataEntry
// ---------------------     Inverse of mapEntry, variable name and list of files and intervals

class dataEntry
{
	public:
		dataEntry(){;}
		~dataEntry(){fileName.clear(); start.clear(); end.clear();}
		void copyFrom(const dataEntry &entry);
		string variableName;
		vector<string> fileName;
		vector <double> start;
		vector <double> end;
		double db_start;
		double db_end;
};

// class dataList
//---------------

class dataList
{
	public:
		dataList(){;}
		~dataList(){vEntry.clear();}
		int locate(string vName);
		vector <dataEntry> vEntry;
};



// Class DataSelector
// ------------------

class DataSelector : public QWidget {
 
    private:

        Q_OBJECT

		int da_bins;
        QSplitter* _top_splitter;
        QGridLayout* _top_gl;

        QLabel* _data_coverage;

        friend class DataSelectionItem;

    public slots:

        void add_to_selection_list();
        void remove_from_selection_list();
        void clear_selection_list();
        void update_database_selection();
        void update_data_availability();
        void time_updated();
        void data_availability_clicked(int section){;}
        void get_data();
		void set_time_interval();
		void issueInterrupt();

    signals:
        void time_checked();
        void setInterval(double ts, double te);

    public:
        DataSelector( QWidget *parent=0, const char *name=0 );
	
		void add_item_to_selection(DataBaseItem* node);
		bool read_database(const char *db_filename);
		void set_def_db();
		string write_db(vector <string> &db_entry_list, const char *title);
		void open_database();
		bool getVarList(vector <string> &fileList, vector <string> &varToGetList, QmjdTimeInterval &tintv, vector <QdObject_var> &objList);
		void disableInterrupt();
		void activateInterrupt(const char *txt);
		bool isInterrupted(const char *txt);
		void resetButtons(bool turnOff);

		TimeIntervalWidget* _time_editor;
		DataBaseListView* _database_listview;
		DataSelectionListView* _data_selection_listview;
		QLabel *progressBarLbl;
		QProgressBar *progressBar;
		string db_dir;
		DataSelectorWindow *DSwindow;
		DB_Manager *managerTab;
		string def_db_dir;
		bool interruptFlag;
		int nFolder;

		QPushButton *quit;
		QPushButton *interrupt;
		QPushButton* _add_button;
		QPushButton* _remove_button;
		QPushButton* _clear_button;
		QPushButton* _get_data_button;
};

// Class DataSelectorWindow
// ------------------------

class DataSelectorWindow : public QguWindow {

    Q_OBJECT

    public:
        DataSelectorWindow(QWidget *parent=0, const char *name=0 );
        ~DataSelectorWindow(){;}
        virtual void save(Vostream&);
        virtual void restore(Vistream& v_is,bool replace=true);
	void read_map_entries(mapList &map_listing, VBistream &b_is);
	bool create_db_entries(const char *target_dir, const char *db_dir, vector <string> &db_entry_list);
	void getFileMapEntries(string &fileName, variableList &varList);
	string update_map_file(const char *existingMapName, const char *dirName, const char *db_dir);
	bool write_map_contents(vector <string> &file_list, mapList &map_listing, const char *mapName);
	string write_map_file(const char *target_dir, const char *db_dir);
	bool file_exists(const char *pathName, const char *fileName);
	string altMapName(const char *target_dir);

	DataSelector* _data_selector;
	QMenu* database_menu;
	
    public slots:
        void save();
        void saveAs();
        void saveSession(QString);
        void saveAsXML();
        void restoreXML(bool replace=true);
        void open_database();
        void close_database();
        void reload(){ ;}
        void launch_QSAS_Help();
        void launch_DS_Help();
        void create_database();

    signals:
		
};

// Class DataBaseListView
// ------------------------

class DataBaseListView: public QTreeWidget
{
	Q_OBJECT

	public:
		DataBaseListView(QWidget* parent=0);
		virtual ~DataBaseListView(){}
		DataSelector* _data_selector;
		QLinkedList<DataBaseItem*> getChildren();
		QLinkedList<DataBaseItem*> getSelectedDBs();
        DataBaseItem* findItemById(const int id);
        bool dropOn(QDropEvent *event, int *dropRow, int *dropCol, QModelIndex *dropIndex);

	public slots:
		void show_files();
		void sortUp();
		void sortDown();
		void deleteItem();
		void doubleClick(QTreeWidgetItem* item, int);
        void updateWidgets();

	protected:
		virtual void mousePressEvent(QMouseEvent*);

        virtual QMimeData* mimeData(const QList<QTreeWidgetItem*> items) const;
        virtual QStringList mimeTypes() const;
        virtual void dropEvent(QDropEvent* event);

        virtual void paintEvent(QPaintEvent* event);

//         virtual void drawRow(QPainter* painter, const QStyleOptionViewItem & option, const QModelIndex& index) const;

		QMenu* menu;
        
	protected slots:
		void selectionChanged ( const QItemSelection & selected, const QItemSelection & deselected );
        
};

// Class DataBaseItem
// ------------------

class DataBaseItem: public QTreeWidgetItem
{
	friend class AvailabilityWidget;
	
	public:
		DataBaseItem(LviType _type, QTreeWidget* parent, const string& name);

		DataBaseItem(LviType _type, QTreeWidgetItem* parent, const string& name);
        
		virtual ~DataBaseItem();

        void updateWidget();

        void recursiveUpdateWidget();

		bool removeEmptyFolders();
		
		void read_map(string fileName);

		DataBaseItem* findChildByName(const string& db_name);
        
		void getTimeRange(double &start, double &end);

		void appendChildrenTo(QLinkedList<DataBaseItem*>& list);

		void show_files();
        
		void get_files(const QmjdTimeInterval &tivl, vector<string> &fnames);
		void getDBentries(vector <string> &db_entry_list);
		
		DataBaseItem* rootItem;
		void getSelectedFolders(vector<string>&);
		void getSubFolders(vector<string>&);
        DataBaseItem* findChildById(const unsigned int id);

		string mapName;
		string fullPathAndName;
		string DB_NameAndPath;
		LviType db_item_type;
        dataEntry databaseEntry;
        DataFileListDialog* _filelist_dialog;
		
        static unsigned int item_counter;
        unsigned int item_id; // identifies the item
        bool hasWidget;
	protected:

		AvailabilityWidget* widget;
};

class AvailabilityWidget: public QWidget
{
	Q_OBJECT

    friend class DataBaseItem;

	public:
		AvailabilityWidget(DataBaseItem* item, QWidget* parent=0);

		virtual ~AvailabilityWidget();

		DataBaseItem* item;

//     signals:


    public slots:

        inline void setInterval(double ts, double te)
        {
            this->ts=ts;
            this->te=te;
            recompute();
        }
        
	protected:

		virtual void paintEvent(QPaintEvent*);
		virtual void resizeEvent(QResizeEvent*);

		void recompute();
        QMutex mutex;
		QPixmap pix;
        double te, ts;
};


// Class DataSelectionListView
// ---------------------------

class DataSelectionListView: public QTreeWidget
{
	Q_OBJECT

	public:
		DataSelectionListView(DataSelector* data_selector, QWidget* parent=0);
		bool add_item(DataBaseItem * db_item);
		DataSelector* _data_selector;

	protected:
        virtual void dragEnterEvent(QDragEnterEvent *event);
        virtual void dropEvent(QDropEvent* event);
		virtual void mousePressEvent(QMouseEvent*);
		QMenu* menu;

	public slots:
		void show_data_info();
		void show_data_coverage();
};


// Class DataSelectionItem
// -----------------------

class DataSelectionItem: public QTreeWidgetItem
{
	public:

		DataSelectionItem(DataSelectionListView* parent, DataBaseItem* db_item);
		DataSelectionItem( DataSelectionListView* parent, const char * name, const char* source);

		virtual ~DataSelectionItem(){}

		int get_data_coverage(QmjdTimeInterval  &time_interval);
		void get_data_info( string& info_txt);
		void get_files(const QmjdTimeInterval &tivl, vector<string> &fnames);
		string mapName;
		dataEntry databaseEntry;
		
	protected:
		
};

// Class DataFileListDialog
// -----------------------

class DataFileListDialog: public QDialog
{
    Q_OBJECT

    public:
	DataFileListDialog( DataBaseItem *item, QWidget *parent=0, const char *name=0);
        virtual ~DataFileListDialog() { killTimer(timer_id); _filelist_listview->clear();}
        void hideEvent(QHideEvent *e) { ;}
		
		DataBaseItem* DB_item;
        int timer_id;
		QListWidget* _filelist_listview;

	void setNumFiles(int n);
		
    protected:
        virtual void timerEvent(QTimerEvent *e)
        {
            if(parentWidget()!=NULL)
            {
                if(!parentWidget()->isVisible()) hide();
            }
        }

	QLabel *dcmfile_label;
		
    public slots:
        void done(int r) { hide(); setResult(r);}
        void accept() { done(Accepted);}
        void reject() { done(Rejected);}
        void browse_metadata( Q3ListViewItem *);
	void browse_metadata( QListWidgetItem *);
		void show_current_meta();
    
};


// Class DB_Manager
// ------------------------

class DB_Manager : public QWidget {

    Q_OBJECT


    public:
        DB_Manager(QWidget *parent=0, const char *db_name=0 );
        ~DB_Manager(){;}
		void addFolderToDB(const char *data_dir, vector <string> &db_entry_list, const char *db_dir);

		void deleteFoldersFromDB(vector <string> &folders, vector <string> &db_entry_list, DataBaseItem *db_item);

        QPushButton * db_erase;
        QPushButton * db_clear;
        QPushButton * db_create;
		QPushButton * db_delete;
		QPushButton * db_update;
		QPushButton * db_add;
		QPushButton * db_remove;
		QPushButton * db_resave;
		
		DataBaseListView *_folder_listview;
		DataSelector *_data_selector;
		string data_dir;
		string def_data_dir;
		
    public slots:
		void updateDB();
		void createDB();
		void clearMaps();
		void removeFolder();
		void addFolder();
		void deleteDB();
		void eraseDB();	   
		void reSaveDB();
	   
    signals:
		
};

// class independent prototypes

bool loadMap(string mapName, mapList &map_listing);
bool isFileWritable(const char *fileName);
void writeDBfile(const char *dbFileName, vector <string> &db_entry_list);
bool fileExists(mapList &map_listing, const char *fileName);
QDateTime getFileModDate(const char * fileName);
int newFile(const char *fileName);
int getNumFolders(const char *data_dir);


#endif // QMenu
