//  DataSelector.h
//
// Data Selection Widget
//
// July 2000: David Burgess
//

#ifndef DATA_SELECTOR_H
#define DATA_SELECTOR_H

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

#include <QObject>
#include <QSplitter>
#include <QTextEdit>
#include <QPainter>
#include <QProgressDialog>
#include <QProgressBar>
#include <QDateTime>
#include <QInputDialog>
#include <QTimer>
#include <QListWidget>
#include "qgu_qt4.h"
#include "qt_version.h"
#include "KVDataBase.h"

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

#include "CDFDataBaseDataSource.h"
#include "CDFDataSource.h"
#include "StringRep.h"

#define DATABASE_DELIM "::/"
#define FILE_NAMES_XREF "File_Names"
#define OBJECT_NAME_XREF "Object_Name"

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

class DataSelectionListView;

class DataBaseListView;

class DataBaseListViewItem;

class DcmFileListViewItem;
class DcmDataSourceListViewItem;

class DataSelector : public QWidget {

    public:
        typedef enum LviType_e { LVI_FOLDER, LVI_DCM_FILE, LVI_DATASOURCENAME }
        LviType;
 
        typedef QDOS::NamingContext<QDOS::CDFDataBaseDataSource_var> DataBaseTable;
    private:

        Q_OBJECT

                DataBaseTable _database_table;
        QDOS::TimeInterval _database_tintv;
        int _open_dcm;
        bool _time_updated;

        QClipboard* _clipboard;

        QSplitter* _top_splitter;
#if QT_VERSION < 0x040000
        QGridLayout* _top_gl;
#else
        QGridLayout* _top_gl;
#endif
        QListWidget*  _data_files_list;
        QTextEdit* _data_info;
        QProgressBar* _data_coverage;
        QPushButton* _add_button;
        QPushButton* _remove_button;
        QPushButton* _clear_button;
        QPushButton* _get_data_button;
  
        int _davail_sz;
        QDOS::TimeSeq _davail_timeseq;
  
        friend class DataBaseListViewItem;
        friend class DataSourceFolderListViewItem;
        friend class DataSourceListViewItem;

    public slots:

        void item_double_click( Q3ListViewItem * item );
//         void copy_item_to_clipboard(DcmDataSourceListViewItem*); 
        void paste_item_from_clipboard();
        void add_to_selection_list();
        void remove_from_selection_list();
        void clear_selection_list();
        void update_database_selection();
        void update_selected_data_display();
        void update_data_availability();
        QDOS::CDFDataBaseDataSource_var read_database( const string& dcm_filename,bool read_dcm=false );
        void add_database( QDOS::CDFDataBaseDataSource_var );

        void data_availability_clicked(int section)
        {;}
        void popup_datasource_menu( Q3ListViewItem *, const QPoint &, int );
        void popup_dataselection_menu( Q3ListViewItem *, const QPoint &, int );
        void close_database();
        void get_data();
        void quit()
        { emit quit_signal();}
        void check_time();
        void time_updated()
        {
            if(!_time_updated) _time_updated=true;
        }

    signals:
        void quit_signal();
        void done_signal();
        void database_closed();
        void database_opened();
        void status_msg(const QString&);
        void time_checked();

    public:
        DataSelector( QWidget *parent=0, const char *name=0 );
    
        void add_database_folder_items(QDOS::DataNamesTable_var folder, DataBaseListViewItem* list_view_item_parent );
        void recursive_add_to_selection(Q_LIST_VIEW_ITEM* node);
        void add_item_to_selection( Q_LIST_VIEW_ITEM* node);
        QPixmap data_availability_pixmap(const vector<bool>& avail );
        void database_listview_expand(bool open);
        void recursive_expand(Q_LIST_VIEW_ITEM*,bool); 
        void close_database(DcmFileListViewItem*);
        void close_database(QDOS::CDFDataBaseDataSource_var);
        string binary_file(const string&);
        bool create_binary_file(const string&);
        void update_time();
        QDOS::CDFDataBaseDataSource_var get_database(const string& name);
        string database_name(const string& name);
        string database_name(QDOS::CDFDataBaseDataSource_var cdf_db)
        { if(cdf_db.is_nil())
            return "";
            string dcm_name;
            cdf_db->get_database_name(dcm_name);
            return database_name(dcm_name);
        }
  
        QbTimeIntervalEditor* _time_editor;
        DataBaseListView* _database_listview;
        DataSelectionListView* _data_selection_listview;
};


