/** @file bytestreamencoder.cpp @headerfile bytestreamencoder.h "EABaseTypesPlus/bytestreamencoder.h"
*	An encoder that Writes data in a fast bytestream format
*	@author Chris Burns (cburns@ea.com)
*
*	CTUI
*	(c) 2013 Electronic Arts Inc.
*/

#include "EABaseTypesPlus/bytestreamencoder.h"

namespace EA
{
	namespace Types
	{
		template<typename T>
		void EncodeBytes(ByteStream* out, T value)
		{
			out->Write(reinterpret_cast<const unsigned char*>(&value), sizeof(T));
		}
		
		static void EncodeString(ByteStream* out, const char* str, size_t length)
		{
			out->Write(reinterpret_cast<const unsigned char*>(str), length);
			out->Write(0); // NULL-terminated
		}
	
		ByteStreamEncoder::ByteStreamEncoder(ByteStream* out):
			mOut(out) {}
	
		void ByteStreamEncoder::Reset()
		{
			mOut->Write(CODE_RESET);
		
			mOut->Clear();
		}

		void ByteStreamEncoder::BeginArray()
		{
			mOut->Write(CODE_ARRAY);
		}
		
		void ByteStreamEncoder::EndArray()
		{
			mOut->Write(CODE_END);
		}

		void ByteStreamEncoder::BeginArrayValue(size_t index)
		{
			mOut->Write(CODE_HASNEXT);
		}

		void ByteStreamEncoder::BeginObject()
		{
			mOut->Write(CODE_OBJECT);
		}
		
		void ByteStreamEncoder::EndObject()
		{
			mOut->Write(CODE_END);
		}

		void ByteStreamEncoder::BeginObjectValue(const char* key, size_t length)
		{
			mOut->Write(CODE_HASNEXT);
			EncodeString(mOut, key, length);
		}

		void ByteStreamEncoder::Boolean(bool boolean)
		{
			mOut->Write(CODE_BOOLEAN);
			EncodeBytes(mOut, boolean);
		}
		
		void ByteStreamEncoder::Number(BaseTypeFloat number)
		{
			mOut->Write(CODE_NUMBER);
			EncodeBytes(mOut, number);
		}
		
		void ByteStreamEncoder::String(const char* str, size_t length)
		{
			mOut->Write(CODE_STRING);
			EncodeString(mOut, str, length);
		}
		
		void ByteStreamEncoder::Function(FunctionIn function)
		{
			mOut->Write(CODE_FUNCTION);
			
			function->AddRef();
			
			EncodeBytes(mOut, function.GetUnsafePointer());
		}
		
		void ByteStreamEncoder::UserData(UserDataIn userData)
		{
			mOut->Write(CODE_USERDATA);
			
			userData->AddRef();
			
			EncodeBytes(mOut, userData.GetUnsafePointer());
		}
		
		void ByteStreamEncoder::Null()
		{
			mOut->Write(CODE_NULL);
		}
	}
}
