#include "Mix/Tool/Win32/Core/File/TemporaryStream.h"

namespace Mix{ namespace Tool{ namespace Win32{ namespace File{

const unsigned int TemporaryStream::DEF_SIZE = 10 * 1024 * 1024;
const unsigned int TemporaryStream::RESIZE_STEP = 5 * 1024 * 1024;

TemporaryStream::TemporaryStream( void ) :
m_FilePath( L"" ),
m_pBuffer( NULL ),
m_Size( 0 ),
m_Pos( 0 )
{
}

TemporaryStream::~TemporaryStream( void )
{
	if( m_pBuffer != NULL )
	{
		::HeapFree( ::GetProcessHeap(), 0, m_pBuffer );
		m_pBuffer = NULL;
	}
}

bool TemporaryStream::Open( const wchar_t* pFilePath )
{
	if( ( pFilePath == NULL ) ||
		( ::wcslen( pFilePath ) == 0 ) )
	{
		return false;
	}

	Close();

	m_pBuffer = reinterpret_cast<unsigned char*>( ::HeapAlloc( ::GetProcessHeap(), HEAP_ZERO_MEMORY, TemporaryStream::DEF_SIZE ) );
	if( m_pBuffer != NULL )
	{
		m_Size = TemporaryStream::DEF_SIZE;
	}
	else
	{
		return false;
	}

	m_FilePath = pFilePath;

	return true;
}

bool TemporaryStream::Close( void )
{
	bool ret = true;

	if( ( m_FilePath.size() > 0 ) &&
		( m_pBuffer != NULL ) &&
		( m_Size > 0 ) &&
		( m_Pos > 0 ) )
	{
		HANDLE hFile = ::CreateFile( m_FilePath.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
		if( hFile != INVALID_HANDLE_VALUE )
		{
			DWORD writeSize = 0;

			if( ::WriteFile( hFile, m_pBuffer, m_Pos, &writeSize, NULL ) == FALSE )
			{
				ret = false;
			}

			::CloseHandle( hFile );
		}
	}

	if( m_pBuffer != NULL )
	{
		::HeapFree( ::GetProcessHeap(), 0, m_pBuffer );
		m_pBuffer = NULL;
	}

	m_FilePath = L"";
	m_Size = 0;
	m_Pos = 0;

	return ret;
}

bool TemporaryStream::Write( const void* pData, unsigned int dataSize )
{
	if( ( pData == NULL ) ||
		( dataSize == 0 ) )
	{
		return false;
	}

	void* pDst = Write( dataSize );
	if( pDst == NULL )
	{
		return false;
	}

	::CopyMemory( pDst, pData, dataSize );

	return true;
}

void* TemporaryStream::Write( unsigned int dataSize )
{
	if( m_pBuffer == NULL )
	{
		return NULL;
	}

	unsigned int prePos = m_Pos;

	if( ( m_Size - m_Pos ) < dataSize )
	{
		unsigned int nextSize = m_Size + TemporaryStream::RESIZE_STEP;
		void* pTemp = ::HeapReAlloc( ::GetProcessHeap(), 0, m_pBuffer, nextSize );

		if( pTemp != NULL )
		{
			m_pBuffer = reinterpret_cast<unsigned char*>( pTemp );
		}
		else
		{
			return NULL;
		}
	}

	m_Pos += dataSize;

	return &( m_pBuffer[prePos] );
}

unsigned int TemporaryStream::GetSize( void ) const
{
	return m_Pos;
}

Mix::Tool::Win32::Object::TYPE TemporaryStream::GetType( void ) const
{
	return Mix::Tool::Win32::Object::FILE__TEMPORARY_STREAM;
}

}}}}
