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

#include "MvKeyCondition.h"
#include "MvMiscellaneous.h"

MvKeyCondition* MvKeyCondition::make(const MvKeyConditionDefinition& condDef, MvVariant::Type type)
{
    if (condDef.isEmpty())
        return nullptr;

    if (type == MvVariant::IntType) {
        std::vector<int> vals;
        for (const auto& value : condDef.values_)
            vals.push_back(metview::fromString<int>(value));

        std::vector<MvVariant> vv = MvVariant::makeVector(vals);
        return MvKeyCondition::make(condDef.oper_, condDef.key_, vv);
    }
    else if (type == MvVariant::LongType) {
        std::vector<long> vals;
        for (size_t i = 0; i < condDef.values_.size(); i++)
            vals.push_back(metview::fromString<long>(condDef.values_[i]));

        std::vector<MvVariant> vv = MvVariant::makeVector(vals);
        return MvKeyCondition::make(condDef.oper_, condDef.key_, vv);
    }
    else if (type == MvVariant::DoubleType) {
        std::vector<double> vals;
        for (size_t i = 0; i < condDef.values_.size(); i++)
            vals.push_back(metview::fromString<double>(condDef.values_[i]));

        std::vector<MvVariant> vv = MvVariant::makeVector(vals);
        return MvKeyCondition::make(condDef.oper_, condDef.key_, vv);
    }
    else if (type == MvVariant::StringType) {
        std::vector<MvVariant> vv = MvVariant::makeVector(condDef.values_);
        return MvKeyCondition::make(condDef.oper_, condDef.key_, vv);
    }
    return nullptr;
}


MvKeyCondition* MvKeyCondition::make(const std::string& condOper, const std::string& key, std::vector<MvVariant> v)
{
    if (v.empty())
        return nullptr;

    if (condOper == "RANK" || condOper == "VALUE")
        return new MvKeyValueCondition(key, v);
    else if (condOper == "VALUE")
        return new MvKeyValueCondition(key, v);
    else if (condOper == "NOT_VALUE")
        return new MvKeyNotValueCondition(key, v);
    else if (condOper == "RANGE") {
        if (v.size() == 2) {
            return new MvKeyRangeCondition(key, v[0], v[1]);
        }
    }
    else if (condOper == "NOT_RANGE") {
        if (v.size() == 2) {
            return new MvKeyNotRangeCondition(key, v[0], v[1]);
        }
    }
    else if (condOper == "LESS_EQUAL_THAN") {
        if (v.size() == 1) {
            return new MvKeyLessEqThanCondition(key, v[0]);
        }
    }
    else if (condOper == "LESS_THAN") {
        if (v.size() == 1) {
            return new MvKeyLessThanCondition(key, v[0]);
        }
    }
    else if (condOper == "GREATER_EQUAL_THAN") {
        if (v.size() == 1) {
            return new MvKeyGreaterEqThanCondition(key, v[0]);
        }
    }
    else if (condOper == "GREATER_THAN") {
        if (v.size() == 1) {
            return new MvKeyGreaterThanCondition(key, v[0]);
        }
    }

    return nullptr;
}


bool MvKeyCondition::check(const std::string& key, const MvVariant& value)
{
    if (key_ == key) {
        eval(value);
        return true;
    }
    return false;
}

MvVariant::Type MvKeyValueCondition::type() const
{
    return (!values_.empty()) ? (values_[0].type()) : MvVariant::NoType;
}

void MvKeyValueCondition::eval(const MvVariant& value)
{
    for (auto& i : values_)
        if (value == i) {
            match_ = true;
            return;
        }
    match_ = false;
}

void MvKeyNotValueCondition::eval(const MvVariant& value)
{
    MvKeyValueCondition::eval(value);
    match_ = !match_;
}

MvVariant::Type MvKeyRangeCondition::type() const
{
    return start_.type();
}

void MvKeyRangeCondition::eval(const MvVariant& value)
{
    match_ = (value >= start_ && value <= end_);
}

void MvKeyNotRangeCondition::eval(const MvVariant& value)
{
    MvKeyRangeCondition::eval(value);
    match_ = !match_;
}

MvVariant::Type MvKeyLessThanCondition::type() const
{
    return value_.type();
}

void MvKeyLessThanCondition::eval(const MvVariant& value)
{
    match_ = value < value_;
}

void MvKeyGreaterThanCondition::eval(const MvVariant& value)
{
    match_ = value > value_;
}

void MvKeyGreaterEqThanCondition::eval(const MvVariant& value)
{
    match_ = value >= value_;
}

void MvKeyLessEqThanCondition::eval(const MvVariant& value)
{
    match_ = value <= value_;
}
