/* -----------------------------------------------------------------------------
	GSFramework
	Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */


		#include "script_squirrel/legacy/binding_helpers.h"
		#include "project/project.h"
		#include "scene3d/scene.h"
		#include "ui/ui_camera.h"
		#include "ui/ui.h"

		using namespace GS;
		using namespace GS::Core;
		using namespace GS::Script;


//------------------------------------------------------------------------------
SQInteger			ProjectGetClock(HSQUIRRELVM vm)
{
	__SQ_GETSINGLESAFEPTR(project, Project, typetag_Project)
	__SQ_RETURNSAFEPTR(project->clock.c_ptr(), typetag_Clock)
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
SQInteger			ProjectSetAll2DLayerOffset(HSQUIRRELVM vm)
{
	__SQ_GETSTART(3)
	__SQ_GETSAFEPTR(project, Project, typetag_Project)
	__SQ_GETFLOAT(x)
	__SQ_GETFLOAT(y)
	__SQ_GETEND

	ListForeachPtr(ProjectLayer *, layer, project->layer_list)
		if	(layer->inst)
			if	(S2D::Scene *scene = layer->inst->instance_2d)
			{
				scene->offset_matrix = Matrix3::IdentityMatrix();
				scene->offset_matrix.m[0][2] = x / scene->GetCurrentCamera()->resolution.x;
				scene->offset_matrix.m[1][2] = y / scene->GetCurrentCamera()->resolution.y;
			}

	__SQ_RETURN
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
SQInteger			ProjectLayerGetScene(HSQUIRRELVM vm)
{
	__SQ_GETSINGLESAFEPTR(layer, ProjectLayer, typetag_ProjectLayer)
	if	(!layer->inst)
		return sq_throwerror(vm, "No scene in project layer");
	__SQ_RETURNSAFEPTR(layer->inst, typetag_ProjectScene)
}
SQInteger			ProjectLayerSetZOrder(HSQUIRRELVM vm)
{
	__SQ_GETSTART(2)
	__SQ_GETSAFEPTR(layer, ProjectLayer, typetag_ProjectLayer)
	__SQ_GETFLOAT(zorder)
	__SQ_GETEND
	layer->zorder = zorder;
	__SQ_RETURN
}
SQInteger			ProjectLayerGetZOrder(HSQUIRRELVM vm)
{
	__SQ_GETSINGLESAFEPTR(layer, ProjectLayer, typetag_ProjectLayer)
	__SQ_RETURNFLOAT(layer->zorder)
}
SQInteger			ProjectAddLayer(HSQUIRRELVM vm)
{
	__SQ_GETSTART(3)
	__SQ_GETSAFEPTR(project, Project, typetag_Project)
	__SQ_GETSAFEPTR(instance, ProjectSceneInstance, typetag_ProjectScene)
	__SQ_GETFLOAT(zorder)
	__SQ_GETEND
	__SQ_RETURNSAFEPTR(project->AddLayer(instance, zorder), typetag_ProjectLayer)
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
SQInteger			ProjectNewScene3D(HSQUIRRELVM vm)
{
	__SQ_GETSINGLESAFEPTR(project, Project, typetag_Project)
	__SQ_RETURNMANAGEDSAFEPTR(project->Instantiate(new S3D::Scene(project->vm)), typetag_ProjectScene)
}
SQInteger			ProjectNewScene2D(HSQUIRRELVM vm)
{
	__SQ_GETSINGLESAFEPTR(project, Project, typetag_Project)
	__SQ_RETURNMANAGEDSAFEPTR(project->Instantiate(new S2D::Scene(project->vm)), typetag_ProjectScene)
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
SQInteger			ProjectGetSceneLayerList(HSQUIRRELVM vm)
{
	__SQ_GETSTART(2)
	__SQ_GETSAFEPTR(project, Project, typetag_Project)
	__SQ_GETSAFEPTR(scene, ProjectSceneInstance, typetag_ProjectScene)
	__SQ_GETEND

	sq_newarray(vm, 0);
	for (uint n = 0; n < project->layer_list.GetCount(); ++n)
	{
		ProjectLayer *layer = project->layer_list[n];
		if	(layer->inst == scene)
		{
			CObject::Push(vm, (void *)layer, typetag_ProjectLayer);
			sq_arrayappend(vm, -2);
		}
	}
	return 1;
}
SQInteger			ProjectInstantiateScene(HSQUIRRELVM vm)
{
	__SQ_GETSTART(2)
		__SQ_GETSAFEPTR(project, Project, typetag_Project)
		__SQ_GETSTRING(path)
	sq_collectgarbage(vm);
	ProjectSceneInstance *project_scene = project->Instantiate(path);
	__SQ_GETEND
	__SQ_RETURNSAFEPTR(project_scene, typetag_ProjectScene)
}
SQInteger			ProjectSceneIsActive(HSQUIRRELVM vm)
{
	__SQ_GETSTART(2)
	__SQ_GETSAFEPTR(project, Project, typetag_Project)
	__SQ_GETSAFEPTR(scene, ProjectSceneInstance, typetag_ProjectScene)
	__SQ_GETEND
	__SQ_RETURNBOOL(project && scene ? project->IsActive(*scene) : false)
}
SQInteger			ProjectSceneActivate(HSQUIRRELVM vm)
{
	__SQ_GETSTART(3)
	__SQ_GETSAFEPTR(project, Project, typetag_Project)
	__SQ_GETSAFEPTR(scene, ProjectSceneInstance, typetag_ProjectScene)
	__SQ_GETBOOL(active)
	__SQ_GETEND
	project->Activate(*scene, active ? true : false);
	__SQ_RETURN
}
SQInteger			ProjectUnloadScene(HSQUIRRELVM vm)
{
	__SQ_GETSTART(2)
	__SQ_GETSAFEPTR(project, Project, typetag_Project)
	__SQ_GETSAFEPTR(scene, ProjectSceneInstance, typetag_ProjectScene)
	__SQ_GETEND
	project->Delete(scene);
	__SQ_RETURN
}
SQInteger			ProjectFindScene(HSQUIRRELVM vm)
{
	__SQ_GETSTART(2)
	__SQ_GETSAFEPTR(project, Project, typetag_Project)
	__SQ_GETSTRING(path)
	ProjectSceneInstance *inst = project->FindSceneInstance(path);
	__SQ_GETEND
	__SQ_RETURNSAFEPTR(inst, typetag_ProjectScene)
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
SQInteger			ProjectSceneGetType(HSQUIRRELVM vm)
{
	__SQ_GETSINGLESAFEPTR(scene, ProjectSceneInstance, typetag_ProjectScene)
	__SQ_RETURNINT(scene->GetType())
}
SQInteger			ProjectSceneGetInstance(HSQUIRRELVM vm)
{
	__SQ_GETSINGLESAFEPTR(scene, ProjectSceneInstance, typetag_ProjectScene)

	switch (scene->GetType())
	{
		case ProjectSceneInstance::Type_Scene2d:
			__SQ_RETURNSAFEPTR(scene->instance_2d, typetag_Scene2d)
		case ProjectSceneInstance::Type_Scene3d:
			__SQ_RETURNSAFEPTR(scene->instance_3d, typetag_Scene3d)

		default: break;
	}
	return sq_throwerror(vm, "Invalid project scene");
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
SQInteger			ProjectGetFileName(HSQUIRRELVM vm)
{
	__SQ_GETSINGLESAFEPTR(project, Project, typetag_Project)
	__SQ_RETURNSTRING(project->name.CutFilePath().toUtf8())
}
SQInteger			ProjectGetFilePath(HSQUIRRELVM vm)
{
	__SQ_GETSINGLESAFEPTR(project, Project, typetag_Project)
	__SQ_RETURNSTRING(project->name.CutFileName().toUtf8())
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
SQInteger			ProjectSceneSetGlobal(HSQUIRRELVM vm)
{
	__SQ_GETSINGLESAFEPTR(scene, ProjectSceneInstance, typetag_ProjectScene)
	if	(scene && (scene->GetType() == ProjectSceneInstance::Type_Scene3d))
		scene->instance_3d->SetAsScriptGlobalScene();
	__SQ_RETURN
}
SQInteger			ProjectGetScriptInstance(HSQUIRRELVM vm)
{
	__SQ_GETSINGLESAFEPTR(project, Project, typetag_Project)
	if	(!project)
		return sq_suspendvm(vm);
	if	(!project->script_unit->Self())
		return sq_throwerror(vm, "No script assigned to this project.");
	__SQ_RETURNOBJECT(((Script::SquirrelObject *)project->script_unit->Self())->object);
}
SQInteger			ProjectEnd(HSQUIRRELVM vm)
{
	__SQ_GETSINGLESAFEPTR(project, Project, typetag_Project)
	if	(project)
		project->flags.Set(Project::ProjectFlagEnd);
//	exit(0);
	__SQ_RETURN
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
SQInteger			ProjectLoadFont(HSQUIRRELVM vm)
{
	__SQ_GETSTART(2)
	__SQ_GETSAFEPTR(project, Project, typetag_Project)
	__SQ_GETSTRING(path)
	FontEx *font = project->font_cache->LoadFont(path);
	if	(!font)
		return sq_throwerror(vm, String::Format("Failed to load font '%s'.", path));
	__SQ_GETEND
	__SQ_RETURNSAFEPTR(font, typetag_Font)
}
SQInteger			ProjectLoadFontAliased(HSQUIRRELVM vm)
{
	__SQ_GETSTART(3)
	__SQ_GETSAFEPTR(project, Project, typetag_Project)
	__SQ_GETSTRING(path)
	__SQ_GETSTRING(alias)
	FontEx *font = project->font_cache->LoadFont(path, alias);
	if	(!font)
		return sq_throwerror(vm, String::Format("Failed to load font '%s' under alias '%s'.", path, alias));
	__SQ_GETEND
	__SQ_RETURNSAFEPTR(font, typetag_Font)
}
SQInteger			ProjectDeleteFontAlias(HSQUIRRELVM vm)
{
	__SQ_GETSTART(2)
	__SQ_GETSAFEPTR(project, Project, typetag_Project)
	__SQ_GETSTRING(alias)
	project->font_cache->DeleteAlias(alias);
	__SQ_GETEND
	__SQ_RETURN
}
SQInteger			ProjectGetFont(HSQUIRRELVM vm)
{
	__SQ_GETSTART(2)
	__SQ_GETSAFEPTR(project, Project, typetag_Project)
	__SQ_GETSTRING(path)
	FontEx *font = project->font_cache->GetAliasedFont(path);
	if	(!font)
		return sq_throwerror(vm, String::Format("Font '%s' not found.", path));
	__SQ_GETEND
	__SQ_RETURNSAFEPTR(font, typetag_Font)
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void		RegisterProjectBinding(HSQUIRRELVM vm)
{
/*#
	Topic: Project
	Type: Project
	Type: ProjectLayer
#*/

/*#
	Section: ProjectGeneral
	Desc: General project functions
#*/
	/*#
		Func: ProjectGetClock
		Proto: Clock:Project
		Desc: Get the project clock object.
	#*/
	sq_register(vm, ProjectGetClock, "ProjectGetClock", _SC(".x"));
	/*#
		Func: ProjectGetScriptInstance
		Proto: Instance:Project
		Desc: Get the project script instance.
	#*/
	sq_register(vm, ProjectGetScriptInstance, "ProjectGetScriptInstance", _SC(".x"));
	/*#
		Func: ProjectEnd
		Proto: void:Project
		Desc: Exit project.
	#*/
	sq_register(vm, ProjectEnd, "ProjectEnd", _SC(".x"));

/*#
	Section: ProjectFontManagement
	Desc: UI Font management functions
#*/
	/*#
		Func: ProjectLoadFont
		Proto: Font:Project, string path
		Desc: Load a TrueType font in the project font cache.
	#*/
	sq_register(vm, ProjectLoadFont, "ProjectLoadFont", _SC(".xs"));
	sq_register(vm, ProjectLoadFont, "ProjectLoadUIFont", _SC(".xs"));
	/*#
		Func: ProjectLoadFontAliased
		Proto: Font:Project, string path, string alias
		Desc: Load a TrueType font under a specific alias.
	#*/
	sq_register(vm, ProjectLoadFontAliased, "ProjectLoadFontAliased", _SC(".xss"));
	sq_register(vm, ProjectLoadFontAliased, "ProjectLoadUIFontAliased", _SC(".xss"));
	/*#
		Func: ProjectDeleteFontAlias
		Proto: void:Project, string alias
		Desc: Delete a font alias from the font cache.
	#*/
	sq_register(vm, ProjectDeleteFontAlias, "ProjectDeleteFontAlias", _SC(".xs"));
	sq_register(vm, ProjectDeleteFontAlias, "ProjectDeleteUIFontAlias", _SC(".xs"));
	/*#
		Func: ProjectGetFont
		Proto: Font:Project, string name
		Desc: Retrieve a font from its name.
	#*/
	sq_register(vm, ProjectGetFont, "ProjectGetFont", _SC(".xs"));
	sq_register(vm, ProjectGetFont, "ProjectGetUIFont", _SC(".xs"));

/*#
	Section: ProjectLayerManagement
	Desc: Layer management functions
#*/
	/*#
		Func: ProjectLayerGetScene
		Proto: ProjectScene:ProjectLayer
		Desc: Return the scene instance a layer is displaying.
	#*/
	sq_register(vm, ProjectLayerGetScene, "ProjectLayerGetScene", _SC(".x"));
	/*#
		Func: ProjectAddLayer
		Proto: ProjectLayer:Project,ProjectScene,float zorder
		Desc: Create a new layer to display a project scene.
		Note: A scene can be added to several layers at once.
	#*/
	sq_register(vm, ProjectAddLayer, "ProjectAddLayer", _SC(".xxn"));
	/*#
		Func: ProjectLayerSetZOrder
		Proto: void:ProjectLayer,float
		Desc: Set layer Z order.
		Note: Smaller Z values are closer to the viewer.
	#*/
	sq_register(vm, ProjectLayerSetZOrder, "ProjectLayerSetZOrder", _SC(".xn"));
	/*#
		Func: ProjectLayerGetZOrder
		Proto: float:ProjectLayer
		Desc: Get layer Z order.
	#*/
	sq_register(vm, ProjectLayerGetZOrder, "ProjectLayerGetZOrder", _SC(".x"));

	/*#
		Func: ProjectSetAll2DLayerOffset
		Proto: void:Project,float x,float y
		Desc: Set the offset of all 2d layer in the current project stack. The offset is specified in the layer reference resolution.
	#*/
	sq_register(vm, ProjectSetAll2DLayerOffset, "ProjectSetAll2DLayerOffset", _SC(".xnn"));

/*#
	Section: ProjectSceneManagement
	Desc: Scene management functions
#*/
	/*#
		Func: ProjectNewScene3D
		Proto: ProjectScene:Project
		Desc: Create a new scene 3D.
		Note: You need to add the newly created scene to a project layer to display it.
		Example:
local project_scene = ProjectNewScene3D(g_project)
ProjectAddLayer(g_project, project_scene, 0.5)		// add the 3d scene to a project layer with Z offset of 0.5
	#*/
	sq_register(vm, ProjectNewScene3D, "ProjectNewScene", _SC(".x"));
	sq_register(vm, ProjectNewScene3D, "ProjectNewScene3D", _SC(".x"));
	/*#
		Func: ProjectNewScene2D
		Proto: ProjectScene:Project
		Desc: Create a new scene 2D.
		Note: You need to add the newly created scene to a project layer to display it.
		Example:
local project_scene = ProjectNewScene2D(g_project)
ProjectAddLayer(g_project, project_scene, 0.5)		// add the 2d scene to a project layer with Z offset of 0.5
	#*/
	sq_register(vm, ProjectNewScene2D, "ProjectNewScene2D", _SC(".x"));

	/*#
		Func: ProjectFindScene
		Proto: ProjectScene:Project,string path
		Desc: Returns an instance of a specific scene in the project, returns an invalid object if no such instance could be found.
	#*/
	sq_register(vm, ProjectFindScene, "ProjectFindScene", _SC(".xs"));
	/*#
		Func: ProjectGetSceneLayerList
		Proto: Array:Project,ProjectScene
		Desc: Return all the project layers displaying a specific scene instance. A scene might be displayed by several different layers (eg. in order to display a split-screen view).
	#*/
	sq_register(vm, ProjectGetSceneLayerList, "ProjectGetSceneLayerList", _SC(".xx"));

	/*#
		Func: ProjectSceneIsActive
		Proto: bool:Project,ProjectScene
		Desc: Return the active state of a project scene.
	#*/
	sq_register(vm, ProjectSceneIsActive, "ProjectSceneIsActive", _SC(".xx"));
	sq_register(vm, ProjectSceneIsActive, "ProjectIsSceneActive", _SC(".xx"));
	/*#
		Func: ProjectSceneActivate
		Proto: void:Project,ProjectScene,bool
		Desc: Activate or deactivate a project scene. When deactivated a scene is not updated or displayed anymore.
	#*/
	sq_register(vm, ProjectSceneActivate, "ProjectSceneActivate", _SC(".xxb"));
	sq_register(vm, ProjectSceneActivate, "ProjectActivateScene", _SC(".xxb"));
	/*#
		Func: ProjectInstantiateScene
		Proto: ProjectScene:Project,string path
		Desc: Instantiate a project scene.
		Note: You need to add the project scene to a layer to display it. This function will detect the type of scene to instantiate, 2d or 3d, from the input file.
		See: ProjectSceneGetType, ProjectDeleteScene
		Example:
local project_scene = ProjectInstantiateScene(g_project, "scene_file.nms")
ProjectAddLayer(g_project, project_scene, 0.5)
	#*/
	sq_register(vm, ProjectInstantiateScene, "ProjectInstantiateScene", _SC(".xs"));
	/*#
		Func: ProjectSceneSetGlobal
		Proto: void:ProjectScene
		Desc: Register scene as the global scene script object (g_scene).
		Note: The project automatically updates g_scene before updating or displaying a scene.
	#*/
	sq_register(vm, ProjectSceneSetGlobal, "ProjectSceneSetGlobal", _SC(".x"));
	/*#
		Func: ProjectDeleteScene
		Proto: void:Project,ProjectScene
		Desc: Delete a project scene.
		Note: All layers displaying this scene will be destroyed as well.
	#*/
	sq_register(vm, ProjectUnloadScene, "ProjectDeleteScene", _SC(".xx"));
	sq_register(vm, ProjectUnloadScene, "ProjectUnloadScene", _SC(".xx"));
	/*#
		Func: ProjectSceneGetType
		Proto: ProjectSceneType:ProjectScene
		Desc: Get a project scene type.
	#*/
	sq_register(vm, ProjectSceneGetType, "ProjectSceneGetType", _SC(".x"));
	/*#
		Func: ProjectSceneGetInstance
		Proto: Scene:ProjectScene
		Desc: Get the scene object of type Scene or UI from a project scene object.
		Example:
local scene = ProjectSceneGetInstace(project_scene)	// this project scene encapsulates a 3d scene
SceneAddLight(scene, "MyLight")
	#*/
	sq_register(vm, ProjectSceneGetInstance, "ProjectSceneGetInstance", _SC(".x"));

	/*#
		Func: ProjectGetFileName
		Proto: String:Project
		Desc: Return the project file name, without the project path.
		See: ProjectGetFilePath
	#*/
	sq_register(vm, ProjectGetFileName, "ProjectGetFileName", _SC(".x"));
	/*#
		Func: ProjectGetFilePath
		Proto: String:Project
		Desc: Return the project path.
		See: ProjectGetFileName
	#*/
	sq_register(vm, ProjectGetFilePath, "ProjectGetFilePath", _SC(".x"));

	/*#
		Enum: ProjectSceneType
		Values: ProjectSceneTypeScene2d,ProjectSceneTypeScene3d
	#*/
	sq_pushstring(vm, "ProjectSceneTypeScene2d", -1); sq_pushinteger(vm, ProjectSceneInstance::Type_Scene2d); sq_newslot(vm, -3, true);
	sq_pushstring(vm, "ProjectSceneTypeScene3d", -1); sq_pushinteger(vm, ProjectSceneInstance::Type_Scene3d); sq_newslot(vm, -3, true);

	sq_pushstring(vm, "NullItem", -1); CObject::Push(vm, NULL, typetag_Item); sq_newslot(vm, -3, true);
}
//------------------------------------------------------------------------------
