#include "builddefines.h"

#ifdef PRECOMPILEDHEADERS
	#include "TileEngine All.h"
#else
	#include "debug.h"
	#include "Debug Control.h"
	#include "tile surface.h"
	#include "tile cache.h"
#endif
#ifdef JA2TESTVERSION
	#include "sys globals.h"
#endif

UINT32	guiNumTileCacheStructs = 0;
UINT32 guiMaxTileCacheSize		= 50;
UINT32 guiCurTileCacheSize		= 0;
INT32	giDefaultStructIndex	= -1;

TILE_CACHE_ELEMENT		*gpTileCache = NULL;
TILE_CACHE_STRUCT			*gpTileCacheStructInfo = NULL;



BOOLEAN InitTileCache(	)
{
	UINT32				cnt;
	GETFILESTRUCT FileInfo;
	INT16					sFiles = 0;

	gpTileCache = (TILE_CACHE_ELEMENT *)MemAlloc( sizeof( TILE_CACHE_ELEMENT ) * guiMaxTileCacheSize );

	// Zero entries
	for ( cnt = 0; cnt < guiMaxTileCacheSize; cnt++ )
	{
		gpTileCache[ cnt ].pImagery = NULL;
		gpTileCache[ cnt ].sStructRefID = -1;
	}

	guiCurTileCacheSize = 0;


	// OK, look for JSD files in the tile cache directory and
	// load any we find....
	if( GetFileFirst("TILECACHE\\*.jsd", &FileInfo) )
	{
		while( GetFileNext(&FileInfo) )
		{
			sFiles++;
		}
		GetFileClose(&FileInfo);
	}

	// Allocate memory...
	if ( sFiles > 0 )
	{
		cnt = 0;

		guiNumTileCacheStructs = sFiles;

		gpTileCacheStructInfo = (TILE_CACHE_STRUCT *)MemAlloc( sizeof( TILE_CACHE_STRUCT ) * sFiles );

		// Loop through and set filenames
		if( GetFileFirst("TILECACHE\\*.jsd", &FileInfo) )
		{
			while( GetFileNext(&FileInfo) )
			{
				sprintf( gpTileCacheStructInfo[ cnt ].Filename, "TILECACHE\\%s", FileInfo.zFileName );

				// Get root name
				GetRootName( gpTileCacheStructInfo[ cnt ].zRootName, gpTileCacheStructInfo[ cnt ].Filename );

				// Load struc data....
				gpTileCacheStructInfo[ cnt ].pStructureFileRef = LoadStructureFile( gpTileCacheStructInfo[ cnt ].Filename );

#ifdef JA2TESTVERSION
				if ( gpTileCacheStructInfo[ cnt ].pStructureFileRef == NULL )
				{
					SET_ERROR(	"Cannot load tilecache JSD: %s", gpTileCacheStructInfo[ cnt ].Filename );
				}
#endif
		if ( _stricmp( gpTileCacheStructInfo[ cnt ].zRootName, "l_dead1" ) == 0 )
		{
			giDefaultStructIndex = cnt;
		}

				cnt++;
			}
			GetFileClose(&FileInfo);
		}
	}

	return( TRUE );
}

void DeleteTileCache( )
{
	UINT32 cnt;

	// Allocate entries
	if ( gpTileCache != NULL )
	{
		// Loop through and delete any entries
		for ( cnt = 0; cnt < guiMaxTileCacheSize; cnt++ )
		{
			if ( gpTileCache[ cnt ].pImagery != NULL )
			{
				DeleteTileSurface( gpTileCache[ cnt ].pImagery );
			}
		}
		MemFree( gpTileCache );
	}

	if ( gpTileCacheStructInfo != NULL )
	{
		MemFree( gpTileCacheStructInfo );
	}

	guiCurTileCacheSize = 0;
}

INT16 FindCacheStructDataIndex( STR8 cFilename )
{
	UINT32 cnt;

	for ( cnt = 0; cnt < guiNumTileCacheStructs; cnt++ )
	{
		if ( _stricmp( gpTileCacheStructInfo[ cnt ].zRootName, cFilename ) == 0 )
		{
			return(	(INT16)cnt );
		}
	}

	return( -1 );
}

