/*
 * Copyright 2020 The casbin Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "casbin/pch.h"

#ifndef MODEL_CPP
#define MODEL_CPP

#include <sstream>
#include <regex>

#include "casbin/config/config.h"
#include "casbin/exception/missing_required_sections.h"
#include "casbin/model/model.h"
#include "casbin/util/util.h"

namespace {

std::vector<std::string> sections_names_reading_order = { "m", "r", "p", "g", "e" };

};

namespace casbin {

std::unordered_map<std::string, std::string> Model::section_name_map = {
    {"r", "request_definition"},
    {"p", "policy_definition"},
    {"g", "role_definition"},
    {"e", "policy_effect"},
    {"m", "matchers"}};

std::vector<std::string> Model::required_sections{"r", "p", "e", "m"};

// matcher can alter vector / hashset storage for policies

void Model::LoadModelFromConfig(std::shared_ptr<Config>& cfg) {
    for (auto section_name : sections_names_reading_order)
        LoadSection(this, cfg, section_name);

    std::vector<std::string> ms;
    ms.reserve(required_sections.size());

    for (const std::string& required_section : required_sections)
        if (!this->HasSection(required_section))
            ms.push_back(section_name_map[required_section]);

    if (ms.size() > 0)
        throw MissingRequiredSections("missing required sections: " + Join(ms, ","));
}

bool Model::HasSection(const std::string& sec) {
    return this->m.find(sec) != this->m.end();
}

void Model::LoadSection(Model* raw_ptr, std::shared_ptr<ConfigInterface> cfg, const std::string& sec) {
    int i = 1;
    while (true) {
        if (!LoadAssertion(raw_ptr, cfg, sec, sec + GetKeySuffix(i)))
            break;
        else
            i++;
    }
}

std::string Model::GetKeySuffix(int i) {
    if (i == 1)
        return "";
    return std::to_string(i);
}

bool Model::LoadAssertion(Model* raw_ptr, std::shared_ptr<ConfigInterface> cfg, const std::string& sec, const std::string& key) {
    std::string value = cfg->GetString(section_name_map[sec] + "::" + key);
    return raw_ptr->AddDef(sec, key, value);
}

static bool IsHashsetUsagePossible(const Model& model) {
    if (model.m.find("r") == model.m.end()
        || model.m.at("r").assertion_map.find("r") == model.m.at("r").assertion_map.end()
        || !model.m.at("r").assertion_map.at("r")) 
    {
         return false;
    }
    const auto& request_tokens = model.m.at("r").assertion_map.at("r")->tokens;
    auto matcher = model.m.at("m").assertion_map.at("m")->value;
    for (const auto& token : request_tokens) {
        auto effective_token = token.substr(2, token.size() - 2);
        matcher = regex_replace(matcher, std::regex("r." + effective_token + " == p." + effective_token), "");
    }
    std::string expected_matcher = "";
    for (size_t i=0; i<request_tokens.size() - 1; i++)
        expected_matcher += " && ";
    
    return expected_matcher == matcher && model.m.find("g") == model.m.end();
}

// AddDef adds an assertion to the model.
bool Model::AddDef(const std::string& sec, const std::string& key, const std::string& value) {
    if (value == "")
        return false;

    std::shared_ptr<Assertion> ast = std::make_shared<Assertion>();
    ast->key = key;
    ast->value = value;
    if (sec == "r" || sec == "p") {
        ast->tokens = Split(ast->value, ",");
        for (std::string& token : ast->tokens)
            token = key + "_" + Trim(token);
    } else
        ast->value = RemoveComments(ast->value);
    if (m.find(sec) == m.end())
        m[sec] = AssertionMap();
    if (sec != "p") {
        ast->policy = IsHashsetUsagePossible(*this) ? PoliciesValues::createWithHashset() : PoliciesValues::createWithVector();
    } else {
        // base model detection expects "m" and "r" to be set
        if ( sec != "m" && sec != "r" && (m.find("m") == m.end() || m.find("r") == m.end())) {
            return false;
        }
        ast->policy = IsHashsetUsagePossible(*this) ? PoliciesValues::createWithHashset() : PoliciesValues::createWithVector();
    }

    m[sec].assertion_map[key] = ast;

    return true;
}

// LoadModel loads the model from model CONF file.
void Model::LoadModel(const std::string& path) {
    std::shared_ptr<Config> cfg = Config::NewConfig(path);
    LoadModelFromConfig(cfg);
}

// LoadModelFromText loads the model from the text.
void Model::LoadModelFromText(const std::string& text) {
    std::shared_ptr<Config> cfg = Config::NewConfigFromText(text);
    LoadModelFromConfig(cfg);
}

// PrintModel prints the model to the log.
void Model::PrintModel() {
    // ------TODO------
    // DefaultLogger df_logger;
    // df_logger.EnableLog(true);

    // Logger *logger = &df_logger;
    // LogUtil::SetLogger(*logger);

    // LogUtil::LogPrint("Model:");
    // for (unordered_map <std::string, AssertionMap>::iterator it1 = M.begin() ; it1 != M.end() ; it1++){
    // 	for(unordered_map <std::string, Assertion*>::iterator it2 = (it1->second).AMap.begin() ; it2 != (it1->second).AMap.end() ; it2++){
    // LogUtil::LogPrintf("%s.%s: %s", it1->first, it2->first, it2->second->Value);
    // 	}
    // }
}

Model::Model() {
}

Model::Model(const std::string& path) {
    LoadModel(path);
}

// NewModel creates an empty model.
std::shared_ptr<Model> Model::NewModel() {
    return std::make_shared<Model>();
}

// NewModel creates a model from a .CONF file.
std::shared_ptr<Model> Model::NewModelFromFile(const std::string& path) {
    std::shared_ptr<Model> m = NewModel();
    m->LoadModel(path);
    return m;
}

// NewModel creates a model from a std::string which contains model text.
std::shared_ptr<Model> Model::NewModelFromString(const std::string& text) {
    std::shared_ptr<Model> m = NewModel();
    m->LoadModelFromText(text);
    return m;
}

void Model::BuildIncrementalRoleLinks(std::shared_ptr<RoleManager>& rm, policy_op op, const std::string& sec, const std::string& p_type, const PoliciesValues& rules) {
    if (sec == "g")
        this->m[sec].assertion_map[p_type]->BuildIncrementalRoleLinks(rm, op, rules);
}

// BuildRoleLinks initializes the roles in RBAC.
void Model::BuildRoleLinks(std::shared_ptr<RoleManager>& rm) {
    for (auto [_, assertion_ptr] : this->m["g"].assertion_map)
        assertion_ptr->BuildRoleLinks(rm);
}

// PrintPolicy prints the policy to log.
void Model::PrintPolicy() {
    // ------TODO------
    // DefaultLogger df_logger;
    // df_logger.EnableLog(true);

    // Logger *logger = &df_logger;
    // LogUtil::SetLogger(*logger);

    // LogUtil::LogPrint("Policy:");

    // for (std::unordered_map<std::string, Assertion*>::iterator it = this->m["p"].assertion_map.begin() ; it != this->m["p"].assertion_map.end() ; it++) {
    // LogUtil::LogPrint(it->first, ": ", (it->second)->Value, ": ", (it->second)->policy);
    // }

    // for (std::unordered_map<std::string, Assertion*>::iterator it = this->m["g"].assertion_map.begin() ; it != this->m["g"].assertion_map.end() ; it++) {
    // LogUtil::LogPrint(it->first, ": ", (it->second)->Value, ": ", (it->second)->policy);
    // }
}

// ClearPolicy clears all current policy.
void Model::ClearPolicy() {
    // Caching "p" assertion map by reference for the scope of this function
    for (auto [_, assertion_ptr] : this->m["p"].assertion_map) {
        if (assertion_ptr->policy.size() > 0)
            assertion_ptr->policy.clear();
    }

    // Caching "g" assertion map by reference for the scope of this function
    for (auto [_, assertion_ptr] : this->m["g"].assertion_map) {
        if (assertion_ptr->policy.size() > 0)
            assertion_ptr->policy.clear();
    }
}

// GetPolicy gets all rules in a policy.
PoliciesValues Model::GetPolicy(const std::string& sec, const std::string& p_type) {
    return this->m[sec].assertion_map[p_type]->policy;
}

// GetFilteredPolicy gets rules based on field filters from a policy.
PoliciesValues Model::GetFilteredPolicy(const std::string& sec, const std::string& p_type, int field_index, const std::vector<std::string>& field_values) {
    const PoliciesValues& policy = m[sec].assertion_map[p_type]->policy;
    PoliciesValues res(policy.size());

    for (const auto& policy_value : policy) {
        bool matched = true;
        for (int j = 0; j < field_values.size(); j++) {
            if (field_values[j] != "" && policy_value[field_index + j] != field_values[j]) {
                matched = false;
                break;
            }
        }
        if (matched)
            res.emplace(policy_value);
    }

    return res;
}

// HasPolicy determines whether a model has the specified policy rule.
bool Model::HasPolicy(const std::string& sec, const std::string& p_type, const std::vector<std::string>& rule) {
    auto& policy = this->m[sec].assertion_map[p_type]->policy;
    for (const std::vector<std::string>& policy_it : policy)
        if (ArrayEquals(rule, policy_it))
            return true;

    return false;
}

// AddPolicy adds a policy rule to the model.
bool Model::AddPolicy(const std::string& sec, const std::string& p_type, const std::vector<std::string>& rule) {
    if (!this->HasPolicy(sec, p_type, rule)) {
        m[sec].assertion_map[p_type]->policy.emplace(rule);
        return true;
    }

    return false;
}

// AddPolicies adds policy rules to the model.
bool Model::AddPolicies(const std::string& sec, const std::string& p_type, const PoliciesValues& rules) {
    for (const std::vector<std::string>& rule : rules)
        if (this->HasPolicy(sec, p_type, rule))
            return false;

    for (const std::vector<std::string>& rule : rules)
        this->m[sec].assertion_map[p_type]->policy.emplace(rule);

    return true;
}

bool Model::UpdatePolicy(const std::string& sec, const std::string& p_type, const std::vector<std::string>& oldRule, const std::vector<std::string>& newRule) {
    // Caching policy by reference for the scope of this function
    auto& policy = m[sec].assertion_map[p_type]->policy;

    // Status flags
    bool is_oldRule_deleted = false, is_newRule_added = false;

    for (auto it = policy.begin(); it != policy.end(); ++it) {
        if (ArrayEquals(oldRule, *it)) {
            policy.erase(it);
            is_oldRule_deleted = true;
            break;
        }
    }

    if (!is_oldRule_deleted)
        return false;

    // Prevents duplicate policies
    if (!this->HasPolicy(sec, p_type, newRule)) {
        policy.emplace(newRule);
        is_newRule_added = true;
    }

    if (!is_newRule_added)
        return false;

    return is_oldRule_deleted && is_newRule_added;
}

bool Model::UpdatePolicies(const std::string& sec, const std::string& p_type, const PoliciesValues& oldRules, const PoliciesValues& newRules) {
    // Caching policy by reference for the scope of this function
    auto& policy = this->m[sec].assertion_map[p_type]->policy;

    // Deleting old rules
    bool is_oldRule_deleted;
    for (const std::vector<std::string>& oldRule : oldRules) {
        is_oldRule_deleted = false;
        for (auto it = policy.begin(); it != policy.end(); ++it) {
            if (ArrayEquals(oldRule, *it)) {
                policy.erase(it);
                is_oldRule_deleted = true;
                break;
            }
        }
        if (!is_oldRule_deleted)
            return false;
    }

    // Checking if the policy already contains newRule
    for (const std::vector<std::string>& newRule : newRules) {
        if (!this->HasPolicy(sec, p_type, newRule))
            continue;
        else
            return false;
    }

    for (const std::vector<std::string>& newRule : newRules) {
       policy.emplace(newRule);
    }

    return true;
}

// RemovePolicy removes a policy rule from the model.
bool Model::RemovePolicy(const std::string& sec, const std::string& p_type, const std::vector<std::string>& rule) {
    // Caching policy by reference for the scope of this function
    auto& policy = m[sec].assertion_map[p_type]->policy;
    for (auto it = policy.begin(); it != policy.end(); ++it) {
        if (ArrayEquals(rule, *it)) {
            policy.erase(it);
            return true;
        }
    }
    return false;
}

// RemovePolicies removes policy rules from the model.
bool Model::RemovePolicies(const std::string& sec, const std::string& p_type, const PoliciesValues& rules) {
    // Caching policy by reference for the scope of this function
    auto& policy = this->m[sec].assertion_map[p_type]->policy;

    bool is_equal;
    for (const std::vector<std::string>& rule : rules) {
        is_equal = false;
        for (const std::vector<std::string>& policy_it : policy) {
            if (ArrayEquals(rule, policy_it))
                is_equal = true;
        }
        if (!is_equal)
            return false;
    }

    for (const std::vector<std::string>& rule : rules) {
        for (auto policy_it = policy.begin(); policy_it != policy.end(); ++policy_it) {
            if (ArrayEquals(rule, *policy_it))
                policy.erase(policy_it);
        }
    }

    return true;
}

// RemoveFilteredPolicy removes policy rules based on field filters from the model.
std::pair<bool, PoliciesValues> Model::RemoveFilteredPolicy(const std::string& sec, const std::string& p_type, int field_index, const std::vector<std::string>& field_values) {
    PoliciesValues& policy = m[sec].assertion_map[p_type]->policy;
    PoliciesValues tmp(policy.size());
    PoliciesValues effects(policy.size());
    bool res = false;
    for (auto& policy_value : policy ) {
        bool matched = true;
        for (int j = 0; j < field_values.size(); j++) {
            if (field_values[j] != "" && policy_value[field_index + j] != field_values[j]) {
                matched = false;
                break;
            }
        }
        if (matched) {
            effects.emplace(policy_value);
            res = true;
        } else
            tmp.emplace(policy_value);
    }

    policy = tmp;
    std::pair<bool, PoliciesValues> result(res, effects);
    return result;
}

// GetValuesForFieldInPolicy gets all values for a field for all rules in a policy, duplicated values are removed.
std::vector<std::string> Model::GetValuesForFieldInPolicy(const std::string& sec, const std::string& p_type, int field_index) {
    std::vector<std::string> values;
    PoliciesValues& policy = m[sec].assertion_map[p_type]->policy;
    values.reserve(policy.size());

    for (const std::vector<std::string>& policy_it : policy)
        values.push_back(policy_it[field_index]);

    ArrayRemoveDuplicates(values);

    return values;
}

// GetValuesForFieldInPolicyAllTypes gets all values for a field for all rules in a policy of all p_types, duplicated values are removed.
std::vector<std::string> Model::GetValuesForFieldInPolicyAllTypes(const std::string& sec, int field_index) {
    std::vector<std::string> values;

    for (auto [assertion, _] : m[sec].assertion_map) {
        const std::vector<std::string>& values_for_field = this->GetValuesForFieldInPolicy(sec, assertion, field_index);
        for (const std::string& value_for_field : values_for_field)
            values.push_back(value_for_field);
    }

    ArrayRemoveDuplicates(values);

    return values;
}

} // namespace casbin

#endif // MODEL_CPP
