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

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

#define PACK_PASSWORD	L"dkdlfltmehdwjq10aks"
#define MAX_PACKS		128

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

const charT* gFolderNames[FOLDER_COUNT] =
{
	L".\\", L"Launcher\\", L"GuildMark\\", L"Sound", L"Data\\", L"Map\\", L"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( L"%s*.pack", gFolderNames[i] );

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

		do
		{
			cFilePack* pack = new cFilePack;

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

			if( pack->Open( packName, cFilePack::OPEN_READONLY ) == false )
			{
				delete pack;
				MessageBox(NULL, _T("Failed Open pack file.. reinstall client."), _T("Error"), MB_OK | MB_ICONEXCLAMATION );
				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 = cstr;
				tempName.ToLower();

				mFileIndexMap.Insert( tempName, fileIndex );
			}
		}
		while( fileFinder.FindNext() );
	}
	fileFinder.Close();
	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 )
{
// 사내 테스트를 위해 로컬 시스템에서 먼저 로딩 후 팩킹 시스템에서 찾음. [1/12/2009 Jo_2]
//#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
}
