#include "stdafx.h"
#include "FilePackSystem.h"

#include "FileFinder.h"
#include "File.h"
#include "MemFile.h"
#include "FilePack.h"


int ConvertToUnicode( const char* str, wchar_t* uniStr, unsigned int buffersize )
{
	size_t len = ::strlen(str);
	if( len == 0 )
		return 0;

	int iLen = ::MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, str, len, NULL, 0 );
	if (iLen > 0)
	{
		assert( iLen+1 < (int)buffersize );
		iLen = ::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, (LPWSTR)uniStr, iLen+1 );
		assert(iLen != 0);
	}
	else
	{
		iLen --; // return -1
	}
	return iLen;
}

int ConvertToAscii( const wchar_t* uniStr, char* str, unsigned int buffersize )
{
	size_t wideLen = ::wcslen(uniStr);
	if (wideLen == 0)
		return 0;

	// iLen does not include terminating character
	int iLen = ::WideCharToMultiByte(CP_ACP, 0, uniStr, (int)wideLen, (LPSTR)str, 0, NULL, NULL);
	if (iLen > 0)
	{
		assert( iLen+1 < (int)buffersize );
		iLen = ::WideCharToMultiByte(CP_ACP, 0, uniStr , (int)-1, (LPSTR)str, iLen+1, NULL, NULL);
		assert(iLen != 0);
	}
	else
	{
		iLen --;
	}
	return iLen;
}


#define PACK_PASSWORD	_T("dkdlfltmehdwjq10aks")
#define MAX_PACKS		128

enum eFolder
{
	FOLDER_BASE = 0,
	FOLDER_LAUNCHER,
	FOLDER_SOUND,
	FOLDER_DATA,
	FOLDER_MAP,
	FOLDER_SCRIPT,
	FOLDER_COUNT
};

const charT* gFolderNames[FOLDER_COUNT] =
{
	_T(".\\"), _T("Launcher\\"), _T("Sound"), _T("Data\\"), _T("Map\\"), _T("Script\\")
};

cFilePackSystem::cFilePackSystem()
: mFileIndexMap( 16384 )
{
	mFilePackArray.Reserve( MAX_PACKS );
}

cFilePackSystem::~cFilePackSystem()
{
	for( unsigned int i = 0, iend = mFilePackArray.GetSize(); i < iend; ++i )
	{
		delete (cFilePack*)mFilePackArray[i];
	}

	mFilePackArray.Clear();
}

bool cFilePackSystem::Init()
{
	/// 파일 팩을 검색
	cFileFinder fileFinder;
	cStringT findPath;
	cStringT packName;
	cStringT pathName;

	for( unsigned int i = FOLDER_DATA; i < FOLDER_COUNT; ++i )
	{
		findPath.Format( _T("%s*.pack"), gFolderNames[i] );

		if( fileFinder.FindFirst( findPath.Cstr() ) == false )
			continue;

		do
		{
			cFilePack* pack = new cFilePack;

			/// 파일 팩을 엶
			packName.Format( _T("%s%s"), gFolderNames[i], fileFinder.GetFileName() );

			if( pack->Open( packName, cFilePack::OPEN_READONLY ) == false )
			{
				delete pack;
				continue;
			}

			/// 패스워드를 설정
			pack->SetPassword( PACK_PASSWORD );

			/// 파일 팩을 추가
			unsigned int packIndex = mFilePackArray.GetSize();
			unsigned int fileIndex;

			mFilePackArray.PushBack( pack );

			/// 파일 인덱스를 맵에 추가
			cFileInPackInfo fipi;

			for( unsigned int j = 0, jend = pack->GetNumFiles(); j < jend; ++j )
			{
				pack->GetFileInfo( &fipi, j );

				if( fipi.IsDirectory() )
					continue;

				fileIndex = j;
				fileIndex <<= 8;
				fileIndex += packIndex;

				///
				//				char cstr[MAX_PATH];
				//				ConvertToAscii( fipi.GetPathName().Cstr(), cstr, MAX_PATH );
				cString tempName = fipi.GetPathName();//cstr;
				tempName.ToLower();

				mFileIndexMap.Insert( tempName, fileIndex );
			}
		}
		while( fileFinder.FindNext() );
	}
	return true;
}