class DataSelectorWindow : public QguWindow {

    Q_OBJECT

            DataSelector* _data_selector;
  
    QAction* _close_menu_item;
    QAction* _create_menu_item;
    QAction* _merge_menu_item;
    QAction* _update_menu_item;
  
    public slots:
        void save();
        void saveAs();
        void saveSession(QString);
        void open_database();
        void update_database();
        void create_database();
        void create_dcm_entries(const string&, const string&,const string&);
        void merge_database();
        void database_closed();
        void database_opened();
        void reload(){ ;}
        void expand_tree();
        void collapse_tree();
        void launch_QSAS_Help();
        void launch_DS_Help();

        void done()
        { emit done_signal();}

    signals:
        void done_signal();

    public:
        DataSelectorWindow(QWidget *parent=0, const char *name=0 );
        ~DataSelectorWindow(){;}
        void open_database(const string& dcm_filename);
 
        virtual void save(Vostream&);
        virtual void restore(Vistream& v_is,bool replace=true);
   
};

// class DcmDataSourceDrag:public QDrag
// {
//     public:
//         DcmDataSourceDrag(const string& datasource_str, QWidget* parent=0, \
//                 const char* name=0): QDrag(parent)
//         { 
// 		QMimeData * mimeData=new QMimeData;
//             QByteArray data;
//             data.setRawData(datasource_str.c_str(),datasource_str.size()+1);
//             setEncodedData(data);
//             data.resetRawData(datasource_str.c_str(),datasource_str.size()+1);
//         }
//  
//         static bool decode(QDropEvent* event, QString& str)
//         {
//             QByteArray rawdata=event->data("text/plain");
//             str=rawdata.data();
//             event->accept();
//             return true;
//         }
// 
//         static bool canDecode(QDragMoveEvent* event)
//         { return event->provides("text/plain");}
// 
// };

class DataBaseListView:public Q_LIST_VIEW
{
    Q_OBJECT
            int _dragdropbutton;
    QPoint _presspos;
    QTimer* _timer;
    public:
        DataBaseListView( QWidget *parent=0, const char* name=0):Q_LIST_VIEW(parent,name)
        {
            _timer=new QTimer(this);
    //connect(_timer,SIGNAL(timeout()),this,SLOT(update_da()));
    // Drag and Drop
            _dragdropbutton=Qt::LeftButton;
    //if(style()==WindowsStyle)
    //  _dragdropbutton=LeftButton;
    //else
    //  _dragdropbutton=RightButton;
        }

//         void contentsMousePressEvent(QMouseEvent* event);
//         void contentsMouseMoveEvent(QMouseEvent* event);
        void hideEvent(QHideEvent *e)
        { ;}
  
    public slots:
        void resizeEvent ( QResizeEvent * );
        void update_da();
    signals:
        void da_resized();
};

class DataSelectionListView:public Q_LIST_VIEW
{
    Q_OBJECT
            DataSelector* _data_selector;
    public:
        DataSelectionListView(DataSelector* data_selector, \
                QWidget *parent=0, const char* name=0):_data_selector(data_selector),\
                Q_LIST_VIEW(parent,name)
                {setAcceptDrops(false);}

//                 void dragEnterEvent( QDragEnterEvent* event)
//                 {
//                     if(DcmDataSourceDrag::canDecode(event))
//                         event->accept();
//                 }
// 
//                 void dropEvent(QDropEvent* event);
   
                bool add_item(string& col0, string& col1, \
                        QDOS::CDFDataBaseDataSource_var cdf_db);
  
                void delete_database_entries(QDOS::CDFDataBaseDataSource_var cdf_db);
     
};

class DataSelectionListViewItem: public Q_LIST_VIEW_ITEM {
    QDOS::CDFDataBaseDataSource_var _cdf_db;
    string _datasource_name;
  
    public:
        DataSelectionListViewItem( DataSelectionListView* parent, const string& name,\
                const string& data_source,  QDOS::CDFDataBaseDataSource_var cdf_db ) 
    : Q_LIST_VIEW_ITEM(parent,name.c_str(),data_source.c_str()),\
                _cdf_db(cdf_db) 
                {
                    string database_delim=DATABASE_DELIM;
                    int pos=data_source.find(database_delim);
                    if(pos!=string::npos)
                        _datasource_name=data_source.substr(pos+database_delim.size());
                    if(_datasource_name.size()!=0)
                        _datasource_name=_datasource_name+"/"+name;
                    else
                        _datasource_name=name;
                }

