/** @file jsonloader.cpp
* Json file loading utility
* @headerfile jsonloader.h "EABaseTypesJson/jsonloader.h"
* @author Nick Beatty (nbeatty@ea.com)
* (c) 2012 Electronic Arts Inc.
*/

#include "EABaseTypesJson/jsonloader.h"

#include "EABaseTypes/nullencoder.h"
#include "EABaseTypes/functioncallwrappers.h"
#include "EABaseTypes/profile.h"

#include "EABaseTypesPlus/ifilehandler.h"
#include "EABaseTypesPlus/vrefcountedica.h"

#include "EABaseTypesJson/jsonencoder.h"
#include "EABaseTypesJson/basetypejsonparser.h"
#include "EABaseTypesJson/basetypejsonwriter.h"
#include "EABaseTypesJson/rawstringwritestream.h"

namespace EA
{
	namespace Types
	{
		class JsonFileLoadCallback : public VRefCountedICA<IFileHandlerCallback>
		{
		public:
			JsonFileLoadCallback(FunctionIn callback)
				: VRefCountedICA<IFileHandlerCallback>(callback->GetFactory()->GetAllocator())
				, mCallback(callback)
			{
			}

			virtual ~JsonFileLoadCallback()
			{
			}

			virtual void LoadComplete(IFileResourceIn fileResource)
			{
				EABASETYPES_PROFILE_AUTO(a, 0, "JsonLoader_LoadComplete");

				if(fileResource != NULL)
				{
					JsonCallbackReader callbackReader(mCallback->GetFactory()->GetAllocator());
					callbackReader.SetString(static_cast<char*>(fileResource->GetData()), fileResource->GetSize(), false);

					JsonDecoderParams decoderParams(mCallback->GetFactory(), &callbackReader);
					NullEncoder encoder;
					
					IEncoderImpl<NullEncoder> defaultEncoder(&encoder);

					mCallback->Call(JsonLoader::CALLER_TYPE, &decoderParams, &encoder, JsonDecoder<IEncoder>::Decode, &defaultEncoder);
				}
				else
				{
					mCallback->Call<void>(BaseTypeIn(NULL), "File not found!");
				}
			}

		private:

			FunctionRef mCallback;
		};

		JsonLoader::JsonLoader(Factory* factory, IFileHandlerIn filehandler)
			: mFactory(factory)
			, mFileHandler(filehandler)
		{
		}

		JsonLoader::~JsonLoader()
		{
			mFactory = NULL;
		}

		//LINT Custodial pointer 'jsoncb' has not been freed or returned. We free it when then load completes in IFileHandler::Update
		//lint -efunc(429, UX::JsonLoader::Load)
		void JsonLoader::Load(FunctionIn callback, const char* fileName)
		{
			EA::Allocator::ICoreAllocator* allocator = mFactory->GetAllocator();

			IFileHandlerCallbackRef jsoncb = CORE_NEW(allocator, "JsonFileLoadCallback", EA::Allocator::MEM_TEMP) JsonFileLoadCallback(callback);
			mFileHandler->Load(jsoncb, allocator, fileName);
		}

		BaseTypeReturn JsonLoader::Load(const char* fileName)
		{
			IFileResourceRef fileResource = mFileHandler->Load(mFactory->GetAllocator(), fileName);

			EA::RawString error(mFactory->GetAllocator());

			BaseTypeRef result = BaseTypeJsonParser::Parse(mFactory, fileResource->GetData(), fileResource->GetSize(), error);

			EA_ASSERT_FORMATTED(result != NULL, ("%s\n", error.c_str()));

			return result;
		}

		BaseTypeReturn JsonLoader::Parse(const EA::RawString& json)
		{
			EA::RawString error(mFactory->GetAllocator());

			BaseTypeRef result = BaseTypeJsonParser::Parse(mFactory, const_cast<char*>(json.c_str()), json.length(), error);

			EA_ASSERT_FORMATTED(result != NULL, ("%s\n", error.c_str()));

			return result;
		}

		EA::RawString JsonLoader::Write(BaseTypeIn data)
		{
			EA::RawString result(mFactory->GetAllocator());
			EA::RawStringWriteStream stream(&result);

			BaseTypeJsonWriter::Write(data, &stream);

			return result;
		}

		// PcLint can't deal with these templates
		//lint -efunc(64, UX::JsonLoader::ToObject)
		//lint -efunc(918, UX::JsonLoader::ToObject)
		ObjectReturn JsonLoader::ToObject()
		{
			ObjectRef result = mFactory->Object();

			// disambiguate overloaded functions
			typedef void (JsonLoader::*LoadType)(FunctionIn, const char*);
			LoadType load = &JsonLoader::Load;

			// should these be capitalized?
			result->insert("load", mFactory->Function(this, load));
			result->insert("parse", mFactory->Function(this, &JsonLoader::Parse));
			result->insert("write", mFactory->Function(this, &JsonLoader::Write));

			return result;
		}
	}
}
