// AJM: ADDED THIS ENTIRE FILE IN

#include "csg.h"
#ifdef HLCSG_WADCFG

//#ifdef SYSTEM_WIN32
#if defined(SYSTEM_WIN32) && !defined( __GNUC__ )
#   include "atlbase.h" // win32 registry API
#pragma warning(disable:4996)
#else
char *g_apppath = NULL; //JK: Stores application path
#endif

#define WAD_CONFIG_FILE "wad.cfg"

typedef struct wadname_s 
{
    char                    wadname[_MAX_PATH];
    bool                    wadinclude;
    struct wadname_s*       next;
} wadname_t; 

typedef struct wadconfig_s
{
    char                    name[_MAX_PATH];
    int                     entries;
    wadname_t*              firstentry;
    wadconfig_s*            next;
} wadconfig_t;

wadconfig_t* g_WadCfg;  // anchor for the wadconfigurations linked list

bool        g_bWadConfigsLoaded = false;
int         g_wadcfglinecount = 1;

//JK: added in
char *g_wadcfgfile = NULL;

// little helper function
void stripwadpath (char *str)
{
    char *p = str + strlen (str) - 1;
    while ((*p == ' ' || *p == '\n' || *p == '\t') && p >= str) *p-- = '\0';
}

// =====================================================================================
//  WadCfgParseError
// =====================================================================================
void        WadCfgParseError(const char* message, int linenum, char* got)
{
    stripwadpath(got); // strip newlines

    Log("Error parsing " WAD_CONFIG_FILE ", line %i:\n"
        "%s, got '%s'\n", linenum, message, got);

    Log("If you need help on usage of the wad.cfg file, be sure to check http://www.zhlt.info/using-wad.cfg.html that came"
        " in the zip file with these tools.\n"); 

    g_bWadConfigsLoaded = false;
}

// ============================================================================
//  IsWhitespace
// ============================================================================
bool        IsWhitespace(const char ThinkChar)
{
    if ((ThinkChar == ' ') || (ThinkChar == '\t') || (ThinkChar == '\n') || (ThinkChar == 13) /* strange whitespace char */)
        return true;

    return false;
}

// ============================================================================
//  Safe_GetToken
// ============================================================================
void        Safe_GetToken(FILE* source, char* TokenBuffer, const unsigned int MaxBufferLength)
{
    char    ThinkChar[1];       // 2 char array = thinkchar and null terminator
    bool    InToken = false;    // are we getting a token?
    bool    InQuotes = false;   // are we in quotes?
    bool    InComment = false;  // are we in a comment (//)?
    //fpos_t* sourcepos;
    long    sourcepos;

    TokenBuffer[0] = '\0';
    ThinkChar[1] = '\0';
    
    while(!feof(source))
    {
        if (strlen(TokenBuffer) >= MaxBufferLength)
            return;     // we cant add any more chars onto the buffer, its maxed out

        ThinkChar[0] = fgetc(source);   
        
        if (ThinkChar[0] == '\n')              // newline
        {
            g_wadcfglinecount++;
            InComment = false;
        }

        if (ThinkChar[0] == '�')
            return;  
                
        if (IsWhitespace(ThinkChar[0]) && !InToken)
            continue;   // whitespace before token, ignore

        if (ThinkChar[0] == '"')               // quotes
        {
            if(InQuotes)
                InQuotes = false;
            else
                InQuotes = true;
            continue;   // dont include quotes
        }

        if (ThinkChar[0] == '/')             
        {   
            sourcepos = ftell(source);
            // might be a comment, see if the next char is a forward slash
            if (fgetc(source) == '/')    // if it is, were in a comment
            {
                InComment = true;
                continue;
            }
            else // if not, rewind pretend nothing happened...
            {
                fseek(source, sourcepos, 0);
            }
        }

        if (
             (IsWhitespace(ThinkChar[0]) && InToken && !InQuotes) // whitespace AFTER token and not in quotes
          || (InToken && InComment) // we hit a comment, and we have our token
           )
        {
            //printf("[gt: %s]\n", TokenBuffer);
            return;   
        }

        if (!InComment)
        {
            strcat(TokenBuffer, ThinkChar);
            InToken = true;
        }
    }
}