                virtual ~DataSelectionListViewItem()
                {;}
 
                virtual QDOS::CDFDataBaseDataSource_var data_base()
                { return _cdf_db;}
  
                virtual string name() const
                { return _datasource_name;}
  
                QDOS::QdObject_var get_data(const QDOS::TimeInterval& time_interval);
        
                void get_files(const QDOS::TimeInterval& time_interval, \
                        vector<string>& fnames)
                {
                    if(!_cdf_db.is_nil())
                    {
                        try{
                            QDOS::DataNamesTable_var data_files=\
                                    _cdf_db->get_datafile_names(_datasource_name,time_interval);
                            if(!data_files.is_nil())
                                data_files->list_names_r(fnames,"/");
                        }
                        catch(QDOS::Exception& e)
                        {;}
                    }
                } 
  
                int get_data_coverage(const QDOS::TimeInterval& time_interval);
  
                void get_data_info(const QDOS::TimeInterval& time_interval,\
                        vector<string>& info_txt)
                {
                    if(!_cdf_db.is_nil())
                    {
                        try{
                            _cdf_db->get_data_info(_datasource_name,info_txt,time_interval);
                        }
                        catch(QDOS::Exception& e)
                        {;}
                    }
                } 

};

class DcmDialog: public QDialog
{
    Q_OBJECT
            QDOS::CDFDataBaseDataSource_var _datasource;

    public:
        DcmDialog(QDOS::CDFDataBaseDataSource_var cdf_db,\
                QWidget *parent=0, const char *name=0   );
    
        virtual ~DcmDialog()
        { killTimer(timer_id);}
      
        QDOS::CDFDataBaseDataSource_var datasource()
        { return _datasource;}

        void hideEvent(QHideEvent *e)
        { ;}
    
        int timer_id;

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

    public slots:
        void done( int r )
        {  hide();setResult(r);}
    
        void accept()
        { done(Accepted);}
    
        void reject()
        { done(Rejected);}

};
  
class DcmFileListDialog: public DcmDialog
{
    Q_OBJECT
            Q_LIST_VIEW* _filelist_listview;

    public:
        DcmFileListDialog( const string& dcmfile_name, \
                const vector<string>& file_names,  QDOS::CDFDataBaseDataSource_var cdf_db,\
                        QWidget *parent=0, const char *name=0   );
        virtual ~DcmFileListDialog()
        {;}

    public slots:
        void popup_file_menu( Q3ListViewItem *, const QPoint &,int );
    
};

class DataBaseListViewItem : public Q_LIST_VIEW_ITEM {
    DcmFileListDialog* _filelist_dialog;
    QDOS::CDFDataBaseDataSource_var _cdf_db;

    public:

        DataBaseListViewItem( Q_LIST_VIEW* parent, const string& name, \
                QDOS::CDFDataBaseDataSource_var cdf_db )
    : Q_LIST_VIEW_ITEM(parent,name.c_str()),\
                _cdf_db(cdf_db),_filelist_dialog(0) {;}
                DataBaseListViewItem( Q_LIST_VIEW_ITEM* parent, const string& name, \
                        QDOS::CDFDataBaseDataSource_var cdf_db )
    : Q_LIST_VIEW_ITEM(parent,name.c_str()),_cdf_db(cdf_db),
                       _filelist_dialog(0) {;}
  
                       virtual ~DataBaseListViewItem()
                       {
                           if(_filelist_dialog)
                           {
                               delete _filelist_dialog;
                               _filelist_dialog=0;
                           }
                       }

                       virtual DataSelector::LviType type() const=0;
                       virtual QDOS::CDFDataBaseDataSource_var data_base()
                       { return _cdf_db;}
  
                       virtual string name() const
                       {  
                           string ret_name;
                           DataBaseListViewItem* item_parent =
                                   dynamic_cast<DataBaseListViewItem*>( parent() );
                           if( item_parent )
                           {
                               if(item_parent->type()!=DataSelector::LVI_DCM_FILE)
                               {
                                   ret_name=item_parent->name();
                                   if(ret_name.size()!=0)
                                       ret_name+="/";
                               }
                           }
                           ret_name+=string(text(0).latin1());
                           return ret_name;
                       }
  
