#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include "cFilePackage.h"

cFilePackage::cFilePackage()
{	
	m_table.clear();
	m_fileHandle.clear();	
	//m_currentIter = m_table.end();
	memset( m_dirStr, 0, sizeof(m_dirStr) );
}

cFilePackage::~cFilePackage()
{
	Destroy();
}

void cFilePackage::Destroy()
{
	/*
	for ( set<FileDbIndex*, FileDbIndex>::iterator iter = m_table.begin(); iter != m_table.end(); iter++ ) {
		if ( (*iter)->fileNameStr ) {
			delete [] (*iter)->fileNameStr;
			(*iter)->fileNameStr = NULL;
		}
	}
	*/

	for ( vector<HANDLE>::iterator iter = m_fileHandle.begin(); iter != m_fileHandle.end(); iter++ ) {
		CloseHandle( *iter );
	}

	m_table.clear();
	m_fileHandle.clear();	
	//m_currentIter = m_table.end();
	memset( m_dirStr, 0, sizeof(m_dirStr) );
}

cFileObj* cFilePackage::GetFileObj(const char *filename)
{
	cFileObj *pFileObj = NULL;
	if ( filename )
	{
		FileDbIndex* pFileIndex = Find(filename);
		if ( pFileIndex )
		{
			switch ( pFileIndex->m_fileType )
			{
			case FILE_TYPE_GENERAL:
				pFileObj = new cFileObj();
				break;
			case FILE_TYPE_IMAGE:
				pFileObj = new cImgFile();
				break;
			default:
				return NULL;
			}

			bool ret = true;
			if ( pFileIndex->m_isFromDB )
			{
				if ( !pFileObj->LoadFromData(pFileIndex->m_hFile) )
					ret = false;
			}
			else
			{
				if ( !pFileObj->LoadFromFile(m_dirStr, filename) )
					ret = false;
			}

			if ( !ret )
			{
				delete pFileObj;
				pFileObj = NULL;
			}
		}
	}
	return pFileObj;
}

IRuStream *cFilePackage::GetIRuStream(const char *keyStr)
{
	cFileObj *pFileObj;

	if ( keyStr == NULL )
		return NULL;

	// 試著開啟真實路徑下檔案
	if ( IsImageFile( keyStr ) )
	{
		pFileObj = new cImgFile();
		if ( pFileObj->LoadFromFile(m_dirStr, keyStr) )
			return pFileObj;
        delete pFileObj;
	}
	else
	{
		pFileObj = new cFileObj();
		if ( pFileObj->LoadFromFile(m_dirStr, keyStr) )
			return pFileObj;
		delete pFileObj;
	}

	if ( (pFileObj = GetFileObj(keyStr)) != NULL )
	{
		if ( !pFileObj->ConvertFormat( COMPRESS_FMT_NORMAL ) )
		{
			delete pFileObj;
			pFileObj = NULL;
		}
	}

	return NULL;
}

bool cFilePackage::AddFile(const TCHAR *fileNameStr, void *pSpecialData, CompressFormat format)
{
	if (fileNameStr == NULL) 
		return false;

	HANDLE hFile;
	if ( (hFile = CreateFile( GetFullNameStr(fileNameStr) , GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ) ) == INVALID_HANDLE_VALUE ) {
		return false;
	}

	FileDbIndex fileInfo;
	fileInfo.m_isFromDB		= false;
	fileInfo.m_hFile		= NULL;
	GetFileTime( hFile, NULL, NULL, &fileInfo.m_fileTime );
	CloseHandle( hFile );

	if ( IsImageFile( fileNameStr ) )
		fileInfo.m_fileType = FILE_TYPE_IMAGE;
	else
		fileInfo.m_fileType = FILE_TYPE_GENERAL;

	return AddToTable(fileNameStr, fileInfo);
}