// =====================================================================================
//  GetWadConfig
//      return true if we didnt encounter any fatal errors
#define MAX_TOKENBUFFER _MAX_PATH
// =====================================================================================
bool        GetWadConfig(FILE* wadcfg, wadconfig_t* wadconfig)
{
    char            TokenBuffer[MAX_TOKENBUFFER];
    wadname_t*      current;
    wadname_t*      previous;

    while (!feof(wadcfg))
    {
        Safe_GetToken(wadcfg, TokenBuffer, MAX_TOKENBUFFER);

        if (!strcmp(TokenBuffer, "}"))
            return true; // no more work to do
        
        if (!strcmp(TokenBuffer, ";"))
            continue; // old seperator, no longer used but here for backwards compadibility

        if (!strcmp(TokenBuffer, "{"))  // wtf
        {
            WadCfgParseError("Expected wadpath (Nested blocks illegal)", g_wadcfglinecount, TokenBuffer);
            return false;
        }

        // otherwise assume its a wadpath, make an entry in this configuration
        current = (wadname_t*)malloc(sizeof(wadname_t));
        wadconfig->entries++;
        current->next = NULL;
        current->wadinclude = false;

        if (!strcmp(TokenBuffer, "include"))
        {
            current->wadinclude = true;
            Safe_GetToken(wadcfg, TokenBuffer, MAX_TOKENBUFFER);
        }
        
        strcpy_s(current->wadname, TokenBuffer);
        
        if (!wadconfig->firstentry)
        {
            wadconfig->firstentry = current;
        }
        else
        {
            previous->next = current;
        }

        previous = current;
        previous->next = NULL;
    }

    safe_snprintf(TokenBuffer, MAX_TOKENBUFFER, "Unexptected end of file encountered while parsing configuration '%s'", wadconfig->name);
    WadCfgParseError(TokenBuffer, g_wadcfglinecount, "(eof)");
    return false; 
}
#undef MAX_TOKENBUFFER

// =====================================================================================
//  LoadWadConfigFile
// =====================================================================================
void        LoadWadConfigFile()
{
    FILE*           wadcfg;
    wadconfig_t*    current;
    wadconfig_t*    previous;

    char            temp[_MAX_PATH];

    //JK: If exists lets use user-defined file
    if (g_wadcfgfile && q_exists(g_wadcfgfile))
    {
    	wadcfg = fopen(g_wadcfgfile, "r");
    }
    else // find the wad.cfg file
    {
        char    appdir[_MAX_PATH];
        char    tmp[_MAX_PATH];
                
        memset(tmp, 0, sizeof(tmp));
        memset(appdir, 0, sizeof(appdir));

        // Get application directory (only an approximation on posix systems)
        // try looking in the directory we were run from
        #ifdef SYSTEM_WIN32
        GetModuleFileName(NULL, tmp, _MAX_PATH);
        #else
        safe_strncpy(tmp, g_apppath, _MAX_PATH);
        #endif
    
        ExtractFilePath(tmp, appdir);
        safe_snprintf(tmp, _MAX_PATH, "%s%s", appdir, WAD_CONFIG_FILE);

        #ifdef _DEBUG
        Log("[dbg] Trying '%s'\n", tmp);
        #endif

        if (!q_exists(tmp))
        {
            // try the Half-Life directory
            #ifdef SYSTEM_WIN32
            {
                HKEY        HLMachineKey;
                DWORD       disposition;
                DWORD       dwType, dwSize;

                // REG: create machinekey
                RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Valve\\Half-Life"), 0, NULL,  
                                                        0, 0, NULL, &HLMachineKey, &disposition);
                // REG: get hl dir 
                dwType = REG_SZ;
                dwSize = _MAX_PATH;
                RegQueryValueEx(HLMachineKey, TEXT("InstallPath"), NULL, &dwType, (PBYTE)&appdir, &dwSize);
            }
            
            safe_strncpy(tmp, appdir, _MAX_PATH);
            safe_strncat(tmp, SYSTEM_SLASH_STR, _MAX_PATH); // system slash pointless as this will only work on win32, but anyway...
            safe_strncat(tmp, WAD_CONFIG_FILE, _MAX_PATH);

            #ifdef _DEBUG
            Log("[dbg] Trying '%s'\n", tmp);
           #endif

            if (!q_exists(tmp))
            #endif  // SYSTEM_WIN32
            {
                // still cant find it, error out
                Log("Warning: could not find wad configurations file\n"
                    "Make sure that wad.cfg is in the Half-Life directory or the current working directory\n"
                   );
                return;
            }
        }

        wadcfg = fopen(tmp, "r");
    }

    if (!wadcfg)
    {
        // cant open it, die
        Log("Warning: could not open the wad configurations file\n"
            "Make sure that wad.cfg is in the Half-Life directory or the current working directory\n"
            );
        return;
    }

    while(!feof(wadcfg))
    {
        Safe_GetToken(wadcfg, temp, MAX_WAD_CFG_NAME);

        if (!strcmp(temp, "HalfLifePath="))  // backwards compadibitly
        {
            Safe_GetToken(wadcfg, temp, MAX_WAD_CFG_NAME); 
            Warning("Redundant line in " WAD_CONFIG_FILE ": \"HalfLifePath= %s\" - Ignoring...\n",
                temp);
            continue;
        }

        if (feof(wadcfg))
            break;

        // assume its the name of a configuration
        current = (wadconfig_t*)malloc(sizeof(wadconfig_t));
        safe_strncpy(current->name, temp, _MAX_PATH);
        current->entries = 0;
        current->next = NULL;
        current->firstentry = NULL;

        // make sure the next char starts a wad configuration
        Safe_GetToken(wadcfg, temp, _MAX_PATH);
        if (strcmp(temp, "{"))
        {
            WadCfgParseError("Expected start of wadfile configuration, '{'", g_wadcfglinecount, temp);
            //Log("[dbg] temp[0] is %i\n", temp[0]);
            fclose(wadcfg);
            return;
        }

        // otherwise were ok, get the definition
        if (!GetWadConfig(wadcfg, current))
        {
            fclose(wadcfg);
            return;
        }

        // add this config to the list
        if (!g_WadCfg)
        {
            g_WadCfg = current;
        }
        else
        {
            previous->next = current;
        }

        previous = current;
        previous->next = NULL;
    }

    g_bWadConfigsLoaded = true;
}