cFileToRead* cFilePackSystem::OpenFileToRead( const cString& pathName )
{
#if defined(_DEBUG) || defined(_DEVSYS) || defined(_DEVMODE)
	/// 로컬 시스템에서 로딩
	cFileToRead* file = cFileSystem::OpenFileToRead( pathName );
	if( file )
		return file;

	/// 팩킹 시스템에서 로딩
	cString tempName = pathName;
	tempName.Replace( '/', '\\' );
	tempName.TrimLeft( ".\\" );
	tempName.ToLower();

	cFileIndexMap::cIterator i = mFileIndexMap.Find( tempName );

	if( i == mFileIndexMap.End() )
		return 0;

	cMemFileInPackToRead* fileInPack = new cMemFileInPackToRead;
	unsigned int packIndex = i->mSecond & 0xFF;
	int fileIndex = int(i->mSecond >> 8);

	if( fileInPack->Open( (cFilePack*)mFilePackArray[packIndex], fileIndex ) == false )
	{
		delete fileInPack;
		return 0;
	}
	return fileInPack;
#else
	/// 팩킹 시스템에서 로딩
	cString tempName = pathName;
	tempName.Replace( '/', '\\' );
	tempName.TrimLeft( ".\\" );
	tempName.ToLower();

	cFileIndexMap::cIterator i = mFileIndexMap.Find( tempName );

	if( i != mFileIndexMap.End() )
	{
		cMemFileInPackToRead* fileInPack = new cMemFileInPackToRead;
		unsigned int packIndex = i->mSecond & 0xFF;
		int fileIndex = int(i->mSecond >> 8);

		if( fileInPack->Open( (cFilePack*)mFilePackArray[packIndex], fileIndex ) == true )
		{
			return fileInPack;
		}
		delete fileInPack;
	}

	/// 로컬 시스템에서 로딩
	return cFileSystem::OpenFileToRead( pathName );
#endif
}

cMemFileToRead* cFilePackSystem::OpenMemFileToRead( const cString& pathName )
{
//#if defined(_DEBUG) || defined(_DEVSYS) || defined(_DEVMODE)
	/// 로컬 시스템에서 로딩
	cMemFileToRead* file = cFileSystem::OpenMemFileToRead( pathName );
	if( file )
		return file;

	/// 팩킹 시스템에서 로딩
	cString tempName = pathName;
	tempName.Replace( '/', '\\' );
	tempName.TrimLeft( ".\\" );
	tempName.ToLower();

	cFileIndexMap::cIterator i = mFileIndexMap.Find( tempName );

	if( i == mFileIndexMap.End() )
		return 0;

	cMemFileInPackToRead* fileInPack = new cMemFileInPackToRead;
	unsigned int packIndex = i->mSecond & 0xFF;
	int fileIndex = int(i->mSecond >> 8);

	if( fileInPack->Open( (cFilePack*)mFilePackArray[packIndex], fileIndex ) == false )
	{
		delete fileInPack;
		return 0;
	}
	return fileInPack;
/*
#else
	/// 팩킹 시스템에서 로딩
	cString tempName = pathName;
	tempName.Replace( '/', '\\' );
	tempName.TrimLeft( ".\\" );
	tempName.ToLower();

	cFileIndexMap::cIterator i = mFileIndexMap.Find( tempName );

	if( i != mFileIndexMap.End() )
	{
		cMemFileInPackToRead* fileInPack = new cMemFileInPackToRead;
		unsigned int packIndex = i->mSecond & 0xFF;
		int fileIndex = int(i->mSecond >> 8);

		if( fileInPack->Open( (cFilePack*)mFilePackArray[packIndex], fileIndex ) == true )
		{
			return fileInPack;
		}
		delete fileInPack;
	}

	/// 로컬 시스템에서 로딩
	return cFileSystem::OpenMemFileToRead( pathName );
#endif
*/
}
