/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include <QAction>
#include <QApplication>
#include <QDebug>
#include <QHBoxLayout>
#include <QInputDialog>
#include <QLabel>
#include <QListWidget>
#include <QProgressBar>
#include <QSettings>
#include <QSpinBox>
#include <QSplitter>
#include <QSortFilterProxyModel>
#include <QTabWidget>
#include <QTextBrowser>
#include <QToolButton>
#include <QVBoxLayout>

#include "MvApplication.h"
#include "MvRequest.h"

#include <stdlib.h>

#include "MvOdb.h"
#include <odc/api/odc.h>


#include "MvQAbout.h"
#include "MvQFileInfoLabel.h"
#include "MvQLogPanel.h"
#include "MvQOdbDataWidget.h"
#include "MvQOdbMetaData.h"
#include "MvQOdbModel.h"
#include "MvQOdbTableView.h"
#include "MvQSearchLinePanel.h"
#include "MvQTreeView.h"
#include "MvQMethods.h"

#ifdef UI_TODO
#include "MvQTreeViewSearchLine.h"
#endif

#include "OdbExaminer.h"


OdbExaminer::OdbExaminer(QWidget* parent) :
    MvQMainWindow(parent)
{
    data_ = 0;
#if UI_TODO
    columnFind_ = 0;
    tableColumnFind_ = 0;
#endif
    setAttribute(Qt::WA_DeleteOnClose);

    setWindowTitle(tr("Metview - ODB Examiner"));

    // Initial size
    setInitialSize(1100, 800);

    QWidget* w;

    //----------------------
    // Main splitter
    //----------------------

    mainSplitter_ = new QSplitter;
    mainSplitter_->setOrientation(Qt::Vertical);

    mainSplitter_->setOpaqueResize(false);
    setCentralWidget(mainSplitter_);

    //-----------------------------------------------------
    // The main layout (the upper part of mainSplitter)
    //-----------------------------------------------------

    auto* mainLayout = new QVBoxLayout;
    mainLayout->setObjectName(QString::fromUtf8("vboxLayout"));
    mainLayout->setContentsMargins(0, 0, 0, 0);
    mainLayout->setSpacing(1);
    w = new QWidget;
    w->setLayout(mainLayout);
    mainSplitter_->addWidget(w);

    //------------------
    // File info label
    //------------------

    fileInfoLabel_ = new MvQFileInfoLabel;
    mainLayout->addWidget(fileInfoLabel_);

    //-------------------
    // Central tab
    //-------------------

    metaTab_ = new QTabWidget;
    mainLayout->addWidget(metaTab_, 1);

    // Set up grib message group box
    setupTableBox();
    setupColumnBox();
    setupVarBox();
    // setupStatsBox();

    dataPanel_ = new MvQOdbDataWidget(this);
    // setupDataBox();

    metaTab_->addTab(tablePanel_, tr("Tables"));
    metaTab_->addTab(columnPanel_, tr("Columns"));
    metaTab_->addTab(varPanel_, tr("SET Variables"));
    metaTab_->addTab(dataPanel_, tr("Data"));

    // Find panel

    // We need to call it after the tab is populated
    // setupFindBox();
    // mainLayout->addWidget(findPanel_);

    //--------------------------
    // Log Area
    //--------------------------

    // Set up the panels
    logPanel_ = new MvQLogPanel(this);
    mainSplitter_->addWidget(logPanel_);
    logPanel_->hide();

#if 0

    QVBoxLayout *logLayout = new QVBoxLayout;
    logLayout->setObjectName(QString::fromUtf8("vboxLayout"));
	logLayout->setContentsMargins(0,0,0,0);
	logLayout->setSpacing(1);
	w=new QWidget;
	w->setLayout(logLayout);
	mainSplitter_->addWidget(w);

	//Label
	QLabel *label = new QLabel(tr("Log"));
	label->setFrameShape(QFrame::StyledPanel);
	logLayout->addWidget(label);

	//Log browser
    logBrowser_= new MvQLogBrowser(this);

	w->hide();
#endif

    //----------------------------
    // Signals and slots
    //----------------------------

    connect(tableView_, SIGNAL(tableSelection(QString)),
            this, SLOT(slotTableSelected(QString)));

    connect(metaTab_, SIGNAL(currentChanged(int)),
            this, SLOT(slotTabIndexChanged(int)));

    // setupEditActions();
    setupViewActions();
    setupSettingsActions();
    setupHelpActions();

    //----------------------------
    // Setup menus and toolbars
    //----------------------------

    setupMenus(menuItems_);

    // Should be called only after init
    // readSettings();
}

