#include "Mix/Private/IO/FileController.h"

namespace Mix{ namespace IO{

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

FileController::FileController( const wchar_t* fileName ) :
Controller( fileName ),
m_hFile( INVALID_HANDLE_VALUE )
{
}

FileController::~FileController( void )
{
}

Boolean FileController::Open( MODE mode )
{
	if( m_hFile != INVALID_HANDLE_VALUE )
	{
		return False;
	}

	UInt32 desiredAccess;
	UInt32 creationDisposition;
	LARGE_INTEGER fileSize;

	switch( mode )
	{
	case Controller::READ:
		desiredAccess = GENERIC_READ;
		creationDisposition = OPEN_EXISTING;
		break;
	case Controller::WRITE:
		desiredAccess = GENERIC_WRITE;
		creationDisposition = CREATE_ALWAYS;
		break;
	case Controller::WRITE_ALWAYS:
		desiredAccess = GENERIC_WRITE;
		creationDisposition = OPEN_ALWAYS;
		break;
	default:
		return False;
	}

	m_hFile = ::CreateFile( m_FilePath.GetConstPtr(), desiredAccess, 0, NULL, creationDisposition, FILE_ATTRIBUTE_NORMAL, NULL );
	if( m_hFile == INVALID_HANDLE_VALUE )
	{
		return False;
	}

	if( mode == Controller::WRITE_ALWAYS )
	{
		if( ::SetFilePointer( m_hFile, 0, NULL, FILE_END ) == INVALID_SET_FILE_POINTER )
		{
			Close();
			return False;
		}
	}

	if( ::GetFileSizeEx( m_hFile, &fileSize ) == False )
	{
		Close();
		return False;
	}

	m_Size = fileSize.QuadPart;
	m_Pos = 0;

	return True;
}

void FileController::Close( void )
{
	if( m_hFile != INVALID_HANDLE_VALUE )
	{
		::CloseHandle( m_hFile );
		m_hFile = INVALID_HANDLE_VALUE;
	}
}

Boolean FileController::IsOpen( void ) const
{
	return ( m_hFile != INVALID_HANDLE_VALUE );
}

UInt32 FileController::Read( void* pReadBuffer, UInt32 readSize )
{
	DWORD size = 0;

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

	m_Pos += size;

	return size;
}

UInt32 FileController::Write( const void* pWriteBuffer, UInt32 writeSize )
{
	DWORD size = 0;

	if( ::WriteFile( m_hFile, pWriteBuffer, writeSize, &size, NULL ) == False )
	{
		return 0;
	}

	m_Pos += size;
	m_Size += size;

	return size;
}

UInt64 FileController::Seek( Mix::IO::SEEK_METHOD seekMethod, Int64 offset )
{
	LARGE_INTEGER dist;
	LARGE_INTEGER pos;

	dist.QuadPart = offset;
	pos.QuadPart = 0;

	if( ::SetFilePointerEx( m_hFile, dist, &pos, seekMethod ) == True )
	{
		m_Pos = pos.QuadPart;
	}

	return m_Pos;
}

Boolean FileController::IsArchive( void ) const
{
	return False;
}

}}
