//
// Asura_FileAccess.h
//
// Created by Kevin Lea - 04/09/2001 15:06:11
// 
// Copyright (C) 2001 Rebellion, All Rights Reserved.
//

#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef __ASURA_FILEACCESS_H__
#define __ASURA_FILEACCESS_H__

// Engine independent.
#include "Core/Asura_Handle.h"

// You can override this limit in Asura_EngineConfiguration.h.
#ifndef ASURA_MAX_NO_OF_OPEN_FILES
    #define ASURA_MAX_NO_OF_OPEN_FILES (2)
#endif

enum ASURA_ASYNCLOADING_STATUS
{
	ASURA_ASYNCLOADING_STATUS_ERROR,
	ASURA_ASYNCLOADING_STATUS_LOADING,
	ASURA_ASYNCLOADING_STATUS_FINISHEDLOADING,
};

enum ASURA_COMPRESSION_TYPE
{
	ASURA_COMPRESSION_NOTCOMPRESSED,
	ASURA_COMPRESSION_HUFFMAN,
	ASURA_COMPRESSION_ZLIB,
	ASURA_COMPRESSION_LZX,
};

class Asura_FileCache;
class Asura_Huffman_Decoder;
#ifdef ASURA_USE_ZLIB
class Asura_Zlib_Decoder;
#endif

class Asura_FileAccess
{
	public:
		static void Initialise(void);
		static void Shutdown(void);

        static Asura_Handle Open( const char* szFilename, bool bComputeChecksum = false, bool bFailureHandledExternally = false );
		static Asura_Handle OpenRaw( const char* szFilename, bool bFailureHandledExternally = false );
		static Asura_Handle OpenFromMemory( const void* pMem, u_int uSize, bool bFailureHandledExternally = false );
#if defined(ASURA_USE_STREAMING)
		static Asura_Handle OpenForStreaming(const char* szFilename);
		static void SetFileCacheForStreaming(Asura_FileCache* pxFileCache) { s_pxStreamingFileCache = pxFileCache; }
		static const Asura_FileCache* GetFileCacheForStreaming(void) { return(s_pxStreamingFileCache); }
#endif	// defined(ASURA_USE_STREAMING)
		static bool			SeekFile( Asura_Handle iFileHandle, u_int uFilePosition, bool bFailureHandledExternally = false );
		static bool			CanBeRead( Asura_Handle iFileHandle );
        static bool         ReadData( Asura_Handle iFileHandle, void* pvDest, int iNumBytes, bool bFailureHandledExternally = false );
        static bool         SkipData( Asura_Handle iFileHandle, int iNumBytes, bool bFailureHandledExternally = false );
        static const char*  ReadString( Asura_Handle iFileHandle, u_int* puLength = NULL, u_int* puSizeInInts = NULL );
        static const char*  GetLastReadString( u_int* puLength = NULL, u_int* puSizeInInts = NULL );
        static u_int        ReadLine( Asura_Handle iFileHandle, char* szBfr, u_int uBfrSize );
        static void         Close( Asura_Handle iFileHandle, u_char* pucChecksumOutput = NULL, bool bFailureHandledExternally = false );
        static unsigned     GetFilePosition( Asura_Handle iFileHandle );//Gets the number of bytes read from the (uncompressed) file so far

		static bool	IsFileRaw(const Asura_Handle iFileHandle)	{ return(s_abFileIsRaw[iFileHandle]); }

        //Reads the first 8 bytes of a file to make sure it is an asura file , and determines what compression
        //(if any) is being used
        static bool ProcessAsuraFileHeader( Asura_Handle iFileHandle, const bool bFailureHandledExternally = false );

		//Asynchronous loading functions , supported on PC at the moment. RAR 21/08/03

		//Opens a file , and starts loading it into a buffer. Once finished the contents
		//can be accessed using ReadData etc as normal.
		static Asura_Handle LoadAsynchronous(const char* szFilename);
		//indicates whether a file is still loading , finished loading , or had an error loading
		static enum ASURA_ASYNCLOADING_STATUS GetAsynchronousLoadingStatus(Asura_Handle iFileHandle);

		// Kevin Lea - 03/10/2001 18:04:20 - GetFilename: for use in debugging to determine the name of an open file
        // (MP - 03.02.2003) Now available in tools as well. This is helpful
        // for error messages or asserts related to chunk data.
		static const char* GetFilename( Asura_Handle iFileHandle );

        static u_int GetNumOpenCompressedFiles( void );

        static Asura_Huffman_Decoder& SetCompressed( Asura_Handle iFileHandle );
		#ifdef ASURA_USE_ZLIB
		static void SetZlibCompressed( Asura_Handle iFileHandle );
		#endif
		#ifdef ASURA_TOOLS
		static void SetLZXCompressed( Asura_Handle iFileHandle);
		#endif

		//Gets the type of compression used by a file (only valid once it has been determined by processing the header)
		static ASURA_COMPRESSION_TYPE GetCompressionType( Asura_Handle iFileHandle);

		static bool DiskExists(void) { return(Platform_DiscExists()); }
        
