#include "DeerStudio/StudioAPI/Entity.h"
#include "DeerStudio/AngelScriptEngine/AngelScriptRegisters.h"

namespace Deer {
	namespace AngelScriptEngine {
		void registerTransformComponentFunctions();
		void registerMeshComponentFunction();
		void registerShaderComponentFunctions();
		void registerComponentComponentFunctions();
	} // namespace AngelScriptEngine

	void AngelScriptEngine::registerEntityStructs() {
		AS_CHECK(scriptEngine->RegisterObjectType("Entity", sizeof(StudioAPI::EntityHandleStruct), asOBJ_VALUE | asOBJ_POD | asGetTypeTraits<StudioAPI::EntityHandleStruct>() | asOBJ_APP_CLASS_ALLINTS));
		AS_CHECK(scriptEngine->RegisterObjectType("EntityChilds", sizeof(StudioAPI::EntityHandleStruct), asOBJ_VALUE | asOBJ_POD | asGetTypeTraits<StudioAPI::EntityHandleStruct>() | asOBJ_APP_CLASS_ALLINTS));
		AS_CHECK(scriptEngine->RegisterObjectType("TransformComponent", sizeof(StudioAPI::EntityHandleStruct), asOBJ_VALUE | asOBJ_POD | asGetTypeTraits<StudioAPI::EntityHandleStruct>() | asOBJ_APP_CLASS_ALLINTS));
		AS_CHECK(scriptEngine->RegisterObjectType("MeshComponent", sizeof(StudioAPI::EntityHandleStruct), asOBJ_VALUE | asOBJ_POD | asGetTypeTraits<StudioAPI::EntityHandleStruct>() | asOBJ_APP_CLASS_ALLINTS));
		AS_CHECK(scriptEngine->RegisterObjectType("ShaderComponent", sizeof(StudioAPI::EntityHandleStruct), asOBJ_VALUE | asOBJ_POD | asGetTypeTraits<StudioAPI::EntityHandleStruct>() | asOBJ_APP_CLASS_ALLINTS));
		AS_CHECK(scriptEngine->RegisterObjectType("CameraComponent", sizeof(StudioAPI::EntityHandleStruct), asOBJ_VALUE | asOBJ_POD | asGetTypeTraits<StudioAPI::EntityHandleStruct>() | asOBJ_APP_CLASS_ALLINTS));
	}

	void AngelScriptEngine::registerEntityFunctions() {
		registerTransformComponentFunctions();
		registerMeshComponentFunction();
		registerShaderComponentFunctions();
		registerComponentComponentFunctions();

		REGISTER_OBJECT_METHOD("Entity", "string get_name() const property", StudioAPI::EntityStruct, getName);
		REGISTER_OBJECT_METHOD("Entity", "void set_name(string& in) property", StudioAPI::EntityStruct, setName);
		REGISTER_OBJECT_METHOD("Entity", "int get_id() const property", StudioAPI::EntityStruct, getId);
		REGISTER_OBJECT_METHOD("Entity", "Entity createChild(const string& in)", StudioAPI::EntityStruct, createChild);
		REGISTER_OBJECT_METHOD("Entity", "bool get_isRoot() const property", StudioAPI::EntityStruct, isRoot);
		REGISTER_OBJECT_METHOD("Entity", "void destroy()", StudioAPI::EntityStruct, destroy);
		REGISTER_OBJECT_METHOD("Entity", "bool get_exists() const property", StudioAPI::EntityStruct, exists);
		REGISTER_OBJECT_METHOD("Entity", "Entity get_parent() property", StudioAPI::EntityStruct, getParent);
		REGISTER_OBJECT_METHOD("Entity", "void set_parent(Entity) property", StudioAPI::EntityStruct, setParent);
		REGISTER_OBJECT_METHOD("Entity", "bool isDescendantOf(Entity)", StudioAPI::EntityStruct, isDescendantOf);
		REGISTER_OBJECT_METHOD("Entity", "bool opEquals(const Entity &in) const", StudioAPI::EntityStruct, opEquals);
		REGISTER_OBJECT_METHOD("Entity", "EntityChilds get_childs() const property", StudioAPI::EntityStruct, getSelf);
		REGISTER_OBJECT_METHOD("Entity", "TransformComponent get_transform() const property", StudioAPI::EntityStruct, getSelf);
		REGISTER_OBJECT_METHOD("Entity", "MeshComponent getMeshComponent()", StudioAPI::EntityStruct, getMeshComponent);
		REGISTER_OBJECT_METHOD("Entity", "MeshComponent createMeshComponent()", StudioAPI::EntityStruct, createMeshComponent);
		REGISTER_OBJECT_METHOD("Entity", "bool hasMeshComponent()", StudioAPI::EntityStruct, hasMeshComponent);
		REGISTER_OBJECT_METHOD("Entity", "void removeMeshComponent()", StudioAPI::EntityStruct, removeMeshComponent);
		REGISTER_OBJECT_METHOD("Entity", "ShaderComponent getShaderComponent()", StudioAPI::EntityStruct, getShaderComponent);
		REGISTER_OBJECT_METHOD("Entity", "ShaderComponent createShaderComponent()", StudioAPI::EntityStruct, createShaderComponent);
		REGISTER_OBJECT_METHOD("Entity", "bool hasShaderComponent()", StudioAPI::EntityStruct, hasShaderComponent);
		REGISTER_OBJECT_METHOD("Entity", "void removeShaderComponent()", StudioAPI::EntityStruct, removeShaderComponent);
		REGISTER_OBJECT_METHOD("Entity", "CameraComponent getCameraComponent()", StudioAPI::EntityStruct, getCameraComponent);
		REGISTER_OBJECT_METHOD("Entity", "CameraComponent createCameraComponent()", StudioAPI::EntityStruct, createCameraComponent);
		REGISTER_OBJECT_METHOD("Entity", "bool hasCameraComponent()", StudioAPI::EntityStruct, hasCameraComponent);
		REGISTER_OBJECT_METHOD("Entity", "void removeCameraComponent()", StudioAPI::EntityStruct, removeCameraComponent);

		scriptEngine->SetDefaultNamespace("Engine");
		REGISTER_GLOBAL_FUNC("Entity getRoot()", StudioAPI::getRoot);
		scriptEngine->SetDefaultNamespace("");

		REGISTER_OBJECT_METHOD("EntityChilds", "int get_count() const property", StudioAPI::EntityChildArrayStruct, getChildCount);
		REGISTER_OBJECT_METHOD("EntityChilds", "Entity opIndex(int) const", StudioAPI::EntityChildArrayStruct, getChild);
	}

