
#include "PajaTypes.h"
#include "FileIO.h"
#include <stdio.h>
#include <string.h>
#include <vector>
#include "SaveC.h"


using namespace PajaTypes;
using namespace FileIO;


SaveC::SaveC() :
	m_pStream( 0 ),
	m_ui32Error( IO_OK ),
	m_i32StartPos( 0 ),
	m_i32CurrPos( 0 ),
	m_i32Indent( 0 )
{
	// empty
}

SaveC::~SaveC()
{
	close();
}

uint32
SaveC::open( const char* szName, const int8* pSignature, int32 i32SignatureSize )
{
	if( m_pStream ) {
		m_ui32Error = IO_ERROR_OPEN;
		return m_ui32Error;
	}

	// open stream
	m_pStream = fopen( szName, "wb" );
	if( !m_pStream ) {
		m_ui32Error = IO_ERROR_OPEN;
		return m_ui32Error;
	}

	m_i32Indent = 0;

	// write file header
	if( fwrite( pSignature, i32SignatureSize, 1, m_pStream ) != 1 ) {
		m_ui32Error = IO_ERROR_WRITE;
		return m_ui32Error;
	}

	return IO_OK;
}

uint32
SaveC::close()
{
	if( m_pStream )
		fclose( m_pStream );
	m_pStream = 0;

	return IO_OK;
}

uint32
SaveC::begin_chunk( uint32 ui32ID, uint32 ui32Version )
{
	if( m_ui32Error )
		return m_ui32Error;

	if( !m_pStream ) {
		m_ui32Error = IO_ERROR_OPEN;
		return m_ui32Error;
	}

	uint32	ui32ChunkHdr[3];

	// chunk:
	// ID		4 bytes
	// Version	4 bytes
	// Size		4 bytes		(Note: len includes these 12 bytes too)

	ui32ChunkHdr[0] = ui32ID;
	ui32ChunkHdr[1] = ui32Version;
	ui32ChunkHdr[2] = 0;		// len will be patched in later

	m_i32StartPos = ftell( m_pStream );

	if( fwrite( ui32ChunkHdr, sizeof( ui32ChunkHdr ), 1, m_pStream ) != 1 ) {
		m_ui32Error = IO_ERROR_WRITE;
		return m_ui32Error;
	}

	m_rStartPosList.push_back( m_i32StartPos );
	m_i32Indent++;

	return IO_OK;
}

uint32
SaveC::end_chunk()
{
	if( m_ui32Error )
		return m_ui32Error;

	if( !m_pStream ) {
		m_ui32Error = IO_ERROR_OPEN;
		return m_ui32Error;
	}

	if( !m_i32Indent ) {
		m_ui32Error = IO_ERROR_WRITE;
		return m_ui32Error;
	}

	uint32	ui32ChunkLen;

	m_i32CurrPos = ftell( m_pStream );

	m_i32StartPos = m_rStartPosList[m_i32Indent - 1];
	m_rStartPosList.erase( m_rStartPosList.begin() + (m_i32Indent - 1) );
	m_i32Indent--;

	// write chunklen
	ui32ChunkLen = (uint32)(m_i32CurrPos - m_i32StartPos);
	fseek( m_pStream, m_i32StartPos + 8, SEEK_SET );

	if( fwrite( &ui32ChunkLen, sizeof( ui32ChunkLen ), 1, m_pStream ) != 1 ) {
		m_ui32Error = IO_ERROR_WRITE;
		return m_ui32Error;
	}

	fseek( m_pStream, m_i32CurrPos, SEEK_SET );

	return IO_OK;
}

uint32
SaveC::write( const void* pBuffer, uint32 ui32Len )
{
	if( m_ui32Error )
		return m_ui32Error;

	if( !m_pStream ) {
		m_ui32Error = IO_ERROR_OPEN;
		return m_ui32Error;
	}

	if( fwrite( pBuffer, 1, ui32Len, m_pStream ) != ui32Len ) {
		m_ui32Error = IO_ERROR_WRITE;
		return m_ui32Error;
	}

	return IO_OK;
}

uint32
SaveC::write_str( const char* szStr )
{
	uint16	ui16StrSize = strlen( szStr );

	// write the length of the string
	if( fwrite( &ui16StrSize, sizeof( ui16StrSize ), 1, m_pStream ) != 1) {
		m_ui32Error = IO_ERROR_WRITE;
		return m_ui32Error;
	}

	if( ui16StrSize ) {
		// write the string
		if( fwrite( szStr, 1, ui16StrSize, m_pStream ) != ui16StrSize ) {
			m_ui32Error = IO_ERROR_WRITE;
			return m_ui32Error;
		}
	}

	return IO_OK;
}

uint32
SaveC::get_error()
{
	return m_ui32Error;
}
