//
// Tools_LZX_Decoder.cpp
//
// Created by Richard Rice - 08/01/2008
// 
// Copyright (C) 2008 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"
#ifdef ASURA_TOOLS
#include "FileAccess/Tools_LZX_Decoder.h"

#include "FileAccess/Asura_FileAccess.h"

Tools_LZX_Decoder::Tools_LZX_Decoder()
:m_pFile(INVALID_HANDLE_VALUE)
,m_uUncompressedSize(0)
{
}

Tools_LZX_Decoder::~Tools_LZX_Decoder()
{
}

void Tools_LZX_Decoder::Begin( Asura_Handle iFileHandle)
{
	const char* szSourceFilename = Asura_FileAccess::GetFilename(iFileHandle);

	//generate a temporary filename for the compressed file	
	Asura_String xFullFilename = szSourceFilename;
	Asura_String xName;

	xFullFilename.SplitFilename(0, &xName, 0);

	char acTempName[MAX_PATH];
	if(!GetTempFileName(".",xName.GetString(),0,acTempName))
	{
		Asura_Assert(0,"Error getting temporary filename");
		return;
	}

	//xbdecompress can't open the file for decompression while we have it open for reading (although I would have thought
	//it ought to be possible). So... we've got to close it first.
	Asura_FileAccess::Platform_CloseFileForLZXDecompression(iFileHandle);

	//decompress to the temporary file
	char acCommand[1024];
	Asura_PrintfToBfr(acCommand,"xbdecompress.exe /q /y \"%s\" \"%s\"",sizeof(acCommand),true,szSourceFilename,acTempName);

	PROCESS_INFORMATION xProcessInfo;
	STARTUPINFO xStartupInfo = {0};
	xStartupInfo.cb = sizeof( STARTUPINFO );

	if( !CreateProcess( NULL, acCommand, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &xStartupInfo, &xProcessInfo ) )
	{
		Asura_Assert(0, "Failed to decompress file. Check that xbdecompress.exe is present." );
		return;
	}
	else
	{
		WaitForSingleObject( xProcessInfo.hProcess, INFINITE );

   		DWORD uProcessExitCode = static_cast< u_int>( ~0);
   		GetExitCodeProcess( xProcessInfo.hProcess, &uProcessExitCode);

		CloseHandle( xProcessInfo.hThread );
		CloseHandle( xProcessInfo.hProcess );

		if(uProcessExitCode != 0)
		{
			Asura_Assert( 0, "xbdecompress.exe returned an error while compressing file." );
			return;
		}
	}

	//store the temporary filename so it can be deleted when we finish reading it
	m_xTempFileName = acTempName;


	//Open the decompressed file
	m_pFile = CreateFile(acTempName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,  FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
	if(m_pFile == INVALID_HANDLE_VALUE)
	{
		Asura_Assert( 0, "Failed to open decompressed file." );
		return;
	}
	m_uUncompressedSize = GetFileSize(m_pFile, NULL);
}


void Tools_LZX_Decoder::End()
{
	//close and delete the temporary file
	if(m_pFile != INVALID_HANDLE_VALUE)
	{
		CloseHandle(m_pFile);
		m_pFile = INVALID_HANDLE_VALUE;
	}	
	if(!m_xTempFileName.IsBlank())
	{
		DeleteFile(m_xTempFileName.GetString());
		m_xTempFileName.MakeNull();
	}
	m_uUncompressedSize = 0;


}

u_int Tools_LZX_Decoder::Decompress( void* pDest, u_int uNumBytes )
{
	if(!uNumBytes) return 0;
	if(m_pFile == INVALID_HANDLE_VALUE)
	{
		Asura_Assert(0,"LZX decompression failed to initialise - can't decompress anything");
		return 0;
	}
	//'Decompression' just involves reading from the decompressed temporary file.
	unsigned long uBytesRead;
	ReadFile(m_pFile,pDest,uNumBytes,&uBytesRead,0);

	Asura_Assert(uNumBytes == uBytesRead, "Failed to read correct amount from decompressed file");

	return uBytesRead;
}

#endif //ASURA_TOOLS
