//
//  GameSettings.cpp
//  eagle0
//
//  Created by Dan Crosby on 9/3/18.
//  Copyright © 2018 none. All rights reserved.
//

#include "src/main/cpp/net/eagle0/shardok/library/settings/GameSettings.hpp"

#include <utility>

#include "src/main/cpp/net/eagle0/common/MapUtils.hpp"

namespace shardok {
using BattalionTypeId = net::eagle0::shardok::storage::fb::BattalionTypeId;
using std::vector;

const SettingsKeys kSettingsKeys = SettingsKeys();

GameSettings::GameSettings(const std::shared_ptr<RandomGenerator>& generator)
    : randomGenerator(generator ?: std::make_shared<StdLibraryGenerator>()) {}

[[nodiscard]] auto SettingsGetter::ActionCostFor(const int value) const -> ActionCost {
    return ActionCost(ActionCost::usesAll, value);
}

auto SettingsGetter::GetBattalionType(const BattalionTypeId typeId) const
        -> const BattalionTypeSPtr& {
    return settings.battalionTypes[typeId];
}

auto SettingsGetter::GetFirePropensityByTerrainType(const TerrainType terrainType) const -> int {
    return settings.firePropensityByTerrain[terrainType];
}

auto SettingsGetter::GetFirePropensityByWeatherConditions(
        const Weather::Conditions conditions) const -> int {
    return settings.firePropensityByWeatherConditions[conditions];
}

auto SettingsGetter::GetFirePropensityByWeatherConditions(
        const net::eagle0::shardok::storage::fb::WeatherConditions conditions) const -> int {
    return settings.firePropensityByWeatherConditions[conditions];
}

void GameSettings::Setter::SetFromTypesAndValues(
        const std::unordered_map<string, string>& types,
        const std::unordered_map<string, string>& values) {
    for (const auto& kv : values) {
        const string& settingName = kv.first;
        const string& typeString = types.at(settingName);
        const string& valueString = kv.second;

        if (typeString.starts_with("int")) {
            SetInt(settingName, std::stoi(valueString));
        } else if (typeString.starts_with("double")) {
            SetDouble(settingName, std::stod(valueString));
        } else if (typeString == "bool") {
            SetBool(settingName, typeString == "true" || typeString == "TRUE");
        } else
            throw SettingNotFoundException(settingName);
    }

    SetFirePropensity(Terrain_Type_CITY, IntForKey(values, kSettingsKeys.firePropensityCity));
    SetFirePropensity(Terrain_Type_HILL, IntForKey(values, kSettingsKeys.firePropensityHill));
    SetFirePropensity(Terrain_Type_PLAINS, IntForKey(values, kSettingsKeys.firePropensityPlains));
    SetFirePropensity(Terrain_Type_FOREST, IntForKey(values, kSettingsKeys.firePropensityForest));
    SetFirePropensity(
            Terrain_Type_STILL_WATER,
            IntForKey(values, kSettingsKeys.firePropensityWater));
    SetFirePropensity(Terrain_Type_RIVER, IntForKey(values, kSettingsKeys.firePropensityWater));
    SetFirePropensity(Terrain_Type_SWAMP, IntForKey(values, kSettingsKeys.firePropensitySwamp));
    SetFirePropensity(
            Terrain_Type_MOUNTAIN,
            IntForKey(values, kSettingsKeys.firePropensityMountain));
    SetFirePropensityFromWeather(
            Weather::Conditions::Weather_Conditions_SUN,
            IntForKey(values, kSettingsKeys.firePropensitySun));
    SetFirePropensityFromWeather(
            Weather::Conditions::Weather_Conditions_CLOUDS,
            IntForKey(values, kSettingsKeys.firePropensityClouds));
    SetFirePropensityFromWeather(
            Weather::Conditions::Weather_Conditions_RAIN,
            IntForKey(values, kSettingsKeys.firePropensityRain));
    SetFirePropensityFromWeather(
            Weather::Conditions::Weather_Conditions_SNOW,
            IntForKey(values, kSettingsKeys.firePropensitySnow));
    SetFirePropensityFromWeather(
            Weather::Conditions::Weather_Conditions_THUNDERSTORM,
            IntForKey(values, kSettingsKeys.firePropensityThunderstorm));
    SetFirePropensityFromWeather(
            Weather::Conditions::Weather_Conditions_BLIZZARD,
            IntForKey(values, kSettingsKeys.firePropensityBlizzard));
}

void GameSettings::Setter::SetRandomGenerator(std::shared_ptr<RandomGenerator> generator) {
    settings.randomGenerator = std::move(generator);
}

void GameSettings::Setter::RegisterBattalionType(const BattalionTypeSPtr& newType) {
    if ((int64_t)settings.battalionTypes.size() <= newType->typeId) {
        settings.battalionTypes.resize(newType->typeId + 1);
    }
    settings.battalionTypes[newType->typeId] = newType;
}

void GameSettings::Setter::SetFirePropensity(const TerrainType terrainType, const int propensity) {
    settings.firePropensityByTerrain[terrainType] = propensity;
}

void GameSettings::Setter::SetFirePropensityFromWeather(
        const Weather::Conditions weatherConditions,
        const int propensity) {
    settings.firePropensityByWeatherConditions[weatherConditions] = propensity;
}

}  // namespace shardok