// =====================================================================================
//  ProcessWadConfiguration
// =====================================================================================
void        ProcessWadConfiguration()
{
    int             usedwads = 0;
    char            szTmp[1024]; // arbitrary, but needs to be large. probably bigger than this.
    wadconfig_t*    config;
    wadname_t*      path;

    if(!g_bWadConfigsLoaded) // we did a graceful exit due to some warning/error, so dont complain about it
    {
        Log("Using mapfile wad configuration\n");
        return;
    }

    szTmp[0] = 0;
    config = g_WadCfg;

    if (!wadconfigname)
        return; // this should never happen

    if (!config)
    {
        Warning("No configurations detected in wad.cfg\n"
                "using map wad configuration");
        return;
    }

    while (1)
    {
        if (!strcmp(config->name, wadconfigname))
        {
            path = config->firstentry;
            while (1)
            {
                if (!path)
                    break;

                Verbose("Wadpath from wad.cfg: '%s'\n", path->wadname);
                PushWadPath(path->wadname, true);
                safe_snprintf(szTmp, 1024, "%s%s;", szTmp, path->wadname);
                usedwads++;

                if (path->wadinclude)
                    g_WadInclude.push_back(path->wadname);

                // next path
                path = path->next;
            }
            break;  // the user can only specify one wad configuration, were done here
        }

        // next config
        config = config->next;
        if (!config)
            break;
    }
    
    if (usedwads)
    {
        Log("Using custom wadfile configuration: '%s' (with %i wad%s)\n", wadconfigname, usedwads, usedwads > 1 ? "s" : "");
        SetKeyValue(&g_entities[0], "wad", szTmp);
        SetKeyValue(&g_entities[0], "_wad", szTmp);    
    }
    else
    {
        Warning("no wadfiles are specified in configuration '%s' --\n"
                "Using map wadfile configuration", wadconfigname);
        g_bWadConfigsLoaded = false;
    }

    return;
}

// =====================================================================================
//  WadCfg_cleanup
// =====================================================================================
void        WadCfg_cleanup()
{
    wadconfig_t*    config;
    wadconfig_t*    nextconfig;
    wadname_t*      path;
    wadname_t*      nextpath;

    config = g_WadCfg;
    while (config)
    {
        path = config->firstentry;
        while (path)
        {
            nextpath = path->next;
            free(path);
            path = nextpath;
        }

        nextconfig = config->next;
        free(config);
        config = nextconfig;
    }

	g_WadCfg = NULL;
	g_bWadConfigsLoaded = false;
    return;
}



#endif // HLCSG_WADCFG