/*==LICENSE==*

CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011  Cyan Worlds, Inc.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

You can contact Cyan Worlds, Inc. by email legal@cyan.com
 or by snail mail at:
      Cyan Worlds, Inc.
      14617 N Newport Hwy
      Mead, WA   99021

*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
//
//	plRawPageAccessor - Dangerous little class that lets you take a
//					    plRegistryPageNode and load the objects in raw (i.e.
//						as block memory buffers).
//						This should NOT be used in any normal app, only 
//						utility apps that don't want to load objects in
//						normally (which basically means if you're not mcn,
//						don't use this!)
//
//// Why We're Bad ///////////////////////////////////////////////////////////
//
//	To store all the raw buffers, we stuff them as pointers into the keys
//	themselves. This is Way Bad(tm) because those pointers are expecting
//	hsKeyedObjects, and what we're giving them certainly ain't those.
//	This is why it's only safe to use this class in a very small, controlled
//	environment, one where we know the keys won't be accessed in a normal
//	fashion so we know nobody will try to use our pointers in a bad way.
//
//////////////////////////////////////////////////////////////////////////////

#include "hsTypes.h"
#include "hsStream.h"
#include "hsResMgr.h"
#include "plRawKeyedObject.h"
#include "../pnKeyedObject/plKeyImp.h"


//// Tiny Yet Now Famous Key Hack ////////////////////////////////////////////

class plPublicKeyImp : public plKeyImp
{
	public:

		void	SetObjectPtrDirect( hsKeyedObject *obj ) 
		{
			fObjectPtr = obj;
		}

		void	SetAsEmpty( void )
		{
			fStartPos = (UInt32)-1;
			fDataLen = (UInt32)-1;
		}

		void	SetStartPosFromStream( hsStream *stream )
		{
			fStartPos = stream->GetPosition();
		}

		void	SetLengthFromStream( hsStream *stream ) 
		{ 
			fDataLen = stream->GetPosition() - fStartPos;
		}
};

//// Constructor/Destructor //////////////////////////////////////////////////

plRawKeyedObject::plRawKeyedObject()
{
	fSrcKey = nil;
	fBuffer = nil;
	fBufferSize = 0;
}

plRawKeyedObject::plRawKeyedObject( const plKey &key, UInt32 size, UInt8 *data )
{
	fSrcKey = key;
	( (plPublicKeyImp *)(plKeyImp *)key )->SetObjectPtrDirect( this );

	fBuffer = nil;
	fBufferSize = 0;

	SetBuffer( size, data );
}

plRawKeyedObject::~plRawKeyedObject()
{
	if( fSrcKey != nil )
	{
		( (plPublicKeyImp *)(plKeyImp *)fSrcKey )->SetObjectPtrDirect( nil );
		fSrcKey = nil;
	}

	delete [] fBuffer;
}

void	plRawKeyedObject::SetBuffer( UInt32 size, UInt8 *data )
{
	delete [] fBuffer;

	if( data == nil )
	{
		fBufferSize = 0;
		fBuffer = nil;
		return;
	}

	fBufferSize = size;
	fBuffer = new UInt8[ size ];
	memcpy( fBuffer, data, size );
}

void	plRawKeyedObject::SetKey( plKey k )
{
	if( fSrcKey != nil )
	{
		( (plPublicKeyImp *)(plKeyImp *)fSrcKey )->SetObjectPtrDirect( nil );
	}

	fSrcKey = k;
	if( fSrcKey != nil )
	{
		( (plPublicKeyImp *)(plKeyImp *)fSrcKey )->SetObjectPtrDirect( this );
	}
}

void	plRawKeyedObject::MarkAsEmpty( plKey &key )
{
	( (plPublicKeyImp *)(plKeyImp *)key )->SetAsEmpty();
}

void	plRawKeyedObject::Write( hsStream *stream )
{
	// BEFORE we write out, somewhere at the top of our buffer is the key to ourselves
	// that all hsKeyedObjects write out as part of their Write() function. We need
	// to REPLACE that key with our new key, since our location has now changed. Note
	// that this will ONLY work if our location changes, NOT if our name changes, 
	// because we're relying on the fact that the written size of our key is not
	// going to change!!!
	{
		hsWriteOnlyStream	replaceStream( fBufferSize, fBuffer );

		// Here's the part that REALLY sucks, 'cause it assumes our written format will never change!!!!
		// It ALSO assumes, VERY dangerously, that ReadSwap16() will ALWAYS read a size UInt16

		replaceStream.SetPosition( sizeof( UInt16 ) );	// Get past creatable class that resManager writes out

		hsgResMgr::ResMgr()->WriteKey( &replaceStream, fSrcKey, hsResMgr::kWriteNoCheck );
	}

	( (plPublicKeyImp *)(plKeyImp *)fSrcKey )->SetStartPosFromStream( stream );

	stream->Write( fBufferSize, fBuffer );

	( (plPublicKeyImp *)(plKeyImp *)fSrcKey )->SetLengthFromStream( stream );
}


//// Warning Stubs ///////////////////////////////////////////////////////////

void	plRawKeyedObject::Validate()
{
	hsAssert( false, "Invalid call on plRawKeyedObject" );
}

hsBool	plRawKeyedObject::IsFinal()
{
	hsAssert( false, "Invalid call on plRawKeyedObject" );
	return false;
}

void	plRawKeyedObject::Read(hsStream *s, hsResMgr *mgr )
{
	hsAssert( false, "Invalid call on plRawKeyedObject" );
}

void	plRawKeyedObject::Write(hsStream *s, hsResMgr *mgr )
{
	hsAssert( false, "Invalid call on plRawKeyedObject" );
}

hsBool	plRawKeyedObject::MsgReceive( plMessage *msg )
{
	hsAssert( false, "Invalid call on plRawKeyedObject" );
	return false;
}

hsKeyedObject *plRawKeyedObject::GetSharedObject()
{
	hsAssert( false, "Invalid call on plRawKeyedObject" );
	return nil;
}