                       virtual string database_name() const
                       {  string ret_name;
                       DataBaseListViewItem* item_parent=
                               dynamic_cast<DataBaseListViewItem*>( parent() );
                       if( item_parent )
                           ret_name=item_parent->database_name();
                       return ret_name;
                       }   
          
                       virtual void show_files(const QPoint& p,const string& datasource="",\
                               const QDOS::TimeInterval& tintv=QDOS::TimeInterval()) 
                       {    
                           if(_filelist_dialog==NULL)
                           {
                               QDOS::CDFDataBaseDataSource_var cdf_db=data_base();
                               QDOS::DataNamesTable_var file_names; 
                               if(!cdf_db.is_nil())
                                   file_names=cdf_db->get_datafile_names(datasource,tintv);
                               vector<string> file_list;
                               if(!file_names.is_nil())
                                   file_names->list_names_r(file_list,"/");
                               _filelist_dialog=new DcmFileListDialog(database_name(),\
                                       file_list,data_base(),listView());
                               _filelist_dialog->setMinimumSize(_filelist_dialog->sizeHint());
                               QPalette palette = QPalette(qApp->palette());
                               _filelist_dialog->setPalette(palette);
                               _filelist_dialog->move(p);
                           }
     
                           _filelist_dialog->show();
                       }  
 
};

  
class DcmFileListViewItem : public DataBaseListViewItem {

    vector<string> file_list;
    public:

        DcmFileListViewItem( Q_LIST_VIEW* parent, const string& name, \
                QDOS::CDFDataBaseDataSource_var cdf_db );

        DataSelector::LviType type() const 
        { return DataSelector::LVI_DCM_FILE; }
    
        virtual string name() const
        {  string ret_name = string(text(0).latin1());
     //retname+=string(DATABASE_DELIM); 
        return ret_name; }
  
        virtual string database_name() const
        {   string ret_name = name(); return ret_name; }
 
};


class DcmFolderListViewItem : public DataBaseListViewItem {

    public:

        DcmFolderListViewItem( Q_LIST_VIEW_ITEM* parent, const string& name, \
                QDOS::CDFDataBaseDataSource_var cdf_db );

        DataSelector::LviType type() const
        { return DataSelector::LVI_FOLDER; }
};
  
  
class DcmMetaDataDialog: public DcmDialog
{
    Q_OBJECT

            QListWidget *metadata_listbox;
    QTextEdit *metadata_tv;
    string datasource_name;
    string _root_name;

    public:
        DcmMetaDataDialog( const string& data_name, \
                const vector<string>& mnames,  QDOS::CDFDataBaseDataSource_var cdf_var,\
                        QWidget *parent=0, const char *name=0   );

        virtual ~DcmMetaDataDialog()
        {;}

    public slots:    
        void show_meta_data();
    
};
  
class DcmBrowseDataDialog: public DcmDialog
{
    Q_OBJECT

            QComboBox *_num_entries_cb;
    QTextEdit *_browsedata_tv;
    QScrollBar *_num_entries_slider;
    QLabel *_entry_start_label;
    QLabel *_entry_end_label;
    QLabel *_timeinterval_lb;
    string _datasource_str;
    QDOS::TimeInterval _time_interval;
    QbTimeIntervalEditor* _time_editor;

    public:
        DcmBrowseDataDialog( const string& data_name, \
                QDOS::CDFDataBaseDataSource_var cdf_var, QbTimeIntervalEditor* time_editor,\
                        QWidget *parent=0, const char *name=0   );

        virtual ~DcmBrowseDataDialog()
        {;}

    public slots:    
        void update_num_entries();
        void update_entry_num(int num)
        { 
            int cur_num=0;
            QString num_entries_qs(\
                    _num_entries_cb->text(_num_entries_cb->currentItem()));
            istrstream ist(num_entries_qs.latin1());
            ist >> cur_num;
            if(cur_num!=num)
                _num_entries_cb->setCurrentItem(num);
        }

        void update_slider_value(int num)
        { 
            int old_val=_num_entries_slider->value();
            int val=old_val;
            QString num_entries_qs(_num_entries_cb->text(num));
            istrstream ist(num_entries_qs.latin1());
            ist >> val;
            if(val!=old_val)
                _num_entries_slider->setValue(val);
        }
  
        void browse_data_entry(int entry=0);
    
};  


class CdfFileListViewItem : public Q_LIST_VIEW_ITEM {

