/*
  Copyright (C) 2016, 2018-2021 cc9cii

  This software is provided 'as-is', without any express or implied
  warranty.  In no event will the authors be held liable for any damages
  arising from the use of this software.

  Permission is granted to anyone to use this software for any purpose,
  including commercial applications, and to alter it and redistribute it
  freely, subject to the following restrictions:

  1. The origin of this software must not be misrepresented; you must not
     claim that you wrote the original software. If you use this software
     in a product, an acknowledgment in the product documentation would be
     appreciated but is not required.
  2. Altered source versions must be plainly marked as such, and must not be
     misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.

  cc9cii cc9c@iinet.net.au

  Much of the information on the data structures are based on the information
  from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
  trial & error.  See http://en.uesp.net/wiki for details.

*/
#ifndef ESM4_NPC__H
#define ESM4_NPC__H

#include <cstdint>
#include <string>
#include <vector>

#include <components/esm/defs.hpp>
#include <components/esm/formid.hpp>

#include "actor.hpp"
#include "inventory.hpp"

namespace ESM4
{
    class Reader;
    class Writer;

    struct Npc
    {
        enum ActorBaseFlagsTes4
        {
            TES4_Female = 0x000001,
            TES4_Essential = 0x000002,
            TES4_Respawn = 0x000008,
            TES4_AutoCalcStats = 0x000010,
            TES4_PCLevelOffset = 0x000080,
            TES4_NoLowLevelProc = 0x000200,
            TES4_NoRumors = 0x002000,
            TES4_Summonable = 0x004000,
            TES4_NoPersuasion = 0x008000, // different meaning to crea
            TES4_CanCorpseCheck = 0x100000 // opposite of crea
        };

        enum ActorBaseFlagsFo3
        {
            FO3_Female = 0x00000001,
            FO3_Essential = 0x00000002,
            FO3_PresetFace = 0x00000004, // Is CharGen Face Preset
            FO3_Respawn = 0x00000008,
            FO3_AutoCalcStats = 0x00000010,
            FO3_PCLevelMult = 0x00000080,
            FO3_UseTemplate = 0x00000100,
            FO3_NoLowLevelProc = 0x00000200,
            FO3_NoBloodSpray = 0x00000800,
            FO3_NoBloodDecal = 0x00001000,
            FO3_NoVATSMelee = 0x00100000,
            FO3_AnyRace = 0x00400000,
            FO3_AutoCalcServ = 0x00800000,
            FO3_NoKnockdown = 0x04000000,
            FO3_NotPushable = 0x08000000,
            FO3_NoRotateHead = 0x40000000
        };

        // In FO4 flags seem to be the same.
        enum ActorBaseFlagsTes5
        {
            TES5_Female = 0x00000001,
            TES5_Essential = 0x00000002,
            TES5_PresetFace = 0x00000004, // Is CharGen Face Preset
            TES5_Respawn = 0x00000008,
            TES5_AutoCalcStats = 0x00000010,
            TES5_Unique = 0x00000020,
            TES5_NoStealth = 0x00000040, // Doesn't affect stealth meter
            TES5_PCLevelMult = 0x00000080,
            // TES5_Unknown        = 0x00000100, // Audio template?
            TES5_Protected = 0x00000800,
            TES5_Summonable = 0x00004000,
            TES5_NoBleeding = 0x00010000,
            TES5_Owned = 0x00040000, // owned/follow? (Horses, Atronachs, NOT Shadowmere)
            TES5_GenderAnim = 0x00080000, // Opposite Gender Anims
            TES5_SimpleActor = 0x00100000,
            TES5_LoopedScript = 0x00200000, // AAvenicci, Arcadia, Silvia, Afflicted, TortureVictims
            TES5_LoopedAudio = 0x10000000, // AAvenicci, Arcadia, Silvia, DA02 Cultists, Afflicted, TortureVictims
            TES5_IsGhost = 0x20000000, // Ghost/non-interactable (Ghosts, Nocturnal)
            TES5_Invulnerable = 0x80000000
        };

