//-------------------------------------------------------------------------
//
// File:		LoadC.cpp
// Desc:		Input stream class implementation.
// Author:		memon <memon@inside.org>
//
//-------------------------------------------------------------------------
//	Copyright (c) 2000 Moppi Productions. All Rights Reserved.
//  This file is part of Moppi Demopaja SDK. For conditions of 
//  distribution and use, see the accompanying license.txt file.
//  http://www.demopaja.org
//-------------------------------------------------------------------------

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


using namespace PajaTypes;
using namespace FileIO;
using namespace PluginClass;


LoadC::LoadC( FactoryC* pFactory ) :
	m_pFactory( pFactory ),
	m_pStream( 0 ),
	m_ui32Indent( 0 ),
	m_ui32Error( IO_OK )
{
	// empty
}

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

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

	m_pStream = fopen( szName, "rb" );
	if( !m_pStream ) {
		return IO_ERROR_OPEN;
	}

	// read file signature
	int8*	pReadSig = new int8[i32SignatureSize];
	fread( pReadSig, i32SignatureSize, 1, m_pStream );	// read null ternimated string
	if( memcmp( pSignature, pReadSig, i32SignatureSize ) != 0 ) {
		delete pReadSig;
		fclose( m_pStream );
		m_pStream = 0;
		return IO_ERROR_FORMAT;
	}
	delete pReadSig;

	uint32	ui32CurPos = ftell( m_pStream );
	fseek( m_pStream, 0, SEEK_END );
	m_ui32FileSize = ftell( m_pStream );
	fseek( m_pStream, ui32CurPos, SEEK_SET );

	return IO_OK;
}

uint32
LoadC::close()
{
	if( m_pStream )
		fclose( m_pStream );
	m_pStream = 0;
	return IO_OK;
}

uint32
LoadC::open_chunk()
{
	if( m_ui32Error )
		return m_ui32Error;

	if( !m_pStream || m_ui32Error != IO_OK )
		return IO_ERROR_OPEN;

	if( m_ui32Indent && ((uint32)ftell( m_pStream ) >= m_rChunkList[m_ui32Indent - 1].m_ui32Next) )
		return IO_END;

//	if( m_ui32Indent && m_rChunkList[m_ui32Indent - 1].m_bLastChunk )
//		return IO_END;

	if( feof( m_pStream ) )
		return IO_EOF;

	ChunkHdrS	rHdr;
	if( fread( &rHdr.m_ui32ID, sizeof( rHdr.m_ui32ID ), 1, m_pStream ) != 1 )
		return IO_ERROR_READ;
	if( fread( &rHdr.m_ui32Version, sizeof( rHdr.m_ui32Version ), 1, m_pStream ) != 1 )
		return IO_ERROR_READ;
	if( fread( &rHdr.m_ui32Size, sizeof( rHdr.m_ui32Size ), 1, m_pStream ) != 1 )
		return IO_ERROR_READ;

	rHdr.m_ui32Size -= 12;	// subscract the header size.
	rHdr.m_ui32Next = ftell( m_pStream ) + rHdr.m_ui32Size;
	rHdr.m_bLastChunk = false;

	m_rChunkList.push_back( rHdr );

	m_ui32Indent++;

	return IO_OK;
}

uint32
LoadC::get_chunk_id()
{
	if( !m_ui32Indent )
		return 0;
	return m_rChunkList[m_ui32Indent - 1].m_ui32ID;
}

uint32
LoadC::get_chunk_size()
{
	if( !m_ui32Indent )
		return 0;
	return m_rChunkList[m_ui32Indent - 1].m_ui32Size;
}

uint32
LoadC::get_chunk_version()
{
	if( !m_ui32Indent )
		return 0;
	return m_rChunkList[m_ui32Indent - 1].m_ui32Version;
}

uint32
LoadC::get_chunk_indent()
{
	return m_ui32Indent;
}

uint32
LoadC::peek_next_chunk()
{
	if( m_ui32Error )
		return m_ui32Error;
	if( !m_pStream || !m_ui32Indent )
		return IO_ERROR_OPEN;

	fseek( m_pStream, m_rChunkList[m_ui32Indent - 1].m_ui32Next, SEEK_SET );
	m_rChunkList.erase( m_rChunkList.begin() + (m_ui32Indent - 1) );
	m_ui32Indent--;
	return IO_OK;
}