		static bool FileExists( const char* szFilename )			{ return (Platform_FileExists(szFilename)); }
		static u_int GetFileSize( const char* szFilename )			{ return(Platform_GetFileSize(szFilename)); }
		static u_int GetFileSize( const Asura_Handle iFileHandle )	{ return Platform_GetFileSize(iFileHandle); }

		//Gets the original uncompressed file size for compressed files , or the file size for uncompressed files
		//Will only give correct values for compressed files once the file header has been parsed , so that
		//the system knows the compression being used.
		static u_int GetDecompressedFileSize(const Asura_Handle iFileHandle);

        // Allows external code to specify where to get the configuration
        // data from.
        static void PlatformSetNetworkCfgFile( const char* szFilename );
        // Similarly for external code to set the AsuraFiles dir.
        static void PlatformSetAsuraFilesDir( const char* szPath );
		static const char* PlatformGetAsuraFilesDir();
		//Converts local filename to network filename if it is appropriate to load from there
		static void PlatformGetNetworkFilename( const char* szFilename, char* szOutputBuffer, u_int uOutputBufferSize );
		//As above , but will do a 'get' of large files , if they are being taken from the network
		static void PlatformGetNetworkFilenameOrGetLocalCopy( const char* szFilename, char* szOutputBuffer, u_int uOutputBufferSize );
        // Similarly for directories.
        static void PlatformGetNetworkDir( const char* szDir, char* szOutputBuffer, u_int uOutputBufferSize, bool bWarnIfOnlyLocal = true );
        // returns the network path.
        static const char* PlatformGetNetworkPath();
		//Returns true if PlatformGetNetworkFilename() would return a file from the network
		static bool PlatformUsingNetworkFile( const char* szFilename );
        // Returns ptr to part of path after network or executable dir.
        static const char* PlatformRemoveNetworkOrExecutableDir( const char* szPath );

#if defined( ASURA_PC_ALLOW_LOAD_FROM_SEARCHPATHS)
		static void PlatformSearchPathsClear( void);
		static void PlatformSearchPathsAddSearchPath( const char* szPath);
		static void PlatformSearchPathsGetExistingFilename( const char* szFilename, char* szOutputBuffer, u_int uOutputBufferSize );
#endif
		// Finds all filenames with the given extension in a directory.
		// Calls the callback for each file that is found.
		static void FindFiles(const char* szDirectory, const char* szExtension, void (*pfnCallback)(const char* szFilename), bool bRecursive = true )
		{
			Platform_FindFiles(szDirectory, szExtension, pfnCallback, bRecursive);
		}
		
	private:

        friend class Asura_Huffman_Decoder;
		#ifdef ASURA_USE_ZLIB
        friend class Asura_Zlib_Decoder;
		#endif
		friend class Tools_LZX_Decoder;

        static Asura_Handle_List* HandleList;
        static bool s_bNetworkDirectoryInitialised;
		static bool s_abFileIsRaw[ASURA_MAX_NO_OF_OPEN_FILES];

#if defined(ASURA_USE_STREAMING)
		static Asura_FileCache*	s_pxStreamingFileCache;		// Cache used when streaming files into memory.
#endif	// defined(ASURA_USE_STREAMING)

        static void Platform_Initialise( void );
        static void Platform_Shutdown( void );

		static bool Platform_DiscExists(void);
        
		static bool Platform_FileExists( const char* szFilename );
		static u_int Platform_GetFileSize( const char* szFilename );
		static u_int Platform_GetFileSize( const Asura_Handle iFileHandle );

		static bool Platform_Open( Asura_Handle iFileHandle, const char* szFilename );
		static bool Platform_OpenFromMemory( Asura_Handle iFileHandle, const void* pMem, u_int uSize );
		static bool Platform_SeekFile( Asura_Handle iFileHandle, u_int uPosition );
		static bool Platform_ReadData( Asura_Handle iFileHandle, void* pvDest, u_int uNumBytes );
        static bool Platform_SkipUncompressedData( Asura_Handle iFileHandle, u_int uNumBytes );
		static bool Platform_Close( Asura_Handle iFileHandle );
	
		#ifdef ASURA_TOOLS
		static void Platform_CloseFileForLZXDecompression( Asura_Handle iFileHandle);
		#endif

		static bool Platform_LoadAsynchronous(Asura_Handle iFileHandle,const char* szFilename);
		static enum ASURA_ASYNCLOADING_STATUS Platform_GetAsynchronousLoadingStatus(Asura_Handle iFileHandle);

		static void Platform_FindFiles(const char* szDirectory, const char* szExtension, void (*pfnCallback)(const char* szFilename), bool bRecursive = true );

        // To allow platform-specific code to override independent record of
        // file position.
        static void SetFilePosition( Asura_Handle iFileHandle, u_int uFilePos );

        // Allow platform-specific class access to the above. This class
        // won't necessarily exist - depending on the platform - but that's
        // okay since a friend declaration doesn't have any linkage
        // implications.
        friend class Asura_Platform_FileAccess;

		static int s_iActiveController;
};


#endif//__ASURA_FILEACCESS_H__
