//::///////////////////////////////////////////////
//:: PRC On Module Load event handler
//:: prc_onmodload
//::///////////////////////////////////////////////
/** @file prc_onmodload
    Things we need to happen upon a module being
    loaded. For example, setting up caches and
    switches.

*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////

#include "prc_alterations"
#include "prc_inc_leadersh"
#include "inc_switch_setup"
#include "inc_cache_setup"
#include "inc_sql"


//////////////////////////////////////////////////
/*             Function prototypes              */
//////////////////////////////////////////////////

void OnLoad_Always(object oModule);
void OnLoad_Save(object oModule);
void OnLoad_Fresh(object oModule);
void PersonalSwitch(object oModule);

//////////////////////////////////////////////////
/*             Function definitions             */
//////////////////////////////////////////////////

void CheckDB()
{
    string sDBName = GetBiowareDBName();
    //check PRC version
    if(GetCampaignString(sDBName, "version") != PRC_VERSION)
    {
        DoDebug("Removing old PRC version databases");
        DestroyCampaignDatabase(sDBName);
        DestroyCampaignDatabase(COHORT_DATABASE);
    }
    SetCampaignString(sDBName, "version", PRC_VERSION);

    // 2da cache fingerprint handling
    // This is for detecting a cache updated by someone else upon loading a saved game
    // and avoiding clobbering it.
    string sFingerprint;

    // Generate the fingerprint from module name, current millisecond value and
    // 31-bit random number.
    sFingerprint = GetModuleName() + "_" + IntToString(GetTimeMillisecond()) + "_" + IntToString(Random(0x7fffffff));

    DoDebug("Module 2da cache fingerprint: " + sFingerprint);

    // Store the fingerprint on the module - it will be written to the DB upon cache storage
    SetLocalString(GetModule(), "PRC_2DA_Cache_Fingerprint", sFingerprint);

    // Also store the fingerprint of the DB we will be loading shortly
    SetLocalString(GetModule(), "PRC_2DA_Cache_Fingerprint_LastAccessed", GetCampaignString(sDBName,  "PRC_2DA_Cache_Fingerprint"));

    location lLoc = GetLocation(GetObjectByTag("HEARTOFCHAOS"));
    // only get it if one doesnt already exist (saved games)
    // This never gets run on saved games due to the "prc_mod_load_done" check.
    // However, it is still usefull cleanup in case some unforseen condition does
    // leave a cache object present in a freshly loaded module - Ornedan 20061229
    if(GetIsObjectValid(GetObjectByTag("Bioware2DACache")))
        DestroyObject(GetObjectByTag("Bioware2DACache"));
    DoDebug("Starting to load 2da cache object from " + sDBName);
    object oChest = RetrieveCampaignObject(sDBName, "CacheChest", lLoc);
    if(!GetIsObjectValid(oChest))
    {
        DoDebug("WARNING: Unable to load 2da cache object (CacheChest) from " + sDBName);
        oChest = CreateObject(OBJECT_TYPE_CREATURE, "prc_2da_cache", lLoc, FALSE, "Bioware2DACache");
    }
    else
    {
        DoDebug("Finished loading 2da cache object from " + sDBName);
    }

    //DB is ready run 2da lookup stuff
    DelayCommand(0.1f, RunLookupLoop());
}

/**
 * Called when a saved game load is detected. Determines if the
 * 2da cache DB has changed in the meanwhile. If it has, reload the
 * cache creature from the DB.
 */
void CheckDBUpdate()
{
    // Get last loaded (or saved) and DB fingerprints
    string sDBName = GetBiowareDBName();
    string sModuleFingerprint = GetLocalString(GetModule(), "PRC_2DA_Cache_Fingerprint_LastAccessed");
    string sDBFingerprint     = GetCampaignString(sDBName,  "PRC_2DA_Cache_Fingerprint");

    DoDebug("CheckDBUpdate():\n"
          + " Module last access fingerprint: " + sModuleFingerprint + "\n"
          + " Database fingerprint: " + sDBFingerprint
            );
    // If they differ, the DB has changed in meanwhile and we need to reload the cache chest
    if(sModuleFingerprint != sDBFingerprint)
    {
        DoDebug("Fingerprint mismatch, reloading 2da cache from " + sDBName);
        location lLoc = GetLocation(GetObjectByTag("HEARTOFCHAOS"));
        DestroyObject(GetObjectByTag("Bioware2DACache"));

        DoDebug("Starting to load 2da cache object from " + sDBName);
        object oChest = RetrieveCampaignObject(sDBName, "CacheChest", lLoc);
        if(!GetIsObjectValid(oChest))
            DoDebug("ERROR: Unable to load 2da cache object (CacheChest) from " + sDBName);
        else
        {
            DoDebug("Finished loading 2da cache object from " + sDBName);

            //DB is ready run 2da lookup stuff
            DelayCommand(0.1f, RunLookupLoop());
        }

        // Updated last access fingerprint
        SetLocalString(GetModule(), "PRC_2DA_Cache_Fingerprint_LastAccessed", sDBFingerprint);
    }
}