uint32
LoadC::close_chunk()
{
	if( m_ui32Error )
		return m_ui32Error;
	if( !m_pStream || !m_ui32Indent )
		return IO_ERROR_OPEN;

	peek_next_chunk();

	// is this last chunk in the file?
	if( (uint32)ftell( m_pStream ) >= m_ui32FileSize ) {
		m_ui32Error = IO_END;
		return IO_OK;
	}


	// have we reached end of the chunks?
//	if( m_ui32Indent && (m_rChunkList[m_ui32Indent - 1].m_ui32Next >= ftell( m_pStream )) ) {
//		m_rChunkList[m_ui32Indent - 1].m_bLastChunk = true;
//		OutputDebugString( "*" );
//	}

	return IO_OK;
}

uint32
LoadC::read( void* pBuffer, uint32 ui32Size )
{
	if( m_ui32Error )
		return m_ui32Error;
	if( !m_pStream || !m_ui32Indent )
		return IO_ERROR_OPEN;

	uint32	ui32ReadSize = fread( pBuffer, 1, ui32Size, m_pStream );
	if( ui32ReadSize != ui32Size ) {
		m_ui32Error = IO_ERROR_READ;
		return m_ui32Error;
	}

	return IO_OK;
}

uint32
LoadC::read_str( char* szStr )
{
	if( m_ui32Error )
		return m_ui32Error;
	if( !m_pStream || !m_ui32Indent )
		return IO_ERROR_OPEN;

	// first read size of the string
	uint16	ui16StrSize;

	if( fread( &ui16StrSize, sizeof( ui16StrSize ), 1, m_pStream ) != 1 ) {
		m_ui32Error = IO_ERROR_READ;
		return m_ui32Error;
	}

	if( ui16StrSize ) {
		uint32	ui32ReadSize = fread( szStr, 1, ui16StrSize, m_pStream );
		if( ui32ReadSize != ui16StrSize ) {
			m_ui32Error = IO_ERROR_READ;
			return m_ui32Error;
		}
	}

	// terminate the string
	szStr[ui16StrSize] = '\0';

	return IO_OK;
}

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

void
LoadC::add_file_handle_patch( void** pPointer, uint32 ui32HandleId )
{
	FileHandlePatchS	rPatch;
	rPatch.m_pPointer = pPointer;
	rPatch.m_ui32HandleId = ui32HandleId;
	m_rFileHandlePatches.push_back( rPatch );
}

void
LoadC::add_effect_patch( void** pPointer, void* pLayer, uint32 ui32EffectId )
{
	EffectPatchS	rPatch;
	rPatch.m_pLayer = pLayer;
	rPatch.m_ui32EffectId = ui32EffectId;
	rPatch.m_pPointer = pPointer;
	m_rEffectPatches.push_back( rPatch );
}

uint32
LoadC::get_file_handle_patch_count()
{
	return m_rFileHandlePatches.size();
}

void**
LoadC::get_file_handle_patch_pointer( uint32 ui32Index )
{
	return m_rFileHandlePatches[ui32Index].m_pPointer;
}

uint32
LoadC::get_file_handle_patch_id( PajaTypes::uint32 ui32Index )
{
	return m_rFileHandlePatches[ui32Index].m_ui32HandleId;
}

uint32
LoadC::get_effect_patch_count()
{
	return (uint32)m_rEffectPatches.size();
}

void**
LoadC::get_effect_patch_pointer( uint32 ui32Index )
{
	return m_rEffectPatches[ui32Index].m_pPointer;
}

uint32
LoadC::get_effect_patch_id( uint32 ui32Index )
{
	return m_rEffectPatches[ui32Index].m_ui32EffectId;
}

void*
LoadC::get_effect_patch_layer( uint32 ui32Index )
{
	return m_rEffectPatches[ui32Index].m_pLayer;
}

FactoryC*
LoadC::get_factory() const
{
	return m_pFactory;
}

uint32
LoadC::get_error_message_count()
{
	return m_rErrorLog.size();
}

const char*
LoadC::get_error_message( PajaTypes::uint32 ui32Index )
{
	return m_rErrorLog[ui32Index].m_sMessage.c_str();
}

void
LoadC::add_error_message( const char* szMessage )
{
	ErrorMessageS	rErrMsg;
	rErrMsg.m_sMessage = szMessage;
	m_rErrorLog.push_back( rErrMsg );
}

uint32
LoadC::get_file_size() const
{
	return m_ui32FileSize;
}

uint32
LoadC::get_read_pos() const
{
	uint32	ui32CurPos = 0;
	if( m_pStream )
		ui32CurPos = ftell( m_pStream );
	return ui32CurPos;
}
