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

 Copyright 2016 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 *************************************/

#ifndef BUFREXAMINER_H
#define BUFREXAMINER_H

#include "MvQAbstractMessageExaminer.h"
#include "MvObsSet.h"
#include "BufrFilterEngine.h"

#include <QSettings>

class QComboBox;
class QLabel;
class QPlainTextEdit;
class QSpinBox;
class QSplitter;
class QTabWidget;
class QTextEdit;
class QToolButton;
class QTreeView;
class QVBoxLayout;

class MvQArrowSpinWidget;
class MvQBufrDataModel;
class MvQTreeView;

class PlainTextWidget;

class MessageLabel;
class MvEccBufrMessage;

class BufrCompDataWidget;
class BufrFilterDef;
class BufrDataFilterDialog;
class BufrFilterDialog;
class BufrMetaData;
class MvQBufrMainPanel;
class BufrKeyWidget;
class LocationWidget;
class TreeViewSearchLine;
class MvQTreeExpandState;
class MvQBufrDumpPanel;
class BufrExpandDataModel;

class BufrJsonDumpWidget : public QWidget
{
  Q_OBJECT
public:
    BufrJsonDumpWidget(MvQBufrDumpPanel* context, QWidget* parent = nullptr);
    ~BufrJsonDumpWidget();

    void showError(QString errMsg);
    void saveExpandState();
    void restoreExpandState();
    void setSubsetNumber(int n);
    void updateKeyInfo();
    bool loadData(const QByteArray& json, bool compressed, QString& err);
    void clearData();

    void readSettings(QSettings& settings);
    void writeSettings(QSettings& settings);

protected slots:
    void slotDataDumpSearch();
    void dataDumpSelected(const QModelIndex& idx);
    void dataDumpDoubleClicked(const QModelIndex& idx);
    void slotCopyDumpKey();

signals:
    void subsetSelectedInKeyWidget(int subsetNumber);

protected:
    void updateKeyInfo(const QModelIndex& idx);

    MvQBufrDumpPanel* context_;
    QSplitter* splitter_;
    QTreeView* tree_;
    MvQBufrDataModel* model_;
    MessageLabel* messageLabel_;
    QToolButton* searchTb_;
    QToolButton* keyInfoTb_;
    TreeViewSearchLine* searchLine_;
    BufrKeyWidget* keyWidget_;
    MvQTreeExpandState* expand_;
};

class BufrExpandDumpWidget : public QWidget
{
  Q_OBJECT
public:
    BufrExpandDumpWidget(QWidget* parent = nullptr);
    ~BufrExpandDumpWidget();

    void showError(QString errMsg);
    bool loadData(const std::string& dump, QString& err);
    void clearData();

    void readSettings(QSettings& settings);
    void writeSettings(QSettings& settings);

protected slots:
    void slotSearch();
    void slotCopyKey();

protected:
    QTreeView* tree_;
    BufrExpandDataModel* model_;
    MessageLabel* messageLabel_;
    QToolButton* searchTb_;
    TreeViewSearchLine* searchLine_;
};

class MvQBufrDumpPanel : public QWidget, public MvMessageMetaDataObserver
{
    Q_OBJECT
public:
    MvQBufrDumpPanel(QWidget* parent = 0);

    void init(BufrMetaData* data);
    void loadEmpty();
    void loadDumps(int msgCnt, int subsetCnt);
    void loadDumpsForSubset(int subsetCnt);
    void dataFileChanged();
    void setNavigateUncompressed(bool b);
    void loadFilterResult(MvKeyProfile* prof);
    void clear();
    void setHasFilterResult(bool);
    void selectFilterResultTab();
    int currentSubset() const {return currentSubset_;}
    int currentMessage() const { return currentMsg_; }
    BufrMetaData* data() const {return data_;}

    QList<QAction*> actionsToControl() const;

    void readSettings(QSettings& settings);
    void writeSettings(QSettings& settings);

protected slots:
    void currentDumpChanged(int);
    void setEnableDebug(bool b);

signals:
    void messageDataInvalid(int);
    void messageSelectedInMap(int);
    void locationScanProgess(int);
    void subsetSelected(int);

protected:
    void locationScanStepChanged(int);

private:
    enum LocationTabContent
    {
        LocationContent,
        FilterResultContent
    };
    enum DumpTabIndex
    {
        JsonTabIndex     = 0,
        ExpandTabIndex   = 1,
        CompTabIndex     = 2,
        TableTabIndex    = 3,
        DebugTabIndex    = 4,
        LocationTabIndex = 5
    };

    void clearDumps();
    void clearDebugDump();
    void clearLocations();
    void loadJsonDump();
    void loadExpandDump();
    void loadTableDump();
    void loadDebugDump();
    void loadCompDump();
    void loadLocations();
    void updateKeyInfo(const QModelIndex&);
    bool doNavigateUncompressed() const;
    bool isDebugEnabled() const;
    void setLocationContent(LocationTabContent locCont);

