#include "characters.h"

#include "constants.h"
#include "level.h"
#include <algorithm>

character::character(RNG *rng, const feature enabled_features,
                     const enum race &nrace, const position &pos):
        rng{rng}, enabled_features{enabled_features},
        race{nrace}, HP{STARTING_HP[race]}, pos{pos},
        ATK{STARTING_ATK[race]}, DEF{STARTING_DEF[race]},
        base_hit_rate{STARTING_HR[race]} {}

void character::start_turn() {
        ATK = STARTING_ATK[race];
        DEF = STARTING_DEF[race];
        base_hit_rate = STARTING_HR[race];
}

enum race character::get_race() const {
        return race;
}

position character::get_pos() const {
        return pos;
}

void character::set_pos(const position &npos) {
        pos = npos;
}

void character::apply_effect(std::unique_ptr<potion> effect) {
        insert_effect(std::move(effect));
}

void character::insert_effect(std::unique_ptr<potion> effect) {
        effects.push_back(std::move(effect));

        for (int i = effects.size() - 1; i > 0 &&
             effects[i]->get_priority() < effects[i - 1]->get_priority(); --i)
                std::swap(effects[i], effects[i - 1]);
}

result character::calc_effects() {
        potion_own_list tmp;
        tmp.reserve(effects.size());

        for (size_t i = 0; i < effects.size(); ++i) {
                effects[i]->apply(this->race, HP, ATK, DEF, base_hit_rate);

                if (is_dead())
                        return result::DIED;

                if (effects[i]->get_duration() != 0)
                        tmp.push_back(std::move(effects[i]));
        }

        tmp.shrink_to_fit();

        std::swap(tmp, effects);

        return result::NOTHING;
}

void character::discard_level_effects() {
        potion_own_list tmp;
        tmp.reserve(effects.size());

        for (size_t i = 0; i < effects.size(); ++i)
                if (effects[i]->get_duration() > 0)
                        tmp.push_back(std::move(effects[i]));

        tmp.shrink_to_fit();

        std::swap(tmp, effects);
}

int calc_dmg(const int ATK, const int DEF) {
        return ceil((100.0f / (100.0f + DEF)) * ATK);
}

character *get_ch_at(const position &pos, const character_list &chlist) {
        for (auto ch : chlist)
                if (ch->get_pos() == pos)
                        return ch;

        return nullptr;
}

bool character::is_dead() const {
        return HP <= 0;
}