OdbExaminer::~OdbExaminer()
{
    writeSettings();

    /*if(columnModel_) delete columnModel_;
    if(dataModel_) delete dataModel_;
    if(bitmapModel_) delete bitmapModel_;

    for(std::vector<QStandardItemModel*>::iterator it=secModel_.begin(); it != secModel_.end(); it++)
    {
        delete *it;
    }*/
}

void OdbExaminer::setupEditActions()
{
    QAction* actionFind_ = MvQMainWindow::createAction(MvQMainWindow::FindAction, this);
    connect(actionFind_, SIGNAL(triggered(bool)),
            findPanel_, SLOT(setHidden(bool)));

    QAction* actionFindNext = MvQMainWindow::createAction(MvQMainWindow::FindNextAction, this);
    connect(actionFindNext, SIGNAL(triggered(bool)),
            findPanel_, SLOT(slotFindNext(bool)));

    QAction* actionFindPrev = MvQMainWindow::createAction(MvQMainWindow::FindPreviousAction, this);
    connect(actionFindPrev, SIGNAL(triggered(bool)),
            findPanel_, SLOT(slotFindPrev(bool)));

    MvQMainWindow::MenuType menuType = MvQMainWindow::EditMenu;

    menuItems_[menuType].push_back(new MvQMenuItem(actionFind_, MvQMenuItem::MenuTarget));
    menuItems_[menuType].push_back(new MvQMenuItem(actionFindNext, MvQMenuItem::MenuTarget));
    menuItems_[menuType].push_back(new MvQMenuItem(actionFindPrev, MvQMenuItem::MenuTarget));
}

void OdbExaminer::setupViewActions()
{
    auto* actionFileInfo = new QAction(this);
    actionFileInfo->setObjectName(QString::fromUtf8("actionFileInfo"));
    actionFileInfo->setText(tr("File info"));
    actionFileInfo->setCheckable(true);
    actionFileInfo->setChecked(true);
    actionFileInfo->setToolTip(tr("View file info"));
    QIcon icon;
    icon.addPixmap(QPixmap(QString::fromUtf8(":/examiner/info_light.svg")), QIcon::Normal, QIcon::Off);
    actionFileInfo->setIcon(icon);

    // Define routines
    connect(actionFileInfo, SIGNAL(triggered(bool)),
            fileInfoLabel_, SLOT(setVisible(bool)));

    MvQMainWindow::MenuType menuType = MvQMainWindow::ViewMenu;
    menuItems_[menuType].push_back(new MvQMenuItem(actionFileInfo));
}

void OdbExaminer::setupSettingsActions()
{
    QAction* action;

    action = createAction(MvQMainWindow::ConfigureAction, this);
    connect(action, SIGNAL(triggered()),
            this, SLOT(slotConfigure()));

    MvQMainWindow::MenuType menuType = MvQMainWindow::SettingsMenu;
    menuItems_[menuType].push_back(new MvQMenuItem(action, MvQMenuItem::MenuTarget));
}

void OdbExaminer::setupHelpActions()
{
    // About
    auto* actionAbout = new QAction(this);
    actionAbout->setObjectName(QString::fromUtf8("actionAbout"));
    actionAbout->setText(tr("&About ODB Examiner"));

    connect(actionAbout, SIGNAL(triggered()), this, SLOT(slotShowAboutBox()));

    MvQMainWindow::MenuType menuType = MvQMainWindow::HelpMenu;
    menuItems_[menuType].push_back(new MvQMenuItem(actionAbout, MvQMenuItem::MenuTarget));
}

