#include "DeerStudio/AngelScriptEngine.h"
#include "DeerStudio/AngelScriptEngine/ErrorHandle.h"
#include "angelscript.h"
#include <cstring>
#include <string>

namespace Deer {
	namespace AngelScriptEngine {
		void Service::init() {
			asIScriptFunction* constructorFunction = getFactory(type);

			if (!constructorFunction) {
				DEER_CORE_ERROR("Error while initing {}", type->GetName());
				return;
			}

			AS_CHECK(scriptContext->Prepare(constructorFunction));
			AS_CHECK(scriptContext->Execute());

			object = *(asIScriptObject**)scriptContext->GetAddressOfReturnValue();
			if (!object) {
				DEER_CORE_ERROR("Error while initing {}", type->GetName());
				AS_CHECK(scriptContext->Unprepare());
				return;
			}

			object->AddRef();
			AS_CHECK(scriptContext->Unprepare());

			if (!initFunction)
				return;
			
			AS_CHECK(scriptContext->Prepare(initFunction));
			AS_CHECK(scriptContext->SetObject(object));
			AS_CHECK(scriptContext->Execute());

			AS_CHECK(scriptContext->Unprepare());
		}

		void Service::update() {
			if (!updateFunction)
				return;

			AS_CHECK(scriptContext->Prepare(updateFunction));
			AS_CHECK(scriptContext->SetObject(object));
			AS_CHECK(scriptContext->Execute());

			AS_CHECK(scriptContext->Unprepare());
		}

		void Service::shutdown() {
			if (!shutdownFunction) {
				if (object)
					object->Release();
						
				AS_CHECK(scriptContext->Unprepare());
				return;
			}

			AS_CHECK(scriptContext->Prepare(shutdownFunction));
			AS_CHECK(scriptContext->SetObject(object));
			AS_CHECK(scriptContext->Execute());

			if (object)
				object->Release();	

			AS_CHECK(scriptContext->Unprepare());
		}

		Service::Service(asITypeInfo* _type)
		    : type(_type) {

			updateFunction = type->GetMethodByDecl("void update()");
			initFunction = type->GetMethodByDecl("void init()");
			shutdownFunction = type->GetMethodByDecl("void shutdown()");
		}

		Service::~Service() { }
	} // namespace AngelScriptEngine
} // namespace Deer