	void AngelScriptEngine::registerMeshComponentFunction() {
		REGISTER_OBJECT_METHOD("MeshComponent", "bool get_isActive() const property", StudioAPI::MeshComponentStruct, isActive);
		REGISTER_OBJECT_METHOD("MeshComponent", "bool get_hasMesh() const property", StudioAPI::MeshComponentStruct, hasMesh);
		REGISTER_OBJECT_METHOD("MeshComponent", "void clear()", StudioAPI::MeshComponentStruct, clear);
		REGISTER_OBJECT_METHOD("MeshComponent", "GPUMesh get_meshResource() property", StudioAPI::MeshComponentStruct, getMesh);
		REGISTER_OBJECT_METHOD("MeshComponent", "void set_meshResource(GPUMesh) property", StudioAPI::MeshComponentStruct, setMesh);
		REGISTER_OBJECT_METHOD("MeshComponent", "void set_isActive(const bool) const property", StudioAPI::MeshComponentStruct, setActive);
	}

	void AngelScriptEngine::registerTransformComponentFunctions() {
		REGISTER_OBJECT_METHOD("TransformComponent", "vec3 get_position() const property", StudioAPI::TransformComponentStruct, getPosition);
		REGISTER_OBJECT_METHOD("TransformComponent", "vec3 get_scale() const property", StudioAPI::TransformComponentStruct, getScale);
		REGISTER_OBJECT_METHOD("TransformComponent", "vec3 get_rotation() const property", StudioAPI::TransformComponentStruct, getRotation);

		REGISTER_OBJECT_METHOD("TransformComponent", "void set_position(const vec3) property", StudioAPI::TransformComponentStruct, setPosition);
		REGISTER_OBJECT_METHOD("TransformComponent", "void set_scale(const vec3) property", StudioAPI::TransformComponentStruct, setScale);
		REGISTER_OBJECT_METHOD("TransformComponent", "void set_rotation(const vec3) property", StudioAPI::TransformComponentStruct, setRotation);
	}

	void AngelScriptEngine::registerShaderComponentFunctions() {
		REGISTER_OBJECT_METHOD("ShaderComponent", "bool get_hasShader() const property", StudioAPI::ShaderComponentStruct, hasShader);
		REGISTER_OBJECT_METHOD("ShaderComponent", "void clear()", StudioAPI::ShaderComponentStruct, clear);

		REGISTER_OBJECT_METHOD("ShaderComponent", "Shader get_shader() const property", StudioAPI::ShaderComponentStruct, getShader);
		REGISTER_OBJECT_METHOD("ShaderComponent", "void set_shader(Shader) property", StudioAPI::ShaderComponentStruct, setShader);

		REGISTER_OBJECT_METHOD("ShaderComponent", "Texture get_texture() const property", StudioAPI::ShaderComponentStruct, getTexture);
		REGISTER_OBJECT_METHOD("ShaderComponent", "void set_texture(Texture) property", StudioAPI::ShaderComponentStruct, setTexture);
	}

	void AngelScriptEngine::registerComponentComponentFunctions() {
		REGISTER_OBJECT_METHOD("CameraComponent", "float get_fov() const property", StudioAPI::CameraComponentStruct, getFov);
		REGISTER_OBJECT_METHOD("CameraComponent", "float get_aspectRatio() const property", StudioAPI::CameraComponentStruct, getAspectRation);
		REGISTER_OBJECT_METHOD("CameraComponent", "float get_nearZ() const property", StudioAPI::CameraComponentStruct, getNearZ);
		REGISTER_OBJECT_METHOD("CameraComponent", "float get_farZ() const property", StudioAPI::CameraComponentStruct, getFarZ);

		REGISTER_OBJECT_METHOD("CameraComponent", "void set_fov(float) property", StudioAPI::CameraComponentStruct, setFov);
		REGISTER_OBJECT_METHOD("CameraComponent", "void set_aspectRatio(float) property", StudioAPI::CameraComponentStruct, setAspectRation);
		REGISTER_OBJECT_METHOD("CameraComponent", "void set_nearZ(float) property", StudioAPI::CameraComponentStruct, setNearZ);
		REGISTER_OBJECT_METHOD("CameraComponent", "void set_farZ(float) property", StudioAPI::CameraComponentStruct, setFarZ);
	}
} // namespace Deer
