/** @file structencoder.cpp
*	struct encoder context/decode implementation
 * 	@headerfile structencoder.h "EABaseTypes/structencoder.h"
 *	@author Chris Burns (cburns@ea.com)
 *
 *	EABaseTypes
 *	(c) 2012 Electronic Arts Inc. 
 */

#include "EABaseTypes/structencoder.h"

namespace EA
{
	namespace Types
	{
		StructContext::StructContext(Factory* factory,
									 IEncoderContext* parent,
									 void* value,
									 const StructSchema* schema):
			ChildContext(parent, value),
			mFactory(factory),
			mSchema(schema),
			mCurrentContext(NULL),
			mNullContext(NULL, NULL)
		{
			mNullContext.SetParent(this);
		}

		/* virtual */ void StructContext::BeginArray() { EA_FAIL_MESSAGE("Cannot encode an Array as a struct"); }

		//lint -efunc(904, EA::Types::StructContext::BeginObjectValue)
		//lint -efunc(1536, EA::Types::StructContext::BeginObjectValue)
		/* virtual */ IEncoderContext* StructContext::BeginObjectValue(const char* key, size_t length)
		{
			unsigned int i = 0;
			const char* currentKey = mSchema[i].mKey;
			while(currentKey != NULL)
			{
				// none too efficient
				if(strlen(currentKey) == length && strncmp(currentKey, key, length) == 0)
				{
					mCurrentContext = mSchema[i].mCreateContext(mFactory, this, static_cast<char*>(mValue) + mSchema[i].mOffset);

					return mCurrentContext;
				}

				++i;
				currentKey = mSchema[i].mKey;
			}
				
			EA_FAIL_MESSAGE("Key not found in struct schema");
			return &mNullContext;
		}
	
		/* virtual */ void StructContext::EndObjectValue(const char* key, size_t length)
		{
			// delete the encoder
			if(mCurrentContext != NULL)
			{
				CORE_DELETE(mFactory->GetAllocator(), mCurrentContext);
				mCurrentContext = NULL;
			}
		}

		/* virtual */ IEncoderContext* StructContext::Boolean(bool boolean) { EA_FAIL_MESSAGE("Cannot encode a Boolean as a struct"); return mParent; }
		/* virtual */ IEncoderContext* StructContext::Number(BaseTypeFloat number) { EA_FAIL_MESSAGE("Cannot encode a Number as a struct"); return mParent; }
		/* virtual */ IEncoderContext* StructContext::String(const char* str, size_t length) { EA_FAIL_MESSAGE("Cannot encode a String as a struct"); return mParent; }
		/* virtual */ IEncoderContext* StructContext::Function(FunctionIn function) { EA_FAIL_MESSAGE("Cannot encode a Function as a struct"); return mParent; }
		/* virtual */ IEncoderContext* StructContext::UserData(UserDataIn userData) { EA_FAIL_MESSAGE("Cannot encode a UserData as a struct"); return mParent; }
		/* virtual */ IEncoderContext* StructContext::Null() { EA_FAIL_MESSAGE("Cannot encode Null as a struct"); return mParent; }

		void DecodeStruct(Factory* factory, IEncoder* encoder, void* value, const StructSchema* schema)
		{
			encoder->BeginObject();
	
			unsigned int i = 0;
			const char* currentKey = schema[i].mKey;
			while(currentKey != NULL)
			{
				size_t length = strlen(currentKey);
				encoder->BeginObjectValue(currentKey, length);
		
				schema[i].mDecode(factory, encoder, static_cast<char*>(value) + schema[i].mOffset);
		
				encoder->EndObjectValue(currentKey, length);
	
				++i;
				currentKey = schema[i].mKey;
			}
	
			encoder->EndObject();
		}
	}
}
