//
// Project UnReality: The First Nintendo 64 Emulator
// Copyright (C) 1997-1998, Cold Fusion Entertainment
// All rights reserved
//
// This source code is unpublished propietary information of Cold Fusion Entertainment.  No portion of this software
// may be disclosed to any third party or copied or duplicated in any form, in whole or in part, without the prior
// written consent of Cold Fusion Entertainment.
// 

//
// $Log: cod_map.cpp $
// Revision 1.4  1998/05/25 20:55:58  BREAKPOINT
// Removed debugger code from release builds.  Only usable when _DEBUG is #defined (a debug build).
// Revision 1.3  1998/04/02 21:48:47  BREAKPOINT
// Changed MessageBox()es to have a heading of "Notice" instead of "Error".
// Revision 1.2  1998/03/29 20:18:43  BREAKPOINT
// Fixed crash problem when loading file with no extension.
// Revision 1.1  1998/03/22 17:44:58  BREAKPOINT
// Initial revision
//

static char *rcsid = "$Id: cod_map.cpp 1.4 1998/05/25 20:55:58 BREAKPOINT Exp $";

//---------------------------------------------------------------------------------------------------------------------

#include <stdio.h>
#include <windows.h>
#include <types.h>

#include "unreal.h"
#include "cod_map.h"

CODMAPNode *FirstCODMAPNode = NULL;
CODMAPNode *LastCODMAPNode = NULL;

CODMAPNode *AddCODMAPNode(void)
{
    if (FirstCODMAPNode == NULL)
    {
        FirstCODMAPNode = new CODMAPNode;
        FirstCODMAPNode->prev = NULL;
        FirstCODMAPNode->next = NULL;

        LastCODMAPNode = FirstCODMAPNode;
    }
    else
    {
        FirstCODMAPNode->prev = new CODMAPNode;
        FirstCODMAPNode->prev->prev = NULL;
        FirstCODMAPNode->prev->next = FirstCODMAPNode;

        FirstCODMAPNode = FirstCODMAPNode->prev;
    }

    return FirstCODMAPNode;
}

CODMAPNode *FindCODMAPNode(ulong PC)
{
    CODMAPNode *cm;

    cm = FirstCODMAPNode;
    while (cm)
    {
        if (cm->PC == PC)
            return cm;

        cm = cm->next;
    }

    return NULL;
}

void RemoveCODMAPNode(CODMAPNode *cm)
{
    CODMAPNode *Current;

    if (cm == NULL) return;

    Current = LastCODMAPNode;
    while ((Current != NULL) && (Current->PC != cm->PC))
        Current = Current->prev;

    // Not found!
    if (Current == NULL) return;

    // Remove symbol memory first.
    delete []Current->symbol;

    // Now remove from list.
    if ((Current->next == NULL) && (Current->prev == NULL))
    {
        // Only one in list...
        FirstCODMAPNode = NULL;
        LastCODMAPNode  = NULL;
    }
    else
    {
        if (Current->next == NULL)
        {
            // Last one in list...
            LastCODMAPNode = Current->prev;
            LastCODMAPNode->next = NULL;
        }
        else
        {
            if (Current->prev == NULL)
            {
                // First one in list...
                FirstCODMAPNode = FirstCODMAPNode->next;
                FirstCODMAPNode->prev = NULL;
            }
            else
            {
                // Somewhere in the middle...
                Current->next->prev = Current->prev;
                Current->prev->next = Current->next;
            }
        }
    }

    delete Current;
}

void LoadCOD(char *fname)
{
    FILE *fp;
    char buf[256], *ptr, temp_symbol[256];
    CODMAPNode *cm;

    fp = fopen(fname, "rt");
    if (fp == NULL) return;

    for (;;)
    {
        fgets(buf, 256, fp);
        if (feof(fp))
        {
            fclose(fp);
			sprintf(buf, "%s successfully loaded\n", fname);
			MessageBox(MainhWnd, buf, "Notice", MB_OK);
            return;
        }

        // Point two bytes into line (skipping over '0x'), and then spacing out the ','.
        ptr = &buf[2];
        *(ptr + 8) = ' ';

        cm = AddCODMAPNode();
        sscanf(ptr, "%08x %s", &cm->PC, temp_symbol);

        // Trim off LF.
        temp_symbol[strlen(temp_symbol)] = 0;
        cm->symbol = new char[strlen(temp_symbol) + 1];
        strcpy(cm->symbol, temp_symbol);
    }
}

void LoadMAP(char *fname)
{
    FILE *fp;
    char buf[256], str1[256], str2[256], temp_symbol[256];
    CODMAPNode *cm;
    bool done;

    fp = fopen(fname, "rt");
    if (fp == NULL) return;

    // Read lines until 'Address Names' is encountered.
    done = FALSE;
    while (!done)
    {
        fgets(buf, 256, fp);
        if (feof(fp))
        {
            fclose(fp);
            return;
        }

        sscanf(buf, "%s %s", str1, str2);
        if (!strcmp(str1, "Address") && !strcmp(str2, "Names")) done = TRUE;
    }

    // Now load the MAP.
    for (;;)
    {
        fgets(buf, 256, fp);
        if (feof(fp) || buf[0] == '\r' || buf[0] == '\n')
        {
            fclose(fp);
			sprintf(buf, "%s successfully loaded\n", fname);
			MessageBox(MainhWnd, buf, "Notice", MB_OK);
            return;
        }

        cm = AddCODMAPNode();
        sscanf(buf, "%08X %s", &cm->PC, temp_symbol);

        // Trim off LF.
        temp_symbol[strlen(temp_symbol)] = 0;
        cm->symbol = new char[strlen(temp_symbol) + 1];
        strcpy(cm->symbol, temp_symbol);
    }
}

void LoadCOD_MAP(char *fname)
{
    char *ptr, buf[256];

#ifdef _DEBUG
    // Free any current stuff that might be loaded.
    FreeCOD_MAP();

    // Slap on a new extension and try to load both types.
    strcpy(buf, fname);
    ptr = strchr(buf, '.');
	if (ptr != NULL)
	{
		*(ptr + 1) = 'C';
		*(ptr + 2) = 'O';
		*(ptr + 3) = 'D';
		*(ptr + 4) = 0;
	}
	else
	{
		strcat(buf, ".COD");
	}
    LoadCOD(buf);

    strcpy(buf, fname);
    ptr = strchr(buf, '.');
	if (ptr != NULL)
	{
		*(ptr + 1) = 'M';
		*(ptr + 2) = 'A';
		*(ptr + 3) = 'P';
		*(ptr + 4) = 0;
	}
	else
	{
		strcat(buf, ".MAP");
	}
    LoadMAP(buf);
#endif // _DEBUG
}

void FreeCOD_MAP(void)
{
    while (FirstCODMAPNode)
        RemoveCODMAPNode(FirstCODMAPNode);
}