void OdbExaminer::setupTableBox()
{
    //--------------------------------
    // Message tree (key profile)
    //--------------------------------

    tablePanel_ = new QWidget;
    auto* tableLayout = new QVBoxLayout;
    tableLayout->setContentsMargins(0, 0, 0, 0);
    tablePanel_->setLayout(tableLayout);

    // Hbox
    tableSplitter_ = new QSplitter;
    tableLayout->addWidget(tableSplitter_);

    // Table view
    tableView_ = new MvQOdbTableView;
    tableSplitter_->addWidget(tableView_);

    // Column tree
    tableColumnModel_ = new MvQOdbColumnModel(false);
    tableColumnSortModel_ = new QSortFilterProxyModel;
    tableColumnSortModel_->setSourceModel(tableColumnModel_);
    tableColumnSortModel_->setDynamicSortFilter(true);
    // columnSortModel_->setFilterRole(Qt::UserRole);
    // columnSortModel_->setFilterRegExp(QRegExp("[1]"));
    // columnSortModel_->setFilterFixedString("1");
    // columnSortModel_->setFilterKeyColumn(0);


    tableColumnTree_ = new QTreeView(this);
    tableColumnTree_->setSortingEnabled(true);
    tableColumnTree_->sortByColumn(0, Qt::AscendingOrder);
    tableColumnTree_->setAlternatingRowColors(true);
    tableColumnTree_->setAllColumnsShowFocus(true);
    tableColumnTree_->setModel(tableColumnSortModel_);
    // columnTree_->header()->setContextMenuPolicy(Qt::CustomContextMenu);
    // columnTree_->setActvatedByKeyNavigation(true);
    // columnTree_->setAcceptDrops(true);
    // columnTree_->setDragDropMode(QAbstractItemView::DropOnly);
    tableColumnTree_->setRootIsDecorated(true);

    tableSplitter_->addWidget(tableColumnTree_);
}

void OdbExaminer::setupColumnBox()
{
    //--------------------------------
    // Message tree (key profile)
    //--------------------------------

    columnPanel_ = new QWidget(this);
    auto* columnLayout = new QVBoxLayout;
    columnLayout->setContentsMargins(0, 0, 0, 0);
    columnPanel_->setLayout(columnLayout);

    // Column tree
    columnModel_ = new MvQOdbColumnModel(true);
    columnSortModel_ = new QSortFilterProxyModel;
    columnSortModel_->setSourceModel(columnModel_);
    columnSortModel_->setDynamicSortFilter(true);

    columnTree_ = new QTreeView(this);
    columnTree_->setSortingEnabled(true);
    columnTree_->sortByColumn(0, Qt::AscendingOrder);
    columnTree_->setAlternatingRowColors(true);
    columnTree_->setAllColumnsShowFocus(true);
    columnTree_->setModel(columnSortModel_);

    columnLayout->addWidget(columnTree_);
}

void OdbExaminer::setupVarBox()
{
    //--------------------------------
    // Message tree (key profile)
    //--------------------------------

    varPanel_ = new QWidget;
    auto* varLayout = new QVBoxLayout;
    varLayout->setContentsMargins(0, 0, 0, 0);
    varPanel_->setLayout(varLayout);

    // Var tree
    varModel_ = new MvQOdbVarModel;
    varSortModel_ = new QSortFilterProxyModel;
    varSortModel_->setSourceModel(varModel_);
    varSortModel_->setDynamicSortFilter(true);

    varTree_ = new QTreeView;
    varTree_->setSortingEnabled(true);
    varTree_->sortByColumn(0, Qt::AscendingOrder);
    varTree_->setAlternatingRowColors(true);
    varTree_->setAllColumnsShowFocus(true);
    varTree_->setModel(varSortModel_);
    // varTree_->header()->setContextMenuPolicy(Qt::CustomContextMenu);
    // varTree_->setActvatedByKeyNavigation(true);
    // varTree_->setAcceptDrops(true);
    // varTree_->setDragDropMode(QAbstractItemView::DropOnly);
    varTree_->setRootIsDecorated(false);

    varLayout->addWidget(varTree_);
}

