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

#ifndef MvKeyProfile_H
#define MvKeyProfile_H

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

class MvVariant;

using namespace std;

class MvKey
{
public:
    MvKey();
    MvKey(const string& name, const string& shortName, string description = string(""));
    MvKey(const MvKey&);

    MvKey* clone();

    enum Role
    {
        IndexRole,
        MessageIndexRole,
        SubsetIndexRole,
        RankRole,
        LatitudeRole,
        LongitudeRole,
        DateRole,
        TimeRole,
        LevelRole,
        StationIdRole,
        NoRole
    };

    enum KeyType
    {
        NormalKey,
        EccodesKey
    };

    void setRole(Role role) { role_ = role; }
    Role role() const { return role_; }

    void setKeyType(KeyType keyType) { keyType_ = keyType; }
    KeyType keyType() const { return keyType_; }

    enum ValueType
    {
        StringType,
        IntType,
        LongType,
        FloatType,
        DoubleType
    };
    void setValueType(ValueType, bool useMissingValue=false);
    ValueType valueType() const { return valueType_; }

    const string& shortName() const { return shortName_; }
    const string& name() const { return name_; }
    const map<string, string>& metaData() const { return metaData_; }
    const string& metaData(const string&) const;
    const string& description() const { return description_; }

    void setShortName(const string& s) { shortName_ = s; }
    void setName(const string& s) { name_ = s; }
    void setMetaData(const string&, const string&);
    void setDescription(const string& d) { description_ = d; }

    int valuePrecision() const { return precision_; }
    void setValuePrecision(int p) { precision_ = p; }

    //TODO: refactor the usage of the "value" functions
    void addValue(const string& v) { addStringValue(v); }
    const vector<string>& value() const { return stringVal_; }
    void setValue(int idx, const string& v) { setStringValue(idx, v); }
    std::string valueAsString(int idx) const;

    void addStringValue(const string&);
    const vector<string>& stringValue() const { return stringVal_; }
    const string& stringConstantValue() const;
    void setStringValue(int, const string&);

    void addIntValue(int);
    const vector<int>& intValue() const { return intVal_; }
    int intConstantValue() const;
    void setIntValue(int, int);
    void setIntRange(int, int);
    void setIntMissingValue(int v)
    {
        intMissingVal_     = v;
        missingValDefined_ = true;
    }
    int intMissingValue() const { return intMissingVal_; }

    void addLongValue(long);
    const vector<long>& longValue() const { return longVal_; }
    long longConstantValue() const;
    void setLongValue(int, long);
    void setLongRange(long, long);
    void setLongMissingValue(long v)
    {
        longMissingVal_    = v;
        missingValDefined_ = true;
    }
    long longMissingValue() const { return longMissingVal_; }

    void addDoubleValue(double);
    const vector<double>& doubleValue() const { return doubleVal_; }
    double doubleConstantValue() const;
    void setDoubleValue(int, double);
    void setDoubleMissingValue(double v)
    {
        doubleMissingVal_  = v;
        missingValDefined_ = true;
    }
    double doubleMissingValue() const { return doubleMissingVal_; }

    void addValue(const MvVariant&);
    void setValue(int chunkStart, int chunkSize, MvKey* key);

    int valueNum() const;
    void clearMetaData();
    void clearData();

    //const map<string,int>& counter() const {return counter_;}

    bool readIntAsString() const { return readIntAsString_; }
    void setReadIntAsString(bool b) { readIntAsString_ = b; }
    bool editable() const { return editable_; }
    void setEditable(bool b) { editable_ = b; }
    void setConstant(bool b) { constant_ = b; }
    bool isConstant() const { return constant_; }
    bool isMissingValueDefined() const { return missingValDefined_; }
    void preAllocate(int);

    bool operator==(const MvKey&) const;
    bool operator!=(const MvKey&) const;

protected:
    void addToCounter(const string&);

    string name_;
    string shortName_;
    string description_;
    map<string, string> metaData_;

    Role role_;
    KeyType keyType_;
    int precision_;
    ValueType valueType_;
    bool constant_;
    vector<string> stringVal_;
    vector<int> intVal_;
    vector<long> longVal_;
    vector<float> floatVal_;
    vector<double> doubleVal_;
    int intMissingVal_;
    long longMissingVal_;
    float floatMissingVal_;
    double doubleMissingVal_;
    bool missingValDefined_;

    //map<string,int> counter_;
    bool readIntAsString_;
    bool editable_;  //if false only shortname is editable
};

class MvKeyProfile : public vector<MvKey*>
{
public:
    MvKeyProfile(string n) :
        name_(n),
        systemProfile_(false) {}
    MvKeyProfile(const MvKeyProfile&);
    ~MvKeyProfile();

    MvKeyProfile* clone();
    void clear();
    MvKey* addKey();
    void addKey(MvKey*);
    void insertKey(int before, MvKey* key);
    void deleteKey(int);
    void swap(int, int);
    void reposition(int, int);
    void reposition(const vector<int>&);
    MvKey* key(string) const;
    MvKey* key(MvKey::Role role) const;
    MvKey* key(MvKey::Role role, int occurence) const;
    string name() { return name_; }
    void setName(string n) { name_ = n; }
    int valueNum(int);
    int valueNum() const;
    void clearKeyData();
    void setSystemProfile(bool b) { systemProfile_ = b; }
    bool systemProfile() { return systemProfile_; }
    void expand(std::vector<MvKeyProfile*> ref);
    void markErrorRow(int i) { errorRows_.push_back(i); }
    bool isErrorRow(int i) const;
    void preAllocate(int);
    void setValuesInChunk(int chunkStart, int chunkSize, MvKeyProfile* prof);

    const string& metaData(const string&) const;
    void setMetaData(const string&, const string&);
    void clearMetaData();

    bool operator==(const MvKeyProfile&) const;
    bool operator!=(const MvKeyProfile&) const;

private:
    string name_;
    bool systemProfile_;
    std::vector<int> errorRows_;
    map<string, string> metaData_;
};

#endif
