// Config.cpp -- INI file management and global configuration
//
// Creates DDO_perf.ini with sensible defaults on first run, migrates
// missing keys into existing INI files, and parses all settings.
#include "Config.h"

static void EnsureIniSettingExists(const char* iniPath, const char* wantedKey, const char* defaultLine)
{
    FILE* f = fopen(iniPath, "r");
    if (!f)
        return;

    int found = 0;
    char line[256];
    while (fgets(line, sizeof(line), f)) {
        char key[64] = { 0 };
        float ignored = 0.0f;
        if (sscanf(line, " %63[^=] = %f", key, &ignored) == 2) {
            char* end = key + strlen(key) - 1;
            while (end >= key && (*end == ' ' || *end == '\t')) *end-- = '\0';
            if (strcmp(key, wantedKey) == 0) {
                found = 1;
                break;
            }
        }
    }
    fclose(f);

    if (found)
        return;

    f = fopen(iniPath, "a");
    if (!f)
        return;
    fputs(defaultLine, f);
    fclose(f);
}

void EnsureIniExists(const char* exeDir, char* outPath) {
    strncpy(outPath, exeDir, MAX_PATH - 1);
    strncat(outPath, "DDO_perf.ini", MAX_PATH - strlen(outPath) - 1);
    FILE* f = fopen(outPath, "r");
    if (!f) {
        f = fopen(outPath, "w");
        if (f) {
            fprintf(f,
                "FPS = 100\n"
                "Log = 0\n"
                "Debugging = 0\n"
                "LightFix = 1\n"
                "Wordwrap = 1\n"
                "DisableIdealProcessor = 0\n"
                "ThreadPriorityOverride = 99\n"
                "ParallelWorkers = 0\n"
                "MinParallelJobs = 0\n"
                "WorkerIdleSleepMs = 1\n"
                "D3D9StateCache = 0\n"
                "D3D9ShaderConstCache = 0\n"
                "DOF = 1\n"
                "ShadowSizeMul = 1.0\n"
            );
            fclose(f);
        }
    }
    else { fclose(f); }

    EnsureIniSettingExists(outPath, "FPS", "FPS = 100\n");
    EnsureIniSettingExists(outPath, "Log", "Log = 0\n");
    EnsureIniSettingExists(outPath, "Debugging", "Debugging = 0\n");
    EnsureIniSettingExists(outPath, "LightFix", "LightFix = 1\n");
    EnsureIniSettingExists(outPath, "Wordwrap", "Wordwrap = 1\n");
    EnsureIniSettingExists(outPath, "DisableIdealProcessor", "DisableIdealProcessor = 0\n");
    EnsureIniSettingExists(outPath, "ThreadPriorityOverride", "ThreadPriorityOverride = 99\n");
    EnsureIniSettingExists(outPath, "ParallelWorkers", "ParallelWorkers = 0\n");
    EnsureIniSettingExists(outPath, "MinParallelJobs", "MinParallelJobs = 0\n");
    EnsureIniSettingExists(outPath, "WorkerIdleSleepMs", "WorkerIdleSleepMs = 1\n");
    EnsureIniSettingExists(outPath, "D3D9StateCache", "D3D9StateCache = 0\n");
    EnsureIniSettingExists(outPath, "D3D9ShaderConstCache", "D3D9ShaderConstCache = 0\n");
    EnsureIniSettingExists(outPath, "DOF", "DOF = 1\n");
    EnsureIniSettingExists(outPath, "ShadowSizeMul", "ShadowSizeMul = 1.0\n");
}

// -------------------------------------------------------
// Global defaults (match INI defaults above)
// -------------------------------------------------------

// General
int   g_wordwrap                      = 1;
int   g_dof                           = 1;

// Thread scheduling
int   g_disableIdealProcessor         = 0;
int   g_threadPriorityOverride        = 99;
int   g_parallelWorkers               = 0;
int   g_minParallelJobs               = 0;
int   g_workerIdleSleepMs             = 1;

// D3D9 optimizations
int   g_d3d9StateCache                = 0;
int   g_d3d9ShaderConstCache          = 0;

// Shadow quality
float g_shadowSizeMul                 = 1.0f;

float ReadIniSettings(const char* iniPath, float defaultFps,
    int* outLog, int* outDebugging, int* outLightFix,
    int* outWordwrap,
    int* outDisableIdealProcessor, int* outThreadPriorityOverride,
    int* outParallelWorkers, int* outMinParallelJobs,
    int* outWorkerIdleSleepMs,
    int* outD3D9StateCache, int* outD3D9ShaderConstCache,
    int* outDOF,
    float* outShadowSizeMul)
{
    *outLog = 0; *outDebugging = 0; *outLightFix = 1;
    *outWordwrap = 1;
    *outDisableIdealProcessor = 0;
    *outThreadPriorityOverride = 99;
    *outParallelWorkers = 0;
    *outMinParallelJobs = 0;
    *outWorkerIdleSleepMs = 1;
    *outD3D9StateCache = 0;
    *outD3D9ShaderConstCache = 0;
    *outDOF = 1;
    *outShadowSizeMul = 1.0f;
    FILE* f = fopen(iniPath, "r");
    if (!f) return defaultFps;
    float result = defaultFps;
    char line[256];
    while (fgets(line, sizeof(line), f)) {
        char key[64] = { 0 }; float val = 0.0f;
        if (sscanf(line, " %63[^=] = %f", key, &val) == 2) {
            char* end = key + strlen(key) - 1;
            while (end >= key && (*end == ' ' || *end == '\t')) *end-- = '\0';
            if      (strcmp(key, "FPS")             == 0 && val > 0.0f) result = val;
            else if (strcmp(key, "Log")             == 0) *outLog             = (int)val ? 1 : 0;
            else if (strcmp(key, "Debugging")       == 0) *outDebugging       = (int)val ? 1 : 0;
            else if (strcmp(key, "LightFix")        == 0) *outLightFix        = (int)val ? 1 : 0;
            else if (strcmp(key, "Wordwrap")        == 0) *outWordwrap        = (int)val ? 1 : 0;
            else if (strcmp(key, "DisableIdealProcessor") == 0) *outDisableIdealProcessor = (int)val ? 1 : 0;
            else if (strcmp(key, "ThreadPriorityOverride") == 0) *outThreadPriorityOverride = (int)val;
            else if (strcmp(key, "ParallelWorkers") == 0) *outParallelWorkers = (int)val;
            else if (strcmp(key, "MinParallelJobs") == 0) *outMinParallelJobs = (int)val;
            else if (strcmp(key, "WorkerIdleSleepMs") == 0) *outWorkerIdleSleepMs = (int)val;
            else if (strcmp(key, "D3D9StateCache") == 0) *outD3D9StateCache = (int)val ? 1 : 0;
            else if (strcmp(key, "D3D9ShaderConstCache") == 0) *outD3D9ShaderConstCache = (int)val ? 1 : 0;
            else if (strcmp(key, "DOF") == 0) *outDOF = (int)val ? 1 : 0;
            else if (strcmp(key, "ShadowSizeMul") == 0) *outShadowSizeMul = val;
        }
    }
    fclose(f);
    return result;
}