void OdbExaminer::setupFindBox()
{
#if UI_TODO
    findPanel_ = new MvQSearchLinePanel;

    columnFind_ = new MvQTreeViewSearchLine(columnTree_, 0, "");
    findPanel_->addSearchLine(columnFind_, columnTree_);

    tableColumnFind_ = new MvQTreeViewSearchLine(tableColumnTree_, 0, "");
    findPanel_->addSearchLine(tableColumnFind_, columnTree_);

    findPanel_->hide();
#endif
}

void OdbExaminer::init(MvQOdbMetaData* data)
{
    // Set bufr metadata object
    data_ = data;

    // It is using the ODB version!!!
    readSettings();

    if (data_->odbVersion() == MvQOdbMetaData::Version1) {
        tableView_->init(data_, "hdr");

        columnModel_->setBaseData(data_->columns(), data_->odbVersion());
        for (int i = 0; i < columnModel_->columnCount() - 1; i++) {
            columnTree_->resizeColumnToContents(i);
        }

        varModel_->setBaseData(data_->vars());
        for (int i = 0; i < varModel_->columnCount() - 1; i++) {
            varTree_->resizeColumnToContents(i);
        }

        metaTab_->setTabEnabled(3, false);

#ifdef UI_TODO
        columnFind_ = new MvQTreeViewSearchLine(columnTree_, 0, "");
        findPanel_->addSearchLine(columnFind_, metaTab_->widget(1));

        tableColumnFind_ = new MvQTreeViewSearchLine(tableColumnTree_, 0, "");
        findPanel_->addSearchLine(tableColumnFind_, metaTab_->widget(0));

        varFind_ = new MvQTreeViewSearchLine(varTree_, 0, "");
        findPanel_->addSearchLine(varFind_, metaTab_->widget(2));
#endif
    }
    else if (data_->odbVersion() == MvQOdbMetaData::Version2) {
        metaTab_->setTabEnabled(0, false);
        metaTab_->setTabEnabled(1, true);
        metaTab_->setTabEnabled(2, false);
        columnModel_->setBaseData(data_->columns(), data->odbVersion());
        for (int i = 0; i < columnModel_->columnCount() - 1; i++) {
            columnTree_->resizeColumnToContents(i);
        }
#ifdef UI_TODO
        columnFind_ = new MvQTreeViewSearchLine(columnTree_, 0, "");
        findPanel_->addSearchLine(columnFind_, metaTab_->widget(1));

        dataFind_ = new MvQTreeViewSearchLine(dataPanel_->dataTree(), 0, "");
        findPanel_->addSearchLine(dataFind_, metaTab_->widget(4));
#endif
        metaTab_->setCurrentIndex(1);
    }

    // Fileinfo label
    updateFileInfoLabel();

    //-----------------------
    // Data
    //-----------------------
    // Data tab is initialised when we first click on it!!

    // It is using the ODB version so has to be called here!!!
    readSettings();
}


void OdbExaminer::slotTableSelected(QString tableName)
{
    MvQOdbTable* table = data_->tables()[tableName];
    tableColumnModel_->setBaseData(table->columns(), data_->odbVersion());
    for (int i = 0; i < tableColumnModel_->columnCount() - 1; i++) {
        tableColumnTree_->resizeColumnToContents(i);
    }
}