INT32 GetCachedTile( const STR8 cFilename )
{
	UINT32			cnt;
	UINT32			ubLowestIndex = 0;
	INT16		sMostHits = (INT16)15000;

	// Check to see if surface exists already
	for ( cnt = 0; cnt < guiCurTileCacheSize; cnt++ )
	{
		if ( gpTileCache[ cnt ].pImagery != NULL )
		{
			if ( _stricmp( gpTileCache[ cnt ].zName, cFilename ) == 0 )
			{
				// Found surface, return
				gpTileCache[ cnt ].sHits++;
				return( (INT32)cnt );
			}
		}
	}

	// Check if max size has been reached
	if ( guiCurTileCacheSize == guiMaxTileCacheSize )
	{
		// cache out least used file
		for ( cnt = 0; cnt < guiCurTileCacheSize; cnt++ )
		{
			if ( gpTileCache[ cnt ].sHits < sMostHits )
			{
					sMostHits = gpTileCache[ cnt ].sHits;
					ubLowestIndex = cnt;
			}
		}

		// Bump off lowest index
		DeleteTileSurface( gpTileCache[ ubLowestIndex ].pImagery );

		// Decrement
		gpTileCache[ ubLowestIndex ].sHits = 0;
		gpTileCache[ ubLowestIndex ].pImagery = NULL;
		gpTileCache[ ubLowestIndex ].sStructRefID = -1;
	}

	// If here, Insert at an empty slot
	// Find an empty slot
	for ( cnt = 0; cnt < guiMaxTileCacheSize; cnt++ )
	{
		if ( gpTileCache[ cnt ].pImagery == NULL )
		{
			// Insert here
			gpTileCache[ cnt ].pImagery = LoadTileSurface( cFilename );

			if ( gpTileCache[ cnt ].pImagery == NULL )
			{
				return( -1 );
			}

			strcpy( gpTileCache[ cnt ].zName, cFilename );
			gpTileCache[ cnt ].sHits = 1;

			// Get root name
			GetRootName( gpTileCache[ cnt ].zRootName, cFilename );

			gpTileCache[ cnt ].sStructRefID = FindCacheStructDataIndex( gpTileCache[ cnt ].zRootName );

			// ATE: Add z-strip info
			if ( gpTileCache[ cnt ].sStructRefID != -1 )
			{
				AddZStripInfoToVObject( gpTileCache[ cnt ].pImagery->vo, gpTileCacheStructInfo[	gpTileCache[ cnt ].sStructRefID ].pStructureFileRef, TRUE, 0 );
			}

			if ( gpTileCache[ cnt ].pImagery->pAuxData != NULL )
			{
				gpTileCache[ cnt ].ubNumFrames = gpTileCache[ cnt ].pImagery->	pAuxData->ubNumberOfFrames;
			}
			else
			{
				gpTileCache[ cnt ].ubNumFrames = 1;
			}

			// Has our cache size increased?
			if ( cnt >= guiCurTileCacheSize )
			{
				guiCurTileCacheSize = cnt + 1;;
			}

			return( cnt );
		}
	}

	// Can't find one!
	return( -1 );
}


BOOLEAN RemoveCachedTile( INT32 iCachedTile )
{
	UINT32			cnt;

	// Find tile
	for ( cnt = 0; cnt < guiCurTileCacheSize; cnt++ )
	{
		if ( gpTileCache[ cnt ].pImagery != NULL )
		{
			if ( cnt == (UINT32)iCachedTile )
			{
				// Found surface, decrement hits
				gpTileCache[ cnt ].sHits--;

				// Are we at zero?
				if ( gpTileCache[ cnt ].sHits == 0 )
				{
						DeleteTileSurface( gpTileCache[ cnt ].pImagery );
						gpTileCache[ cnt ].pImagery = NULL;
						gpTileCache[ cnt ].sStructRefID = -1;
						return( TRUE );;
				}
			}
		}
	}

	return( FALSE );
}


HVOBJECT GetCachedTileVideoObject( INT32 iIndex )
{
	if ( iIndex == -1 )
	{
		return( NULL );
	}

	if ( gpTileCache[ iIndex ].pImagery == NULL )
	{
		return( NULL );
	}

	return( gpTileCache[ iIndex ].pImagery->vo );
}


STRUCTURE_FILE_REF *GetCachedTileStructureRef( INT32 iIndex )
{
	if ( iIndex == -1 )
	{
		return( NULL );
	}

	if ( gpTileCache[ iIndex ].sStructRefID == -1 )
	{
		return( NULL );
	}

	return( gpTileCacheStructInfo[ gpTileCache[ iIndex ].sStructRefID ].pStructureFileRef );
}


STRUCTURE_FILE_REF *GetCachedTileStructureRefFromFilename( const STR8 cFilename )
{
	INT16 sStructDataIndex;

	// Given filename, look for index
	sStructDataIndex = FindCacheStructDataIndex( cFilename );

	if ( sStructDataIndex == -1 )
	{
		return( NULL );
	}

	return( gpTileCacheStructInfo[ sStructDataIndex ].pStructureFileRef );
}


void CheckForAndAddTileCacheStructInfo( LEVELNODE *pNode, INT32 sGridNo, INT8 bLevel, UINT16 usIndex, UINT16 usSubIndex )
{
	STRUCTURE_FILE_REF *pStructureFileRef;

	pStructureFileRef = GetCachedTileStructureRef( usIndex );

	if ( pStructureFileRef != NULL)
	{
		if ( !AddStructureToWorld( sGridNo, bLevel, &( pStructureFileRef->pDBStructureRef[ usSubIndex ] ), pNode ) )
	{
		if ( giDefaultStructIndex != -1 )
		{
		pStructureFileRef = gpTileCacheStructInfo[ giDefaultStructIndex ].pStructureFileRef;

		if ( pStructureFileRef != NULL)
		{
			AddStructureToWorld( sGridNo, bLevel, &( pStructureFileRef->pDBStructureRef[ usSubIndex ] ), pNode );
		}
		}
	}
	}
}

void CheckForAndDeleteTileCacheStructInfo( LEVELNODE *pNode, UINT16 usIndex )
{
	STRUCTURE_FILE_REF *pStructureFileRef;

	if ( usIndex >= TILE_CACHE_START_INDEX )
	{
		pStructureFileRef = GetCachedTileStructureRef( ( usIndex - TILE_CACHE_START_INDEX ) );

		if ( pStructureFileRef != NULL)
		{
			DeleteStructureFromWorld( pNode->pStructureData );
		}
	}
}

void GetRootName( STR8 pDestStr, const STR8 pSrcStr )
{
	// Remove path and extension
	CHAR8		cTempFilename[ 120 ];
	STR			cEndOfName;

	// Remove path
	strcpy( cTempFilename, pSrcStr );
	cEndOfName = strrchr( cTempFilename, '\\' );
	if (cEndOfName != NULL)
	{
		cEndOfName++;
		strcpy( pDestStr, cEndOfName );
	}
	else
	{
		strcpy( pDestStr, cTempFilename );
	}

	// Now remove extension...
	cEndOfName = strchr( pDestStr, '.' );
	if (cEndOfName != NULL)
	{
		*cEndOfName = '\0';
	}

}


