//
//  FireSpreadActionFactory.cpp
//  eagle0_engine
//
//  Created by Dan Crosby on 1/6/19.
//  Copyright © 2019 none. All rights reserved.
//

#include "FireSpreadActionFactory.hpp"

#include "src/main/cpp/net/eagle0/shardok/library/FireUtils.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/actions/FireSpreadAction.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/util/HexMapUtils.hpp"

namespace shardok {
FireSpreadActionFactory::FireSpreadActionFactory(const SettingsGetter &getter) : settings(getter) {}

auto FireSpreadActionFactory::MakeFireSpreadAction(
        const Coords &coords,
        const HexMapDirectionFb direction,
        const Terrain *terrain,
        const WeatherFb *weather) const -> ActionSPtr {
    constexpr int16_t base = 0;

    const int16_t terrainFactor = PropensityByTerrain(terrain, settings);

    const int16_t weatherFactor =
            settings.GetFirePropensityByWeatherConditions(weather->conditions());

    int relativeWindDirection = (int)weather->wind().direction() - (int)direction;
    if (relativeWindDirection < 0) relativeWindDirection += 6;
    const int windIntensity =
            (int)(weather->wind().speed_in_mph() *
                  settings.Backing().fire_propensity_wind_speed_multiplier());

    int16_t windFactor;
    switch (relativeWindDirection) {
        case 0: {
            windFactor = windIntensity;
            break;
        }
        case 1:
        case 5: {
            windFactor = windIntensity / 2;
            break;
        }
        case 2:
        case 4: {
            windFactor = -windIntensity / 2;
            break;
        }
        case 3: {
            windFactor = -windIntensity;
            break;
        }
        default: {
            // impossible
            windFactor = -500;
            break;
        }
    }

    auto odds = MakeOdds(base, terrainFactor, weatherFactor, windFactor, 0);

    return std::make_shared<FireSpreadAction>(coords, terrain->modifier(), odds);
}

auto FireSpreadActionFactory::MakeFireSpreadActions(const HexMap *hexMap, const WeatherFb *weather)
        const -> ActionList {
    ActionList fireOutActions;

    for (const Coords &coords : GetAllCoords(hexMap)) {
        const auto *terrain = GetTerrain(hexMap, coords);
        if (terrain->modifier().fire().present()) {
            std::vector<AdjacentTile> adjacentTiles = HexMapUtils::GetAdjacentTiles(hexMap, coords);

            for (const AdjacentTile &adjacentTile : adjacentTiles) {
                const auto &destinationTerrain = GetTerrain(hexMap, adjacentTile.coords);

                if (!destinationTerrain->modifier().fire().present()) {
                    fireOutActions.push_back(MakeFireSpreadAction(
                            adjacentTile.coords,
                            static_cast<HexMapDirectionFb>(adjacentTile.directionTo),
                            destinationTerrain,
                            weather));
                }
            }
        }
    }

    return fireOutActions;
}
}  // namespace shardok