void OdbExaminer::slotTabIndexChanged(int index)
{
    if (index == 3) {
        if (data_) {
            if (!dataPanel_->initialised() &&
                !dataPanel_->init(data_->path())) {
                metaTab_->setTabEnabled(3, false);
            }
        }
        else {
            metaTab_->setTabEnabled(3, false);
        }
    }

    // findPanel_->setCurrentSearchLineById(metaTab_->currentWidget());
}

void OdbExaminer::slotShowAboutBox()
{
    const char* odc_ver;
    odc_version(&odc_ver);
    QString odcVersion(odc_ver);

    QMap<MvQAbout::Version, QString> text;
    text[MvQAbout::OdcVersion] = odcVersion;

    MvQAbout about("ODB Examiner", "", MvQAbout::MetviewVersion | MvQAbout::OdcVersion, text);
    about.exec();
}

void OdbExaminer::slotConfigure()
{
    if (data_ && data_->odbVersion() != MvQOdbMetaData::Version2)
        return;

    bool ok;
    int maxSize = QInputDialog::getInt(0, tr("Configure"),
                                       tr("Maximum size of data blocks (MB):"),
                                       dataPanel_->maxChunkSizeInMb(), 1, 2000, 1, &ok);
    if (ok) {
        dataPanel_->setMaxChunkSizeInMb(maxSize);
    }
}

void OdbExaminer::loadStarted()
{
    QApplication::setOverrideCursor(QCursor(Qt::BusyCursor));

    // loadProgress_->setRange(0,0);
    // loadProgress_->show();
}

void OdbExaminer::loadFinished()
{
    QApplication::restoreOverrideCursor();

    // loadProgress_->hide();
    // loadProgress_->setRange(0,1);
    // loadProgress_->setValue(1);
}

void OdbExaminer::updateFileInfoLabel()
{
    fileInfoLabel_->setOdbTextLabel(data_->path(), data_->odbVersionString());
}

void OdbExaminer::writeSettings()
{
    if (!data_)
        return;

    QSettings settings(MVQ_QSETTINGS_DEFAULT_ARGS, "MV4-OdbExaminer");

    if (data_->odbVersion() == MvQOdbMetaData::Version1) {
        settings.beginGroup("mainWindow_version1");
        settings.setValue("geometry", saveGeometry());
        settings.setValue("mainSplitter", mainSplitter_->saveState());
        // settings.setValue("bottomSplitter",bottomSplitter->saveState());
        settings.endGroup();
    }
    else if (data_->odbVersion() == MvQOdbMetaData::Version2) {
        settings.beginGroup("mainWindow_version2");
        settings.setValue("geometry", saveGeometry());
        settings.setValue("mainSplitter", mainSplitter_->saveState());
        settings.endGroup();
    }

    settings.beginGroup("global");
    settings.setValue("maxChunkSizeInMb", dataPanel_->maxChunkSizeInMb());
    settings.endGroup();
}

void OdbExaminer::readSettings()
{
    if (!data_)
        return;

    QSettings settings(MVQ_QSETTINGS_DEFAULT_ARGS, "MV4-OdbExaminer");

    if (data_->odbVersion() == MvQOdbMetaData::Version1) {
        settings.beginGroup("mainWindow_version1");
        restoreGeometry(settings.value("geometry").toByteArray());
        mainSplitter_->restoreState(settings.value("mainSplitter").toByteArray());
        // bottomSplitter->restoreState(settings.value("bottomSplitter").toByteArray());
        settings.endGroup();
    }
    else if (data_->odbVersion() == MvQOdbMetaData::Version2) {
        settings.beginGroup("mainWindow_version2");
        restoreGeometry(settings.value("geometry").toByteArray());
        mainSplitter_->restoreState(settings.value("mainSplitter").toByteArray());
        // bottomSplitter->restoreState(settings.value("bottomSplitter").toByteArray());
        settings.endGroup();
    }

    settings.beginGroup("global");
    if (!settings.value("maxChunkSizeInMb").isNull()) {
        dataPanel_->setMaxChunkSizeInMb(settings.value("maxChunkSizeInMb").toInt());
    }
    settings.endGroup();
}
