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

 Copyright 2017 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>

#include "MvVariant.h"

class MvKeyCondition;

class MvKeyConditionDefinition
{
    friend class MvKeyCondition;

public:
    MvKeyConditionDefinition() = default;
    MvKeyConditionDefinition(const std::string& key, const std::string& oper,
                             const std::vector<std::string>& values) :
        key_(key),
        oper_(oper),
        values_(values) {}

    bool isEmpty() const { return oper_.empty() || key_.empty(); }
    const std::string& key() const { return key_; }

protected:
    std::string key_;
    std::string oper_;
    std::vector<std::string> values_;
};

class MvKeyCondition
{
public:
    MvKeyCondition(const std::string& key) :
        key_(key),
        match_(false) {}
    virtual ~MvKeyCondition() = default;

    const std::string& key() const { return key_; }
    virtual MvVariant::Type type() const = 0;
    const std::string& data() const { return data_; }
    void setData(const std::string& d) { data_ = d; }
    void setCurrentKeyValue(MvVariant v) { currentKeyValue_ = v; }
    MvVariant currentKeyValue() const { return currentKeyValue_; }

    bool match() const { return match_; }
    bool check(const std::string& key, const MvVariant& value);
    void reset() { match_ = false; }
    virtual void eval(const MvVariant& value) = 0;
    bool isEnabled() const { return enabled_; }
    void setEnabled(bool b) { enabled_ = b; }

    static MvKeyCondition* make(const std::string& cond, const std::string& key, std::vector<MvVariant> v);
    static MvKeyCondition* make(const MvKeyConditionDefinition& condDef, MvVariant::Type type);

protected:
    std::string key_;
    bool match_;
    std::string data_;
    MvVariant currentKeyValue_;
    bool enabled_{true};
};

class MvKeyValueCondition : public MvKeyCondition
{
public:
    MvKeyValueCondition(const std::string& key, const std::vector<MvVariant>& v) :
        MvKeyCondition(key),
        values_(v) {}
    MvVariant::Type type() const override;

protected:
    void eval(const MvVariant& value) override;
    std::vector<MvVariant> values_;
};

class MvKeyNotValueCondition : public MvKeyValueCondition
{
public:
    MvKeyNotValueCondition(const std::string& key, const std::vector<MvVariant>& v) :
        MvKeyValueCondition(key, v) {}

protected:
    void eval(const MvVariant& value) override;
};

class MvKeyRangeCondition : public MvKeyCondition
{
public:
    MvKeyRangeCondition(const std::string& key, const MvVariant& start, const MvVariant& end) :
        MvKeyCondition(key),
        start_(start),
        end_(end) {}
    MvVariant::Type type() const override;

protected:
    void eval(const MvVariant& value) override;
    MvVariant start_;
    MvVariant end_;
};

class MvKeyNotRangeCondition : public MvKeyRangeCondition
{
public:
    MvKeyNotRangeCondition(const std::string& key, const MvVariant& start, const MvVariant& end) :
        MvKeyRangeCondition(key, start, end) {}

protected:
    void eval(const MvVariant& value) override;
};

class MvKeyLessThanCondition : public MvKeyCondition
{
public:
    MvKeyLessThanCondition(const std::string& key, const MvVariant& v) :
        MvKeyCondition(key),
        value_(v) {}
    MvVariant::Type type() const override;

protected:
    void eval(const MvVariant& value) override;
    MvVariant value_;
};

class MvKeyGreaterThanCondition : public MvKeyLessThanCondition
{
public:
    MvKeyGreaterThanCondition(const std::string& key, const MvVariant& v) :
        MvKeyLessThanCondition(key, v) {}

protected:
    void eval(const MvVariant& value) override;
};

class MvKeyLessEqThanCondition : public MvKeyLessThanCondition
{
public:
    MvKeyLessEqThanCondition(const std::string& key, const MvVariant& v) :
        MvKeyLessThanCondition(key, v) {}

protected:
    void eval(const MvVariant& value) override;
};

class MvKeyGreaterEqThanCondition : public MvKeyLessThanCondition
{
public:
    MvKeyGreaterEqThanCondition(const std::string& key, const MvVariant& v) :
        MvKeyLessThanCondition(key, v) {}

protected:
    void eval(const MvVariant& value) override;
};
