#include "Mix/Private/IO/Archive.h"
#include "Mix/ScopedLock.h"

namespace Mix{ namespace IO{

Archive* Archive::CreateInstance( const wchar_t* fileName )
{
	return MIX_LIB_NEW_T( Mix::Memory::SECTION_GENERAL, Archive, fileName );
}

Archive::Archive( const wchar_t* fileName ) :
m_FileName( fileName ),
m_OpenCount( 0 ),
m_Pos( 0 ),
m_hFile( INVALID_HANDLE_VALUE )
{
}

Archive::~Archive( void )
{
}

Boolean Archive::Open( void )
{
	Mix::ScopedLock lock( m_MySync );

	if( m_OpenCount == 0 )
	{
		m_hFile = ::CreateFile( m_FileName.GetConstPtr(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
		if( m_hFile == INVALID_HANDLE_VALUE )
		{
			return False;
		}
	}

	m_OpenCount++;

	return True;
}

void Archive::Close( void )
{
	Mix::ScopedLock lock( m_MySync );

	m_OpenCount--;

	if( m_OpenCount == 0 )
	{
		::CloseHandle( m_hFile );
		m_hFile = INVALID_HANDLE_VALUE;
		m_Pos = 0;
	}
}

UInt32 Archive::Read( void* pReadBuffer, UInt64 readPos, UInt32 readSize )
{
	Mix::ScopedLock lock( m_MySync );

	if( m_hFile == INVALID_HANDLE_VALUE )
	{
		return 0;
	}

	LARGE_INTEGER distance;
	LARGE_INTEGER newPos;
	DWORD moveSize = 0;

	distance.QuadPart = readPos;//( readPos - m_Pos );
	newPos.QuadPart = 0;

	if( m_Pos != readPos )
	{
		if( ::SetFilePointerEx( m_hFile, distance, &newPos, FILE_BEGIN ) == FALSE )
		{
			return 0;
		}
		else
		{
			m_Pos = newPos.QuadPart;
		}
	}

	if( ::ReadFile( m_hFile, pReadBuffer, readSize, &moveSize, NULL ) == FALSE )
	{
		return 0;
	}

	m_Pos += moveSize;

	return moveSize;
}

}}