        // All FO3+ games.
        enum TemplateFlags
        {
            Template_UseTraits = 0x0001, // Destructible Object; Traits tab, including race, gender, height, weight,
                                         // voice type, death item; Sounds tab; Animation tab; Character Gen tabs
            Template_UseStats = 0x0002, // Stats tab, including level, autocalc, skills, health/magicka/stamina,
                                        // speed, bleedout, class
            Template_UseFactions = 0x0004, // both factions and assigned crime faction
            Template_UseSpellList = 0x0008, // both spells and perks
            Template_UseAIData = 0x0010, // AI Data tab, including aggression/confidence/morality, combat style and
                                         // gift filter
            Template_UseAIPackage = 0x0020, // only the basic Packages listed on the AI Packages tab;
                                            // rest of tab controlled by Def Pack List
            Template_UseModel = 0x0040, // FO3, FONV; probably not used in TES5+
            Template_UseBaseData = 0x0080, // including name and short name, and flags for Essential, Protected,
                                           // Respawn, Summonable, Simple Actor, and Doesn't affect stealth meter
            Template_UseInventory = 0x0100, // Inventory tab, including all outfits and geared-up item,
                                            // but not death item
            Template_UseScript = 0x0200,

            // The following flags were added in TES5+:

            Template_UseDefined = 0x0400, // Def Pack List (the dropdown-selected package lists on the AI Packages tab)
            Template_UseAtkData = 0x0800, // Attack Data tab, including override from behavior graph race,
                                          // events, and data)
            Template_UseKeywords = 0x1000
        };

#pragma pack(push, 1)
        struct SkillValues
        {
            std::uint8_t armorer;
            std::uint8_t athletics;
            std::uint8_t blade;
            std::uint8_t block;
            std::uint8_t blunt;
            std::uint8_t handToHand;
            std::uint8_t heavyArmor;
            std::uint8_t alchemy;
            std::uint8_t alteration;
            std::uint8_t conjuration;
            std::uint8_t destruction;
            std::uint8_t illusion;
            std::uint8_t mysticism;
            std::uint8_t restoration;
            std::uint8_t acrobatics;
            std::uint8_t lightArmor;
            std::uint8_t marksman;
            std::uint8_t mercantile;
            std::uint8_t security;
            std::uint8_t sneak;
            std::uint8_t speechcraft;
        };

        struct HairColour
        {
            std::uint8_t red;
            std::uint8_t green;
            std::uint8_t blue;
            std::uint8_t custom; // alpha?
        };

        struct Data
        {
            SkillValues skills;
            std::uint32_t health;
            AttributeValues attribs;
        };

#pragma pack(pop)

        ESM::FormId mId; // from the header
        std::uint32_t mFlags; // from the header, see enum type RecordFlag for details

        bool mIsTES4;
        bool mIsFONV;
        bool mIsFO4 = false;

        std::string mEditorId;
        std::string mFullName;
        std::string mModel; // skeleton model (can be a marker in FO3/FONV)

        ESM::FormId mRace;
        ESM::FormId mClass;
        ESM::FormId mHair; // not for TES5, see mHeadParts
        ESM::FormId mEyes;

        std::vector<ESM::FormId> mHeadParts; // FO3/FONV/TES5

        float mHairLength;
        HairColour mHairColour; // TES4/FO3/FONV
        ESM::FormId mHairColourId; // TES5
        ESM::FormId mBeardColourId; // FO4

        ESM::FormId mDeathItem;
        std::vector<ESM::FormId> mSpell;
        ESM::FormId mScriptId;

        AIData mAIData;
        std::vector<ESM::FormId> mAIPackages; // seems to be in priority order, 0 = highest priority
        ActorBaseConfig mBaseConfig; // union
        ActorFaction mFaction;
        Data mData;
        ESM::FormId mCombatStyle;
        ESM::FormId mSoundBase;
        ESM::FormId mSound;
        std::uint8_t mSoundChance;
        float mFootWeight;

        float mBoundRadius;
        std::vector<std::string> mKf; // filenames only, get directory path from mModel

        std::vector<InventoryItem> mInventory;

        ESM::FormId mBaseTemplate; // FO3/FONV/TES5
        ESM::FormId mWornArmor; // TES5 only?

        ESM::FormId mDefaultOutfit; // TES5 OTFT
        ESM::FormId mSleepOutfit; // TES5 OTFT
        ESM::FormId mDefaultPkg;

        std::vector<float> mSymShapeModeCoefficients; // size 0 or 50
        std::vector<float> mAsymShapeModeCoefficients; // size 0 or 30
        std::vector<float> mSymTextureModeCoefficients; // size 0 or 50
        std::int16_t mFgRace;

        void load(ESM4::Reader& reader);
        // void save(ESM4::Writer& writer) const;

        // void blank();
        static constexpr ESM::RecNameInts sRecordId = ESM::RecNameInts::REC_NPC_4;
    };
}

#endif // ESM4_NPC__H