void CheckXPSwitches(object oModule)
{
    if(!GetLocalInt(oModule, PRC_XP_PC_PARTY_COUNT_x100))//player will get 0 xp for kills - we assume that the XP system was not setup
    {
        SetLocalInt(oModule, PRC_XP_SLIDER_x100, 100);
        SetLocalInt(oModule, PRC_XP_GROUP_BONUS, 10);
        SetLocalInt(oModule, PRC_XP_PC_PARTY_COUNT_x100, 100);
        SetLocalInt(oModule, PRC_XP_DOMINATED_PARTY_COUNT_x100, 0);
        SetLocalInt(oModule, PRC_XP_HENCHMAN_PARTY_COUNT_x100, 50);
        SetLocalInt(oModule, PRC_XP_UNKNOWN_PARTY_COUNT_x100, 0);
        SetLocalInt(oModule, PRC_XP_SUMMONED_PARTY_COUNT_x100, 0);
        SetLocalInt(oModule, PRC_XP_FAMILIAR_PARTY_COUNT_x100, 0);
        SetLocalInt(oModule, PRC_XP_ANIMALCOMPANION_PARTY_COUNT_x100, 0);
        SetLocalInt(oModule, PRC_XP_MUST_BE_IN_AREA, 1);
        SetLocalInt(oModule, PRC_XP_MAX_PHYSICAL_DISTANCE, 100);
    }
    //
    if(!GetLocalInt(oModule, PRC_XP_MAX_LEVEL_DIFF))
        SetLocalInt(oModule, PRC_XP_MAX_LEVEL_DIFF, 5);
}

void main()
{
    object oModule = GetModule();
    PersonalSwitch(oModule);

    OnLoad_Always(oModule);

    // Determine if we are loading a saved game or entering a fresh module
    // Some things should only be run in one situation or the other.
    if(GetLocalInt(oModule, "prc_mod_load_done"))
    {
        OnLoad_Save(oModule);
    }
    else
    {
        SetLocalInt(oModule, "prc_mod_load_done", TRUE);
        OnLoad_Fresh(oModule);
    }

    //NWNX_Funcs plugin test:
    PRC_Funcs_Init(oModule);
}

/**
 * Things that should always be run on loading a module,
 * irrespective of whether it's a fresh load or a save.
 */
void OnLoad_Always(object oModule)
{
    //this triggers NWNX on Linux
    SetLocalInt(oModule, "NWNX!INIT", 1);
    SetLocalString(oModule, "NWNX!INIT", "1"); 
}

/**
 * Things that should be run only when a saved game is loaded.
 */
void OnLoad_Save(object oModule)
{
    CheckDBUpdate();
}

/**
 * Things that should only be run when a module is first loaded.
 */