    int currentMsg_;     //starts at 0
    int currentSubset_;  //starts at 1
    BufrMetaData* data_;
    QTabWidget* dumpTab_;

    BufrJsonDumpWidget *jsonDumpWidget_;
    BufrExpandDumpWidget *expandDumpWidget_;

    QTextEdit* tableTe_;
    PlainTextWidget* debugTe_;

    BufrCompDataWidget* compDumpWidget_;
    MvQKeyProfileTree* compDumpTree_;
    MvQKeyProfileModel* compDumpModel_;
    MvQKeyProfileSortFilterModel* compDumpSortModel_;

    MessageLabel* locationMessageLabel_;
    LocationWidget* locationW_;
    LocationTabContent locationContent_;

    QAction* actionDebug_;
    QAction* actionNavigateUncompressed_;

    bool messageCanBeDecoded_;
    bool expandDumpLoaded_;
    bool debugDumpLoaded_;
    bool navigateUncompressed_;
    bool compDumpLoaded_;
    bool locationLoaded_;
};

class MvQBufrMainPanel : public QWidget
{
    Q_OBJECT

public:
    MvQBufrMainPanel(bool filtered, QWidget* parent);
    void init(BufrMetaData*);
    void clear();
    MvKeyProfile* keyProfile() const;
    void loadKeyProfile(MvKeyProfile* prof);
    void reloadData(bool hasFilterResult);
    void messageFilterChanged(const BufrFilterDef&);
    void setFilterInfo(bool filtered, int oriNum, int num);
    bool doNavigateUncompressed() const;
    void loadFilterResult(MvKeyProfile*);
    void selectFilterResultTab();
    QString fileName() const;
    BufrMetaData* data() const { return data_; }
    int currentMessage() const { return dumpPanel_->currentMessage(); }

    void readSettings(QSettings& settings);
    void writeSettings(QSettings& settings);

protected slots:
    void messageSelected(int);
    void messageChangedInGoto(int value);
    void subsetChangedInGoto(int value);
    void subsetChangedInDump(int currentSubset);
    void messageSelectedInMap(int);
    void navigateUncompressedChanged(bool);
    void keyProfileReady();
    void keyProfileLoadFinished();

signals:
    void newMessageSelected(int);
    void keyProfileChanged();
    void messageNumDetermined();

private:  
    BufrMetaData* data_;
    MvQMessagePanel* messagePanel_;
    MvQBufrDumpPanel* dumpPanel_;
    MessageControlPanel* gotoPanel_;
    QSplitter* dataSplitter_;
    bool navigateUncompressed_;
    bool inProfileLoad_;
    QAction* actionDebug_;
    QAction* actionNavigateUncompressed_;
};

class BufrExaminer : public MvQAbstractMessageExaminer, public BufrFilterEngineObserver
{
    Q_OBJECT

public:
    BufrExaminer(QWidget* parent = 0);
    ~BufrExaminer();

    void notifyBufrFilterProgress(int n);

protected slots:
    void slotShowAboutBox();
    void slotStatusMessage(QString);
    void slotLoadFile(QString);
    void slotUncompressedMode(bool);
    void slotFilterEdit();
    void slotFilterRevert();
    void slotRunFilter(const BufrFilterDef&);
    void slotSaveFilteredFile(bool);
    void newMessageLoaded(int msg);
    void updateFileInfoLabel();
    void initFilterEditorHelpers();

signals:
    void filterProgess(int);

protected:
    MvKeyProfile* loadedKeyProfile() const;

private:
    enum MainTabIndex
    {
        OriiginalTabIndex = 0,
        FilteredTabIndex  = 1
    };

    void setupFileMenu();
    void setupFilterMenu();

    void initMain(MvMessageMetaData* data);
    void initDumps();
    void initAllKeys();
    void addCloseButtonFilteredTab();
    void createFilteredPanel();
    void loadKeyProfile(MvKeyProfile*);
    void loadFile(QString);
    void loadEmptyFile(QString f);
    void loadFilteredFile(QString, MvKeyProfile*);
    void loadFilteredEmptyFile(QString f);

    void writeSettings();
    void readSettings();

    QTabWidget* mainTab_;
    MvQBufrMainPanel* mainPanel_;
    MvQBufrMainPanel* filteredPanel_;
    BufrMetaData* filteredData_;
    bool messageCanBeDecoded_;
    QAction* actionFilterEdit_;
    QAction* actionFilterRemove_;
    QAction* actionSave_;
    BufrFilterDialog* filterDialog_;
};

#endif  // BUFREXAMINER_H
