#include "DeerStudio/EditorEngine.h"
#include "DeerStudio/EditorEngine/ErrorHandle.h"
#include "DeerStudio/EditorEngine/API.h"
#include "DeerStudio/EditorEngine/API_Registration/API_Registration.h"

#include "scripthandle.h"
#include "scriptany.h"
#include "angelscript.h"

namespace Deer {
    namespace EditorEngine { 
        void registerTransformComponentFunctions();
        void registerMeshComponentFunction();
        void registerShaderComponentFunctions();
        void registerComponentComponentFunctions();

        void registerEntityStructs() {
            AS_CHECK(scriptEngine->RegisterObjectType("Entity", sizeof(EntityHandleStruct), 
                asOBJ_VALUE | asOBJ_POD | asGetTypeTraits<EntityHandleStruct>() | asOBJ_APP_CLASS_ALLINTS));

            AS_CHECK(scriptEngine->RegisterObjectType("EntityChilds", sizeof(EntityHandleStruct), 
                asOBJ_VALUE | asOBJ_POD | asGetTypeTraits<EntityHandleStruct>() | asOBJ_APP_CLASS_ALLINTS));

            AS_CHECK(scriptEngine->RegisterObjectType("TransformComponent", sizeof(EntityHandleStruct), 
                asOBJ_VALUE | asOBJ_POD | asGetTypeTraits<EntityHandleStruct>() | asOBJ_APP_CLASS_ALLINTS));

            AS_CHECK(scriptEngine->RegisterObjectType("MeshComponent", sizeof(EntityHandleStruct), 
                asOBJ_VALUE | asOBJ_POD | asGetTypeTraits<EntityHandleStruct>() | asOBJ_APP_CLASS_ALLINTS));

            AS_CHECK(scriptEngine->RegisterObjectType("ShaderComponent", sizeof(EntityHandleStruct), 
            asOBJ_VALUE | asOBJ_POD | asGetTypeTraits<EntityHandleStruct>() | asOBJ_APP_CLASS_ALLINTS));

            AS_CHECK(scriptEngine->RegisterObjectType("CameraComponent", sizeof(EntityHandleStruct), 
            asOBJ_VALUE | asOBJ_POD | asGetTypeTraits<EntityHandleStruct>() | asOBJ_APP_CLASS_ALLINTS));
        }

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

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

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

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

        }

        void registerMeshComponentFunction() {
            REGISTER_OBJECT_METHOD("MeshComponent", "bool get_isActive() const property", MeshComponentStruct, isActive);
            REGISTER_OBJECT_METHOD("MeshComponent", "bool get_hasMesh() const property", MeshComponentStruct, hasMesh);
            REGISTER_OBJECT_METHOD("MeshComponent", "void clear()", MeshComponentStruct, clear);
            REGISTER_OBJECT_METHOD("MeshComponent", "string getMesh()", MeshComponentStruct, getMesh);
            REGISTER_OBJECT_METHOD("MeshComponent", "void setMesh(string&in)", MeshComponentStruct, setMesh);
            REGISTER_OBJECT_METHOD("MeshComponent", "void set_isActive(const bool) property", MeshComponentStruct, setActive);
        }

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

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

        void registerShaderComponentFunctions() {
            REGISTER_OBJECT_METHOD("ShaderComponent", "bool get_hasShader() const property", ShaderComponentStruct, hasShader);
            REGISTER_OBJECT_METHOD("ShaderComponent", "void clear()", ShaderComponentStruct, clear);
            REGISTER_OBJECT_METHOD("ShaderComponent", "string getShader()", ShaderComponentStruct, getShader);
            REGISTER_OBJECT_METHOD("ShaderComponent", "void setShader(const string& in)", ShaderComponentStruct, setShader);
        }
    
        void registerComponentComponentFunctions() {
            REGISTER_OBJECT_METHOD("CameraComponent", "float get_fov() const property", CameraComponentStruct, getFov);
            REGISTER_OBJECT_METHOD("CameraComponent", "float get_aspectRatio() const property", CameraComponentStruct, getAspectRation);
            REGISTER_OBJECT_METHOD("CameraComponent", "float get_nearZ() const property", CameraComponentStruct, getNearZ);
            REGISTER_OBJECT_METHOD("CameraComponent", "float get_farZ() const property", CameraComponentStruct, getFarZ);

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