bool cFilePackage::LoadFromFile( const TCHAR *fileNameStr )
{
	Destroy();

	HANDLE hFile = CreateFile( fileNameStr, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
	if ( hFile == INVALID_HANDLE_VALUE ) return false;

	DWORD magic, readBytesOut;
	ReadFile( hFile, &magic, sizeof(DWORD), &readBytesOut, NULL );
	if ( magic != FILEPACKAGE_MAGIC ) {
		CloseHandle( hFile );
		return false;
	}

	int pos = sizeof(DWORD);					// 檢查碼大小
	int ret;
	FileDbIndex info;
	cFileObj file;
	while ( (ret = file.LoadFromData( hFile, false )) != 0 )
	{
		info.m_fileType		= file.GetType();
		info.m_fileTime		= file.GetFileTime();
		info.m_hFile		= hFile;
		info.m_offset		= pos;
		info.m_isFromDB		= true;

		AddToTable(file.GetFileName(), info);
		pos	+= ret;
		SetFilePointer( hFile, pos, NULL, FILE_BEGIN );		// 偏移到下一筆資料開頭
	}

	m_fileHandle.push_back( hFile );
	//CloseHandle( hFile );

	return true;
}

int cFilePackage::SaveToFile( const TCHAR *fileNameStr )
{
	if ( m_table.empty() ) return -1;

	HANDLE hFile = CreateFile( fileNameStr, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL );
	if ( hFile == INVALID_HANDLE_VALUE ) return -2;
	
	DWORD writeBytesOut;
	DWORD magic = FILEPACKAGE_MAGIC;
	WriteFile( hFile, &magic, sizeof(DWORD), &writeBytesOut, NULL );		// 寫入檔案檢查碼
	
	int count = 0;
	/*
	for ( set<FileDbIndex*, FileDbIndex>::iterator iter = m_table.begin(); iter != m_table.end(); iter++ ) {
		cFileObj *pFileObj = NULL;
		if ( GetFileObj( (*iter)->filename, &pFileObj ) ) {
			pFileObj->SaveData( hFile );
			count++;
			delete pFileObj;
			pFileObj = NULL;
		}
	}
	*/

	const int zero = 0;
	WriteFile( hFile, &zero, sizeof(int), &writeBytesOut, NULL );			// 區塊結束
	WriteFile( hFile, &count, sizeof(int), &writeBytesOut, NULL );
	CloseHandle( hFile );

	return count;
}

/*
FileDbIndex *cFilePackage::GetFirstItem()
{
	if ( m_table.empty() ) return NULL;
	m_currentIter = m_table.begin();
	return *m_currentIter;
}

FileDbIndex *cFilePackage::GetNextItem()
{	
	if ( m_currentIter != m_table.end() ) m_currentIter++;
	if ( m_currentIter != m_table.end() ) {
		return *m_currentIter;
	}
	return NULL;
}
*/

void cFilePackage::SetDirectory( const TCHAR *dirStr )
{
	if ( dirStr )
	{
		_tcscpy( m_dirStr, dirStr );
		int len = (int)_tcslen( m_dirStr );
		if ( len > 0 && m_dirStr[len] != _T('\\') )
			_tcscat( m_dirStr, _T("\\") );
	}
}

bool cFilePackage::AddToTable(string filename, FileDbIndex &fileInfo)
{
	_strlwr( (char*)filename.c_str() );
	m_table.insert( make_pair(filename, fileInfo) );
	return true;	
}

FileDbIndex *cFilePackage::Find(string filename)
{
	_strlwr( (char*)filename.c_str() );
	map<string, FileDbIndex>::iterator iter = m_table.find(filename);
	if ( iter != m_table.end() )
		return &(iter->second);
	return NULL;
}

TCHAR *cFilePackage::GetFullNameStr( const TCHAR *fileNameStr )
{
	static TCHAR fullNameStr[MAX_PATH];
	if ( fileNameStr ) {
		_tcscpy( fullNameStr, m_dirStr );
		_tcscat( fullNameStr, fileNameStr );
		return fullNameStr;
	}
	return NULL;
}