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

#pragma once

#include <QDebug>
#include <QList>
#include <QMap>
#include <QStringList>

#include <iostream>
#include <map>
#include <vector>
#include <list>
#include <cassert>


class MvQOdbVar
{
public:
    MvQOdbVar(QString name, QString value) :
        name_(name),
        value_(value) {}

    QString name() { return name_; }
    QString value() { return value_; }

private:
    QString name_;
    QString value_;
};

class MvQOdbBitfieldMember
{
public:
    MvQOdbBitfieldMember(QString name, int pos, int size) :
        name_(name),
        pos_(pos),
        size_(size) {}

    MvQOdbBitfieldMember(const MvQOdbBitfieldMember& m) :
        name_(m.name()),
        pos_(m.pos()),
        size_(m.size()) {}
    QString name() const { return name_; }
    int pos() const { return pos_; }
    int size() const { return size_; }

private:
    QString name_;
    int pos_;
    int size_;
};


class MvQOdbColumn
{
public:
    enum OdbColumnType
    {
        None,
        Int,
        Float,
        String,
        Bitfield,
        Double,
        OldType
    };

    MvQOdbColumn() :
        typeId_(None) {}
    MvQOdbColumn(QString name, QString type, QString table) :
        name_(name),
        type_(type),
        table_(table),
        typeId_(None),
        constant_(false),
        hasMissingValue_(false),
        missingValue_(-999999.) {}

    ~MvQOdbColumn()
    {
        foreach (MvQOdbBitfieldMember* bf, bitfield_) {
            delete bf;
        }
    }

    QString name() { return name_; }
    QString type() { return type_; }
    QString table() { return table_; }
    OdbColumnType typeId() { return typeId_; }
    QString unit() { return unit_; }
    const QList<MvQOdbBitfieldMember*>& bitfield() { return bitfield_; }
    int bitfieldNum() { return bitfield_.size(); }
    bool isConstant() { return constant_; }
    double min() { return min_; }
    double max() { return max_; }
    bool hasMissingValue() { return hasMissingValue_; }
    double missingValue() { return missingValue_; }

    void setName(QString s) { name_ = s; }
    void setTable(QString s) { table_ = s; }
    void setType(QString s) { type_ = s; }
    void setTypeId(OdbColumnType s) { typeId_ = s; }
    void setUnit(QString s) { unit_ = s; }
    void addBitfieldMember(MvQOdbBitfieldMember* b) { bitfield_.push_back(b); }
    void setBitfield(QList<MvQOdbBitfieldMember*> b) { bitfield_ = b; }
    void setConstant(bool b) { constant_ = b; }
    void setMin(double min) { min_ = min; }
    void setMax(double max) { max_ = max; }
    void setHasMissingValue(bool b) { hasMissingValue_ = b; }
    void setMissingValue(double v) { missingValue_ = v; }

private:
    QString name_;
    QString type_;
    QString table_;
    OdbColumnType typeId_;
    QString unit_;
    QList<MvQOdbBitfieldMember*> bitfield_;
    bool constant_;
    double min_;
    double max_;
    bool hasMissingValue_;
    double missingValue_;
};


class MvQOdbTable : public QList<MvQOdbColumn*>
{
public:
    MvQOdbTable(QString name) :
        name_(name) {}

    QString name() { return name_; }
    void addColumn(MvQOdbColumn* col) { columns_.push_back(col); }
    QList<MvQOdbColumn*>& columns() { return columns_; }

    QStringList& linksTo() { return linksTo_; }
    QStringList& linksFrom() { return linksFrom_; }
    void findLinks();
    void addToLinksFrom(QString lnk) { linksFrom_.push_back(lnk); }
    int treePosX() { return treePosX_; }
    void setTreePosX(int i) { treePosX_ = i; }
    int treePosY() { return treePosY_; }
    void setTreePosY(int i) { treePosY_ = i; }

private:
    QString name_;
    QList<MvQOdbColumn*> columns_;
    QStringList linksTo_;
    QStringList linksFrom_;
    int treePosX_{0};
    int treePosY_{0};
};

class MvQOdbMetaData
{
public:
    enum OdbVersion
    {
        Version1,
        Version2,
        InvalidVersion
    };
    // MvQOdbMetaData(QString);
    MvQOdbMetaData(std::string, std::string);
    // MvQOdbMetaData(QString,QString,QString);
    ~MvQOdbMetaData();
    void init();

    OdbVersion odbVersion() { return odbVersion_; }
    QString odbVersionString();
    QString path() { return path_; }
    QString query() { return query_; }
    int rowNum() { return rowNum_; }
    int columnNum()
    {
        return columns_.size();
    }

    QMap<QString, MvQOdbTable*>& tables() { return tables_; }
    QList<MvQOdbColumn*>& columns() { return columns_; }
    QList<MvQOdbVar*>& vars() { return vars_; }

    void getTreePosRange(int&, int&);

protected:
    // void readMetaData();
    void removeCommentFromLine(QString&);
    void loadSchemaFile();
    void getTableTree();
    void computeTreePos(MvQOdbTable*, int&);

#ifdef METVIEW_ODB_NEW
    void loadOdbHeader();
#endif
    OdbVersion odbVersion_;

    int rowNum_;
    QString path_;
    QString sourcePath_;
    QString query_;

    QList<MvQOdbTable*> rootTables_;
    QMap<QString, MvQOdbTable*> tables_;
    QList<MvQOdbColumn*> columns_;
    QList<MvQOdbVar*> vars_;
};
