/***************************** 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 <fstream>
#include <map>
#include <string>
#include <vector>
#include "fstream_mars_fix.h"

class MvFlextraBlock;

class MvFlextraItem
{
    friend class MvFlextraBlock;

public:
    enum DataType
    {
        NoType,
        DateType,
        IntType,
        FloatType
    };

    MvFlextraItem(int);
    std::string metaData(const std::string&) const;
    const std::map<std::string, std::string>& metaData() const { return metaData_; }
    void pointData(const std::string&, std::vector<std::string>&, DataType&) const;
    void addMetaData(const std::string& key, const std::string& value) { metaData_[key] = value; }
    void addPoint(const std::vector<std::string>& pt) { points_.push_back(pt); }
    const std::vector<std::vector<std::string> >& points() const { return points_; }
    int id() const { return id_; }

protected:
    std::map<std::string, int> pointKeyIndex_;
    std::map<std::string, DataType> pointKeyType_;
    int id_;
    std::map<std::string, std::string> metaData_;
    std::vector<std::vector<std::string> > points_;
};


class MvFlextra;

class MvFlextraBlock
{
    friend class MvFlextra;

public:
    MvFlextraBlock();
    ~MvFlextraBlock();

    const std::string& comment() const { return comment_; }
    void writeAll(const std::string&, int&);
    void writeHighlightPoints(const std::string&, int&, std::string);
    void writeLabels(const std::string&, int&, std::string, std::vector<std::string>&);
    int itemNum() const { return static_cast<int>(items_.size()); }
    const std::map<std::string, std::string>& metaData() const { return metaData_; }
    const std::vector<MvFlextraItem*>& items() const { return items_; }
    bool constantStep() const { return constantStep_; }
    void setUncertantyTr(bool b) { uncertaintyTr_ = b; }
    bool uncertaintyTr() const { return uncertaintyTr_; }

protected:
    void decode(std::string);
    void decode(std::ifstream& in, std::string& line);
    void writeMetaData(std::ofstream&, int&);
    bool parseHeaderLine(const std::string& line, const std::string& key, std::string& value);
    bool parseHeaderLine(const std::string& line, const std::string& key, std::string& fromValue, std::string& toValue);
    bool isMetaDataConst(const std::string& key);
    void checkStepType();

    // std::string fileName_;
    std::string comment_;
    std::string direction_;
    std::map<std::string, std::string> metaData_;
    std::vector<MvFlextraItem*> items_;
    bool constantStep_;
    bool uncertaintyTr_;
};

class MvFlextra
{
public:
    MvFlextra(const std::string&);
    ~MvFlextra();

    const std::string& fileName() const { return fileName_; }
    int blockNum() const { return static_cast<int>(blocks_.size()); }
    const std::vector<MvFlextraBlock*>& blocks() const { return blocks_; }
    void write(FILE* f);
    void write(const std::string&, int);


protected:
    void decode();

    std::string fileName_;
    std::vector<MvFlextraBlock*> blocks_;
};
