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

namespace Mix{ namespace IO{

ArchiveController* ArchiveController::CreateInstance( const wchar_t* fileName, Mix::IO::Archive* pArchive, UInt64 pos, UInt64 size )
{
	return MIX_LIB_NEW_T( Mix::Memory::SECTION_GENERAL, ArchiveController, fileName, pArchive, pos, size );
}

ArchiveController::ArchiveController( const wchar_t* fileName, Mix::IO::Archive* pArchive, UInt64 head, UInt64 size ) :
Controller( fileName ),
m_pArchive( pArchive ),
m_Head( head )
{
	MIX_ADD_REF( m_pArchive );

	m_Size = size;
}

ArchiveController::~ArchiveController( void )
{
	MIX_RELEASE( m_pArchive );
}

Mix::IO::Archive* ArchiveController::GetArchivePointer( void ) const
{
	return m_pArchive;
}

Boolean ArchiveController::Open( Controller::MODE mode )
{
	if( ( m_pArchive == NULL ) ||
		( mode == Controller::WRITE ) )
	{
		return False;
	}

	return m_pArchive->Open();
}

void ArchiveController::Close( void )
{
	if( m_pArchive != NULL )
	{
		m_pArchive->Close();
	}
}

Boolean ArchiveController::IsOpen( void ) const
{
	return False;
}

UInt32 ArchiveController::Read( void* pReadBuffer, UInt32 readSize )
{
	UInt32 moveSize = m_pArchive->Read( pReadBuffer, ( m_Head + m_Pos ), readSize );

	m_Pos += moveSize;

	return moveSize;
}

UInt32 ArchiveController::Write( const void* pWriteBuffer, UInt32 writeSize )
{
	return 0;
}

UInt64 ArchiveController::Seek( Mix::IO::SEEK_METHOD seekMethod, Int64 offset )
{
	UInt64 uoffset = offset;

	switch( seekMethod )
	{
	case Mix::IO::SEEK_METHOD_BEGIN:
		if( m_Size < uoffset )
		{
			m_Pos = m_Size;
		}
		else
		{
			m_Pos = uoffset;
		}
		break;

	case Mix::IO::SEEK_METHOD_CURRENT:
		if( offset > 0 )
		{
			if( ( m_Pos + uoffset ) > m_Size )
			{
				m_Pos = m_Size;
			}
			else
			{
				m_Pos += uoffset;
			}
		}
		else if( offset < 0 )
		{
			if( m_Pos < static_cast<UInt64>( -offset ) )
			{
				m_Pos = 0;
			}
			else
			{
				m_Pos += offset;
			}
		}
		break;

	case Mix::IO::SEEK_METHOD_END:
		if( offset < 0 )
		{
			if( m_Pos < static_cast<UInt64>( -offset ) )
			{
				m_Pos = 0;
			}
			else
			{
				m_Pos += offset;
			}
		}
		else if( offset == 0 )
		{
			m_Pos = m_Size;
		}
		break;
	}

	return m_Pos;
}

Boolean ArchiveController::IsArchive( void ) const
{
	return True;
}

}}
