/***************************** 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 GribMetaData_H
#define GribMetaData_H

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

#ifdef ECCODES_UI
#include "grib_api.h"
#endif

#include "MvMessageMetaData.h"

#ifdef METVIEW
//for off_t
#include "mars.h"
#endif

class MvKeyProfile;

class GribItem
{
public:
    void pos(const std::string& s) { pos_ = s; }
    const std::string& pos() const { return pos_; }
    void name(const std::string& s) { name_ = s; }
    const std::string& name() const { return name_; }
    void type(const std::string& s) { type_ = s; }
    const std::string& type() const { return type_; }
    void value(const std::string& s) { value_ = s; }
    const std::string& value() const { return value_; }
    void intValue(const std::string& s) { intValue_ = s; }
    const std::string& intValue() const { return intValue_; }
    void description(const std::string& s) { description_ = s; }
    const std::string& description() const { return description_; }
    void addAlias(const std::string& s) { alias_.push_back(s); }
    const vector<std::string>& alias() const { return alias_; }
    void addArrayData(const std::string& s) { array_.push_back(s); }
    const vector<std::string>& arrayData() const { return array_; }

protected:
    std::string pos_;
    std::string name_;
    std::string type_;
    std::string value_;
    std::string intValue_;
    std::string description_;
    std::vector<std::string> alias_;
    std::vector<std::string> array_;
};

class GribSection;
typedef list<GribSection*>::const_iterator GribSectionIterator;

class GribSection
{
public:
    GribSection() {}
    ~GribSection();
    void name(const std::string& s) { name_ = s; }
    const std::string& name() const { return name_; }
    void lenght(int i) { lenght_ = i; }
    int lenght() const { return lenght_; }
    void offset(int i) { offset_ = i; }
    int offset() const { return offset_; }
    void addItem(GribItem* i) { item_.push_back(i); }
    int itemNum() const { return item_.size(); }
    const std::vector<GribItem*>& item() const { return item_; }

protected:
    std::string name_;
    int lenght_;
    int offset_;
    std::vector<GribItem*> item_;
};

class GribWmoDump
{
public:
    GribWmoDump() {}
    ~GribWmoDump();
    void clear();
    bool read(const std::string&, int);
    int sectionNum() const { return section_.size(); }
    const string& text() const { return text_; }
    const std::vector<GribSection*>& section() const { return section_; }

protected:
    void parse(std::stringstream&);

    std::vector<GribSection*> section_;
    string text_;
};

class GribStdDump
{
public:
    GribStdDump() {}
    ~GribStdDump();
    void clear();
    bool read(const std::string&, int);
    int itemNum() const { return item_.size(); }
    const std::string& text() const { return text_; }
    const std::vector<GribItem*>& item() const { return item_; }

protected:
    void parse(std::stringstream&);

    std::vector<GribItem*> item_;
    std::string text_;
};

class GribMvDump
{
public:
    GribMvDump();
    ~GribMvDump();
    void clear();
    bool read(const std::string&, int);
    int itemNum() const { return item_.size(); }
    const std::vector<GribItem*>& item() { return item_; }

protected:
    std::vector<GribItem*> item_;
    static std::map<int, std::string> keyMap_;
};

class GribValueDump
{
public:
    GribValueDump();
    ~GribValueDump();
    void clear();
    bool read(const std::string&, int);
    double* latitude() { return latitude_; }
    double* longitude() { return longitude_; }
    double* value() { return value_; }
    int num() { return num_; }
    int decimalPlaces() { return decimalPlaces_; }
    double average() { return average_; }
    double stdev() { return stdev_; }
    double skewness() { return skewness_; }
    double kurtosis() { return kurtosis_; }

protected:
    void readFailed(FILE*, grib_handle*);

    double* latitude_;
    double* longitude_;
    double* value_;
    int num_;
    int decimalPlaces_;
    std::string gridType_;
    double average_;
    double stdev_;
    double skewness_;
    double kurtosis_;
};


class GribMetaData : public MvMessageMetaData
{
public:
    GribMetaData();
    ~GribMetaData();
    void setFileName(std::string);
    int computeTotalMessageNum();
    int getGribCount();
    void getKeyList(int, std::string, MvKeyProfile*);
    void getKeyList(int, std::string, list<std::string>&);
    void getKeyProfileForFirstMessage(MvKeyProfile *prof);

    void setTotalMessageNum(int);
    long gribapiVersionNumber();
    void setFilter(const std::vector<off_t>&, const std::vector<int>&);
    void updateFilterCnt(const std::vector<off_t>& offset, const std::vector<int>& cnt);
    bool hasMultiMessage() { return hasMultiMessage_; }

protected:
    void clear();

private:
    //void readMessages(MvKeyProfile *);
    void readMessage(MvKeyProfile*, grib_handle*);
    void setDateStructure();

    bool hasMultiMessage_;
};

#endif