    DcmMetaDataDialog* metadata_dialog;
    vector<string> metadata_names;
    QDOS::CDFDataBaseDataSource_var _cdf_db;

    public:

        CdfFileListViewItem( Q_LIST_VIEW* parent, const char* name,\
                QDOS::CDFDataBaseDataSource_var cdf_db):\
                Q_LIST_VIEW_ITEM(parent,name),metadata_dialog(0),_cdf_db(cdf_db){;}

        virtual ~CdfFileListViewItem()
        { 
            if(metadata_dialog)
            {
                delete metadata_dialog;
                metadata_dialog=0;
            }
        }
  
        void show_meta_data(const QPoint& p) 
        {    
            try{
                string filename(text(0).latin1());
                if(metadata_dialog==NULL)
                {
                    if(metadata_names.size()==0)
                    {
                        QApplication::setOverrideCursor(Qt::waitCursor);
#if QT_VERSION < 0x040000
                        qApp->processEvents(2000);
#else
                        qApp->processEvents(QEventLoop::AllEvents, 2000);
#endif
                        _cdf_db->get_meta_names(filename,metadata_names);
                        QApplication::restoreOverrideCursor();
                    }
                    metadata_dialog=new DcmMetaDataDialog(\
                            filename,metadata_names,_cdf_db,listView());
                    QPalette palette = QPalette(qApp->palette());
                    metadata_dialog->setPalette(palette);
                    metadata_dialog->move(p);
                }
                metadata_dialog->show();
            }
            catch(QDOS::Exception& e)
            { 
                QApplication::restoreOverrideCursor();
                string errmsg(e.msg());
                (void)QMessageBox::warning(listView(),"Meta Data",errmsg.c_str());
    //e.print_msg();
            }
        }
};

class DcmDataSourceListViewItem : public DataBaseListViewItem {

    DcmMetaDataDialog* metadata_dialog;
    DcmBrowseDataDialog* browsedata_dialog;
    vector<string> metadata_names;

    public:

        DcmDataSourceListViewItem( Q_LIST_VIEW_ITEM* parent, const string& name, \
                QDOS::CDFDataBaseDataSource_var cdf_db );

        virtual ~DcmDataSourceListViewItem()
        { 
            if(metadata_dialog)
            {
                delete metadata_dialog;
                metadata_dialog=0;
            }
            if(browsedata_dialog)
            {
                delete browsedata_dialog;
                browsedata_dialog=0;
            }
        }

        DataSelector::LviType type() const
        { return DataSelector::LVI_DATASOURCENAME; }

        void browse_data(const QPoint& p, QbTimeIntervalEditor* time_editor)
        { 
            try{ 
                string data_name(name());   
                if(browsedata_dialog==NULL)
                {
                    browsedata_dialog=new DcmBrowseDataDialog(\
                            data_name,data_base(),time_editor,listView());
                    QPalette palette = QPalette(qApp->palette());
                    browsedata_dialog->setPalette(palette);
                    browsedata_dialog->move(p); 
                }
                browsedata_dialog->show();
            }
            catch(QDOS::Exception& e)
            { 
                QApplication::restoreOverrideCursor();
                string errmsg(e.msg());
                (void)QMessageBox::warning(listView(),"Browse Data",errmsg.c_str());
    //e.print_msg();
            }
        }

        void show_meta_data(const QPoint& p) 
        { 
            try{ 
                string data_name(name());   
                if(metadata_dialog==NULL)
                {
                    if(metadata_names.size()==0)
                    {
                        QApplication::setOverrideCursor(Qt::waitCursor);
#if QT_VERSION < 0x040000
                        qApp->processEvents(2000);
#else
                        qApp->processEvents(QEventLoop::AllEvents, 2000);
#endif
                        data_base()->get_meta_names(data_name,metadata_names); 
                        QApplication::restoreOverrideCursor();
                    }      
                    metadata_dialog=new DcmMetaDataDialog(\
                            data_name,metadata_names,data_base(),listView());
                    QPalette palette = QPalette(qApp->palette());
                    metadata_dialog->setPalette(palette);
                    metadata_dialog->move(p); 
                }
                metadata_dialog->show();
            }
            catch(QDOS::Exception& e)
            { 
                QApplication::restoreOverrideCursor();
                string errmsg(e.msg());
                (void)QMessageBox::warning(listView(),"Meta Data",errmsg.c_str());
    //e.print_msg();
            }
        }
    
      
};

#endif // DATA_SELECTOR_H
