#include <cassert>

#include "npcstats.hpp"

#include "esmreader.hpp"
#include "esmwriter.hpp"

ESM::NpcStats::Faction::Faction() : mExpelled (false), mRank (-1), mReputation (0) {}

void ESM::NpcStats::load (ESMReader &esm)
{
    while (esm.isNextSub ("FACT"))
    {
        std::string id = esm.getHString();

        Faction faction;

        int expelled = 0;
        esm.getHNOT (expelled, "FAEX");

        if (expelled)
            faction.mExpelled = true;

        esm.getHNOT (faction.mRank, "FARA");

        esm.getHNOT (faction.mReputation, "FARE");

        mFactions.insert (std::make_pair (id, faction));
    }

    mDisposition = 0;
    esm.getHNOT (mDisposition, "DISP");

    bool intFallback = esm.getFormat() < 11;
    for (int i=0; i<27; ++i)
        mSkills[i].load (esm, intFallback);

    mWerewolfDeprecatedData = false;
    if (esm.getFormat() < 8 && esm.peekNextSub("STBA"))
    {
        // we have deprecated werewolf skills, stored interleaved
        // Load into one big vector, then remove every 2nd value
        mWerewolfDeprecatedData = true;
        std::vector<ESM::StatState<float> > skills(mSkills, mSkills + sizeof(mSkills)/sizeof(mSkills[0]));

        for (int i=0; i<27; ++i)
        {
            ESM::StatState<float> skill;
            skill.load(esm, intFallback);
            skills.push_back(skill);
        }

        int i=0;
        for (std::vector<ESM::StatState<float> >::iterator it = skills.begin(); it != skills.end(); ++i)
        {
            if (i%2 == 1)
                it = skills.erase(it);
            else
                ++it;
        }
        assert(skills.size() == 27);
        std::copy(skills.begin(), skills.end(), mSkills);
    }

    // No longer used
    bool hasWerewolfAttributes = false;
    esm.getHNOT (hasWerewolfAttributes, "HWAT");
    if (hasWerewolfAttributes)
    {
        ESM::StatState<int> dummy;
        for (int i=0; i<8; ++i)
            dummy.load(esm, intFallback);
        mWerewolfDeprecatedData = true;
    }

    mIsWerewolf = false;
    esm.getHNOT (mIsWerewolf, "WOLF");

    mBounty = 0;
    esm.getHNOT (mBounty, "BOUN");

    mReputation = 0;
    esm.getHNOT (mReputation, "REPU");

    mWerewolfKills = 0;
    esm.getHNOT (mWerewolfKills, "WKIL");

    // No longer used
    if (esm.isNextSub("PROF"))
        esm.skipHSub(); // int profit

    // No longer used
    if (esm.isNextSub("ASTR"))
        esm.skipHSub(); // attackStrength

    mLevelProgress = 0;
    esm.getHNOT (mLevelProgress, "LPRO");

    for (int i = 0; i < 8; ++i)
        mSkillIncrease[i] = 0;
    esm.getHNOT (mSkillIncrease, "INCR");

    for (int i=0; i<3; ++i)
        mSpecIncreases[i] = 0;
    esm.getHNOT (mSpecIncreases, "SPEC");

    while (esm.isNextSub ("USED"))
        mUsedIds.push_back (esm.getHString());

    mTimeToStartDrowning = 0;
    esm.getHNOT (mTimeToStartDrowning, "DRTI");

    // No longer used
    float lastDrowningHit = 0;
    esm.getHNOT (lastDrowningHit, "DRLH");

    // No longer used
    float levelHealthBonus = 0;
    esm.getHNOT (levelHealthBonus, "LVLH");

    mCrimeId = -1;
    esm.getHNOT (mCrimeId, "CRID");
}

void ESM::NpcStats::save (ESMWriter &esm) const
{
    for (std::map<std::string, Faction>::const_iterator iter (mFactions.begin());
        iter!=mFactions.end(); ++iter)
    {
        esm.writeHNString ("FACT", iter->first);

        if (iter->second.mExpelled)
        {
            int expelled = 1;
            esm.writeHNT ("FAEX", expelled);
        }

        if (iter->second.mRank >= 0)
            esm.writeHNT ("FARA", iter->second.mRank);

        if (iter->second.mReputation)
            esm.writeHNT ("FARE", iter->second.mReputation);
    }

    if (mDisposition)
        esm.writeHNT ("DISP", mDisposition);

    for (int i=0; i<27; ++i)
        mSkills[i].save (esm);

    if (mIsWerewolf)
        esm.writeHNT ("WOLF", mIsWerewolf);

    if (mBounty)
        esm.writeHNT ("BOUN", mBounty);

    if (mReputation)
        esm.writeHNT ("REPU", mReputation);

    if (mWerewolfKills)
        esm.writeHNT ("WKIL", mWerewolfKills);

    if (mLevelProgress)
        esm.writeHNT ("LPRO", mLevelProgress);

    bool saveSkillIncreases = false;
    for (int i = 0; i < 8; ++i)
    {
        if (mSkillIncrease[i] != 0)
        {
            saveSkillIncreases = true;
            break;
        }
    }
    if (saveSkillIncreases)
        esm.writeHNT ("INCR", mSkillIncrease);

    if (mSpecIncreases[0] != 0 ||
        mSpecIncreases[1] != 0 ||
        mSpecIncreases[2] != 0)
    esm.writeHNT ("SPEC", mSpecIncreases);

    for (std::vector<std::string>::const_iterator iter (mUsedIds.begin()); iter!=mUsedIds.end();
        ++iter)
        esm.writeHNString ("USED", *iter);

    if (mTimeToStartDrowning)
        esm.writeHNT ("DRTI", mTimeToStartDrowning);

    if (mCrimeId != -1)
        esm.writeHNT ("CRID", mCrimeId);
}

void ESM::NpcStats::blank()
{
    mWerewolfDeprecatedData = false;
    mIsWerewolf = false;
    mDisposition = 0;
    mBounty = 0;
    mReputation = 0;
    mWerewolfKills = 0;
    mLevelProgress = 0;
    for (int i=0; i<8; ++i)
        mSkillIncrease[i] = 0;
    for (int i=0; i<3; ++i)
        mSpecIncreases[i] = 0;
    mTimeToStartDrowning = 20;
    mCrimeId = -1;
}