void OnLoad_Fresh(object oModule)
{
    // Set PRC presence & version marker. If plugins ever happen, this would be useful.
    SetLocalString(oModule, "PRC_VERSION", PRC_VERSION);

    SetModuleSwitch(MODULE_SWITCH_ENABLE_TAGBASED_SCRIPTS, TRUE); /// @todo This is somewhat intrusive, make it unnecessary and remove

    // Run a script to determine if the PRC Companion is present
    ExecuteScript("hakmarker", OBJECT_SELF);

    //delay this to avoid TMIs
    DelayCommand(0.01, CreateSwitchNameArray());
    DelayCommand(0.01, DoEpicSpellDefaults());
    DelayCommand(0.01, DoSamuraiBanDefaults());
    SetDefaultFileEnds();
    if(GetPRCSwitch(PRC_CONVOCC_ENABLE))
    {
        SetPRCSwitch(PRC_USE_DATABASE, TRUE);
        //SetPRCSwitch(PRC_DB_PRECACHE, TRUE);
        SetPRCSwitch(PRC_USE_LETOSCRIPT, TRUE);
        // set up the convoCC combination switches
        if(GetPRCSwitch(PRC_CONVOCC_ENFORCE_FEATS))
        {
            SetPRCSwitch(PRC_CONVOCC_ENFORCE_BLOOD_OF_THE_WARLORD, TRUE);
            SetPRCSwitch(PRC_CONVOCC_ENFORCE_FEAT_NIMBUSLIGHT, TRUE);
            SetPRCSwitch(PRC_CONVOCC_ENFORCE_FEAT_HOLYRADIANCE, TRUE);
            SetPRCSwitch(PRC_CONVOCC_ENFORCE_FEAT_SERVHEAVEN, TRUE);
            SetPRCSwitch(PRC_CONVOCC_ENFORCE_FEAT_SAC_VOW, TRUE);
            SetPRCSwitch(PRC_CONVOCC_ENFORCE_FEAT_VOW_OBED, TRUE);
            SetPRCSwitch(PRC_CONVOCC_ENFORCE_FEAT_THRALL_TO_DEMON, TRUE);
            SetPRCSwitch(PRC_CONVOCC_ENFORCE_FEAT_DISCIPLE_OF_DARKNESS, TRUE);
            SetPRCSwitch(PRC_CONVOCC_ENFORCE_FEAT_LICHLOVED, TRUE);
            SetPRCSwitch(PRC_CONVOCC_ENFORCE_FEAT_EVIL_BRANDS, TRUE);
            SetPRCSwitch(PRC_CONVOCC_ENFORCE_FEAT_VILE_WILL_DEFORM, TRUE);
            SetPRCSwitch(PRC_CONVOCC_ENFORCE_FEAT_VILE_DEFORM_OBESE, TRUE);
            SetPRCSwitch(PRC_CONVOCC_ENFORCE_FEAT_VILE_DEFORM_GAUNT, TRUE);
            SetPRCSwitch(PRC_CONVOCC_ENFORCE_FEAT_LOLTHS_MEAT, TRUE);
        }
        if(GetPRCSwitch(PRC_CONVOCC_ENFORCE_PNP_RACIAL))
        {
            SetPRCSwitch(PRC_CONVOCC_RAKSHASA_FEMALE_APPEARANCE, TRUE);
            SetPRCSwitch(PRC_CONVOCC_GENASI_ENFORCE_DOMAINS, TRUE);
            SetPRCSwitch(PRC_CONVOCC_DROW_ENFORCE_GENDER, TRUE);
            SetPRCSwitch(PRC_CONVOCC_TIEFLING_TAIL, TRUE);
            SetPRCSwitch(PRC_CONVOCC_FEYRI_TAIL, TRUE);
            SetPRCSwitch(PRC_CONVOCC_FEYRI_WINGS, TRUE);
            SetPRCSwitch(PRC_CONVOCC_AVARIEL_WINGS, TRUE);
        }
    }
    if(GetPRCSwitch(PRC_USE_BIOWARE_DATABASE) == 0)
        SetPRCSwitch(PRC_USE_BIOWARE_DATABASE, 300);//100 HBs = 1800sec = 30min
    if(GetPRCSwitch(PRC_USE_BIOWARE_DATABASE))
        DelayCommand(0.1, CheckDB());

    if(GetPRCSwitch(PRC_USE_DATABASE))
    {
        PRC_SQLInit();
        if(GetPRCSwitch(PRC_DB_SQLITE))
        {
            StartSQLiteCommitHB();
            CreateXChestDB_SQLite();
        }
        else if(GetPRCSwitch(PRC_DB_MYSQL))
            CreateXChestDB_MySQL();
    }
    if(GetPRCSwitch(PRC_DB_PRECACHE))
        Cache_2da_data();

    // Disable Bioware XP as it's being handled by PRC
    if(GetPRCSwitch(PRC_XP_USE_PNP_XP))
    {
        SetModuleXPScale(0);
        DelayCommand(5.0f, CheckXPSwitches(oModule));
    }

    //pre-made cohorts
    //DelayCommand(6.0, AddPremadeCohortsToDB());
    //done differently now

    //check for letoscript dir
    /*    if(GetLocalString(oModule, PRC_LETOSCRIPT_NWN_DIR) == "")
    {
        string sDir = Get2DACache("directory", "Dir", 0);
        if(sDir != "")
            SetLocalString(oModule, PRC_LETOSCRIPT_NWN_DIR, sDir);
    } */

    //mark server as loading
    float fDelay = IntToFloat(GetPRCSwitch(PRC_PW_LOGON_DELAY))*60.0;
    if(fDelay>0.0)
    {
        SetLocalInt(GetModule(), PRC_PW_LOGON_DELAY+"_TIMER", TRUE);
        DelayCommand(fDelay, DeleteLocalInt(GetModule(), PRC_PW_LOGON_DELAY+"_TIMER"));
    }
}

void PersonalSwitch(object oModule)
{
    DoDebug("PersonalSwitch Running");
    //load any default switch 2da
    int i = 0;
    string sSwitchName, sSwitchType, sSwitchValue;
    // Use Get2DAString() instead of Get2DACache() to avoid caching.
    // People might want to set different switch values when playing in different modules.
    // Or just change the switch values midplay.
    sSwitchName = Get2DAString("personal_switch", "SwitchName", i);
    while(sSwitchName != "") // Brute force
    {
        DoDebug("SwitchName: "+sSwitchName);
        // Read rest of the line
        sSwitchType  = Get2DAString("personal_switch", "SwitchType",  i);
        sSwitchValue = Get2DAString("personal_switch", "SwitchValue", i);
        DoDebug("SwitchType: "+sSwitchType);
        DoDebug("SwitchValue: "+sSwitchValue);

        // Determine switch type and set the var
        if     (sSwitchType == "float")
            SetLocalFloat(oModule, sSwitchName, StringToFloat(sSwitchValue));
        else if(sSwitchType == "int")
            SetPRCSwitch(sSwitchName, StringToInt(sSwitchValue));
        else if(sSwitchType == "string")
            SetLocalString(oModule, sSwitchName, sSwitchValue);

        // Increment loop counter
        i += 1;
        sSwitchName = Get2DAString("personal_switch", "SwitchName", i);
    }  
}