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

 Copyright 2015 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 <string>
#include <vector>

class MvProfileData;
class MvScmProfileData;

class MvProfileChange
{
public:
    MvProfileChange() :
        group_(NoGroup) {}
    MvProfileChange(int lev, float val, float prevVal) :
        level_(lev),
        value_(val),
        prevValue_(prevVal),
        group_(NoGroup) {}

    MvProfileChange(const MvProfileChange& c) :
        level_(c.level()),
        value_(c.value()),
        prevValue_(c.prevValue()),
        group_(c.group()) {}

    enum GroupStatus
    {
        GroupStart,
        GroupEnd,
        GroupMember,
        NoGroup
    };

    virtual bool checkData(const MvProfileData&) const { return false; }
    virtual bool checkData(const MvScmProfileData&) const { return false; }


    int level() const { return level_; }
    float value() const { return value_; }
    float prevValue() const { return prevValue_; }
    GroupStatus group() const { return group_; }
    void setGroup(GroupStatus b) { group_ = b; }

protected:
    int level_;
    float value_;
    float prevValue_;
    GroupStatus group_;
};

class MvProfileData
{
public:
    enum LevelDirection
    {
        TopDown,
        BootmUp
    };

    MvProfileData();
    virtual ~MvProfileData() = default;

    virtual float value(int) = 0;

    virtual float level(int)                 = 0;
    virtual float auxLevel(int)              = 0;
    virtual void levels(std::vector<float>&) = 0;

    std::string name() const { return name_; }
    std::string units() const { return units_; }
    std::string levelName() const { return levelName_; }
    std::string levelUnits() const { return levelUnits_; }
    std::string auxLevelName() const { return auxLevelName_; }
    std::string auxLevelUnits() const { return auxLevelUnits_; }
    std::string stepString() const { return stepString_; }

    bool auxLevelDefined() const { return auxLevelDefined_; }
    void valueRange(int, int, float&, float&);
    void valueRange(float&, float&);

    virtual bool acceptChange(const MvProfileChange&) const;
    virtual int count() const         = 0;
    virtual void setValue(int, float) = 0;

    void setRange(float min, float max)
    {
        rangeMin_ = min;
        rangeMax_ = max;
        rangeSet_ = true;
    }
    bool isRangeSet() const { return rangeSet_; }
    float rangeMin() const { return rangeMin_; }
    float rangeMax() const { return rangeMax_; }
    bool fitToRange(float&);

protected:
    std::string name_;
    std::string units_;
    std::string stepString_;
    bool editable_;

    LevelDirection levelDirection_;
    std::string levelName_;
    std::string levelUnits_;
    bool auxLevelDefined_;
    std::string auxLevelName_;
    std::string auxLevelUnits_;

    bool rangeSet_;
    float rangeMin_;
    float rangeMax_;
};
