// Author: Juan Carlos De Abreu (jcabreur@gmail.com)

#include "banfa_viewer.h"
#include "Renderer/OpenGLRenderer.h"
#include "Base/LogManagement.h"
#include "Base/Memory/MMObject.h"
#include "GUI/window_management.h"
#include "Util/Time/TimeManagement.h"
#include "Scene Parser/SceneFile.h"
#include "Util/TextureManagement.h"
#include "Material/MaterialManagement.h"
#include "Scene/scene_inl.h"

//#include "Media/Sound/sound_management.h"
#include "Media/Sound/soundManager.h"
#include "Media/Sound/sound.h"


#include "Scene Parser/DataStructures/DataKey.h"
#include "Scene Parser/DataStructures/DataRaster.h"

#include "input/device/isotrak/isotrak.h"

#include "Global.h"

#include "../resource.h"

#include "Model/ModelManagement.h"

#include "collision_detection/aabb_tree_collision.h"

#include "tablero.h"
#include "ai.h"
#include "actor.h"


using namespace teg;

//BEGIN_TEG_NAMESPACE();

bool active = TRUE;		// Window active flag set to TRUE by default.

gui::WindowManagement* pWManagement = gui::WindowManagement::GetInstancePtr();


/// Prototype of functions
void init();
void createInterfaz();

void processSpecialKeys(int key_);

SmartPointer<IRenderer> renderer = NULL;
static const std::string className = _T("BanFa Viewer Class");

SmartPointer<TranslateNode> tNode;
SmartPointer<TranslateNode> tNodeActor;
SmartPointer<RotateNode> rNodeActor;
SmartPointer<RotateNode> rXNode;
SmartPointer<RotateNode> rYNode;
SmartPointer<RotateNode> rZNode;
SmartPointer<RotateNode> rPedofiloNode;
SmartPointer<TranslateNode> translateArrow;
SmartPointer<GeometryNode> geometryArrow;
float arrowAnim;

float offsetX = 0.0, offsetZ = 0.0;
int posActualX, posActualY;
//Tablero tablero;
ai::Tablero tab;

int movementDir = 3;

float minMapX, minMapZ;

clock_t last;
clock_t lastForChild;
clock_t appTime;

int mousePosX, mousePosY;
bool mousePressed = false;

void liberarNodos() {
	tNode = NULL;
	rXNode = NULL;
	rYNode = NULL;
	rZNode = NULL;
	rPedofiloNode = NULL;
	tNodeActor = NULL;
	rNodeActor= NULL;
	translateArrow = NULL;
	geometryArrow = NULL;
}

void BuildSceneTree();
void CreateSlide(const char* path);

void killWindow() {
	// Delete the renderer
	renderer = NULL;

	COLLECT_GARBAGE();

	HINSTANCE hInstance = GetModuleHandle(NULL);

	// Are We Able To Unregister Class
	if(!UnregisterClass(className.c_str(), hInstance)) {
		PRINT_LOG(TYPE_ERROR, _T("Shutdown Error: Could Not Unregister Class."));
		hInstance = NULL;	// Set hInstance To NULL
	}
}

// 
bool createWindow(char *title, int width__, int height__, int bits, bool fsFlag) {

	HINSTANCE hInstance = GetModuleHandle(NULL);

    // the handle for the window, filled by a function
    HWND hWnd;

    // this struct holds information for the window class
    WNDCLASSEX wc;

    // clear out the window class for use
    ZeroMemory(&wc, sizeof(WNDCLASSEX));

    // fill in the struct with the needed information
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = (WNDPROC) WindowProc;
	wc.hInstance = hInstance;
	//wc.hIcon			= LoadIcon(NULL, IDI_WINLOGO);			// Load The Default Icon
	wc.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_ICON_APP);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	// wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
	wc.lpszClassName = className.c_str();
	wc.cbSize = sizeof(WNDCLASSEX);
    
    // register the window class
	// Attempt To Register The Window Class
	if (!RegisterClassEx(&wc)) {
		PRINT_LOG(TYPE_ERROR, _T("Error: Failed To Register The Window Class."));
		return FALSE;
	}

	DWORD	dwExStyle = NULL;		/// Seria bueno definirlo
	DWORD	dwStyle;

	// Are We Still In Fullscreen Mode?
	if (FULLSCREEN) {
		//dwExStyle = WS_EX_APPWINDOW;			// Window Extended Style
		dwStyle = WS_EX_TOPMOST | WS_POPUP;						// Windows Style
		ShowCursor(FALSE);						// Hide Mouse Pointer
	}
	else {
		//dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;			// Window Extended Style
		dwStyle = WS_OVERLAPPEDWINDOW;							// Windows Style
	}

	// Realmente no es necesaria esta instruccion
	//	AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);		// Adjust Window To True Requested Size

	// Create the window and use the result as the handle
	if (!(hWnd = CreateWindowEx(dwExStyle,
					className.c_str(),		// Name of the window class
					_T("BanFa Viewer"),		// Title of the window
					dwStyle,				// Window style
					0,						// X-position of the window
					0,						// Y-position of the window
					WIDTH_SCREEN,			// Width of the window
					HEIGHT_SCREEN,			// Height of the window
					NULL,					// We have no parent window, NULL
					NULL,					// We aren't using menus, NULL
					hInstance,				// Application handle
					NULL)))					// Used with multiple windows, NULL
	{
		//KillGLWindow();		// Reset The Display
		PRINT_LOG(TYPE_ERROR, _T("Error: Window Creation Error."));
		return FALSE;
	}

	// 
	bool bOpenR = true;
	if(bOpenR) {
		renderer = new OpenGLRenderer(hWnd, FULLSCREEN);
	}
	else {
		//renderer = new D3DRenderer(hWnd, FULLSCREEN);
	}

	// Display the window on the screen
	ShowWindow(hWnd, SW_SHOW);		// Show the window

/*		SetForegroundWindow(hWnd);						// Slightly Higher Priority
		SetFocus(hWnd);									// Sets Keyboard Focus To The Window
		ReSizeGLScene(width, height);					// Set Up Our Perspective GL Screen

		if (!InitGL())									// Initialize Our Newly Created GL Window
		{
			KillGLWindow();								// Reset The Display
			PRINT_LOG(_T("Error: Initialization Failed.\n"));
			return FALSE;								// Return FALSE
		}
*/
	// 
	renderer->resize(WIDTH_SCREEN, HEIGHT_SCREEN);

	return true;
}

/**
 * The entry point for a windows program.
 *
 * Params:
 *   hInstance: Instance.
 *   hPrevInstance: Previus instance.
 *   lpCmdLine: Command line parameters.
 *   nCmdShow: window show state.
 */
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
	// Create our window
	if (!createWindow("", 640, 480, 32, true)) {
		return 0;		// Quit if window was not created
	}

	// Init the application
	init();

	// Struct to hold Window event messages
	MSG msg;

	// Enter the infinite message loop
	while(AppWindow::GetInstance().isRunning) {
		// Check to see if any messages are waiting in the queue
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
			// If the message is WM_QUIT, exit the while loop
			if (msg.message == WM_QUIT) break;

			// Translate keystroke messages into the right format
			TranslateMessage(&msg);

			// Send the message to the WindowProc function
			DispatchMessage(&msg);
		}

		// Was ESC pressed?
		if (KEY[VK_ESCAPE])	break;

		// Is F1 being pressed?
		/*if (KEY[VK_F1])	{
			// Make the key false
			KEY[VK_F1] = FALSE;
			
			// Kill the current window
			killWindow();
			
			// Toggle Fullscreen / Windowed Mode
			FULLSCREEN =! FULLSCREEN;

			// Recreate a new window
			if (!createWindow("", 640, 480, 32, true)) {
				return 0;		// Quit if window was not created
			}
		}
		*/

		// Check if is the language must be restarted.
		if (SceneFileManagement::GetInstance().reset()) {
			// Free all the resources related to the actual state.
			Scene::GetInstance().Release();
			TimeManagement::GetInstance().release();
			SceneFileManagement::GetInstance().release();
			MaterialManagement::GetInstance().release();
			DataKey::GetInstance().release();
			DataRaster::GetInstance().Release();

			// Initialize the language state.
			Scene::GetInstance().Load();
		
			SceneFileManagement::GetInstance().set_reset(false);
		}

		// Program Active?
		if (active)	{
			// Capture the input ...
			/// GET_INPUT();

			// Update the timers
			UPDATE_TIMERS();

			// Draw the scene
			renderer->render();	

			DataKey::GetInstance().update();

			if (AppWindow::GetInstance().gameState == AppWindow::GAME_RUN) {

				const clock_t tmp = clock();
				if (tmp - appTime > 300000) {
					AppWindow::GetInstance().gameState = AppWindow::LOOSE;
					CreateSlide("./Data/Models/slide.obj");
				}

				if(tmp - last > 0) {
					//AI movement
					ai::ActorManagement::GetInstance().UpdateMoves(tab);

					/*int actorPosX = ai::ActorManagement::GetInstance().workers[0].position.x;
					int actorPosY = ai::ActorManagement::GetInstance().workers[0].position.y;

					tNodeActor->set_x(minMapX + offsetX*actorPosX);
					tNodeActor->set_z(minMapZ + offsetZ*actorPosY);

					int dir = ai::ActorManagement::GetInstance().workers[0].dir;
					if(dir == 1) rNodeActor->set_angle(90);
					else if(dir == 2) rNodeActor->set_angle(-90);
					else if(dir == 4) rNodeActor->set_angle(0);
					else if(dir == 8) rNodeActor->set_angle(180);*/

					last = tmp;
				}

				translateArrow->set_y((sin(arrowAnim += 0.1) + 1) / 20);
				if (arrowAnim >= 3.14) arrowAnim = 0; 

				if (tmp - lastForChild > 50) {
					
					ai::ActorManagement::GetInstance().UpdateChild(tab);
					lastForChild = tmp;
				}

				if (ai::ActorManagement::GetInstance().theChild.withThief) geometryArrow->set_draw(false);
				else geometryArrow->set_draw(true);
				
				if (ai::ActorManagement::GetInstance().capture) {
					AppWindow::GetInstance().gameState = AppWindow::LOOSE;
					CreateSlide("./Data/Models/slide.obj");
				}

				if (ai::ActorManagement::GetInstance().finish) {
					AppWindow::GetInstance().gameState = AppWindow::WIN;
					CreateSlide("./Data/Models/slide.obj");
				}
			}
			
		}
	}

	// Erase all the information in the SceneFile
	Scene::GetInstance().Release();

	TimeManagement::GetInstance().release();	// Clear all the timers
	SceneFileManagement::GetInstance().release();			// Erase all the information in the SceneFile

	// Release all the materials in the memory.
	MaterialManagement::GetInstance().release();

	DataKey::GetInstance().release(); // Clear all the functions related to keys.
	DataRaster::GetInstance().Release();

	Isotrak::GetInstance().Disconnect();

//	SoundManagement::closeManager();

	ai::ActorManagement::GetInstance().release();

	//soundmanager->Destroy();

	liberarNodos();

	// Delete the renderer
	killWindow();

	COLLECT_REMAINING_OBJECTS();

	

	PRINT_LOG(TYPE_DEBUG, "Termino Bien...");

	SHOW_LOG();

    // Return this part of the WM_QUIT message to Windows.
    return msg.wParam;
}

/**
 * Main message handler for the app.
 *
 * Params:
 *   hWnd: Handle for this window
 *   message: Message for this window
 *   wParam: Additional message information
 *   lParam: Additional message information
 */
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
	// Sort through and find what code to run for the message given
	switch(message) {		
		// Watch for window activate message
		case WM_ACTIVATE:
			{
				// Check minimization state
				if (!HIWORD(wParam)) active = true;	// Program is active
				else active = false;				// Program is no longer active
				return 0;							// Return to the message loop
			}

		// Intercept system commands
		case WM_SYSCOMMAND:
			{
				// Check system calls
				switch (wParam)	{
					case SC_SCREENSAVE:		// Screensaver trying to start?
					case SC_MONITORPOWER:	// Monitor trying to enter powersave?
					return 0;				// Prevent from Happening
				}
				break;						// Exit
			}

		// Did we receive a close message?
		case WM_CLOSE:
			{
				// Close the application entirely
				PostQuitMessage(0);		// Send a quit message
				return 0;				// Return to the message loop
			}
		
		// This message is read when the window is closed
        case WM_DESTROY:
            {
                // Close the application entirely
                PostQuitMessage(0);		// Send a quit message
                return 0;				// Return to the message loop
            } break;

		// Is a key being held down?
		case WM_KEYDOWN:
			{
				if (AppWindow::GetInstance().gameState == AppWindow::GAME_RUN) {
				if (wParam == VK_F2)
                    gui::WindowManagement::GetInstance().set_is_console_enable(!gui::WindowManagement::GetInstance().is_console_enable());
                else if(wParam == VK_LEFT) {
                    movementDir = (movementDir+1)%4;
                    rPedofiloNode->set_angle(rPedofiloNode->angle() + 90);
                }
                else if(wParam == VK_RIGHT) {
                    movementDir = movementDir == 0 ? 3 : movementDir-1;
                    rPedofiloNode->set_angle(rPedofiloNode->angle() - 90);
                }
                else if(wParam == VK_UP) {
                    if(movementDir == 0) {
                        if(tab.get(posActualX+1, posActualY) == ai::Tablero::EMPTY) {
                            tNode->set_x(tNode->x() + offsetX);
                            tab.set(posActualX, posActualY, ai::Tablero::EMPTY);
                            ++posActualX;
                            tab.set(posActualX, posActualY, ai::Tablero::THIEF);
                            ai::ActorManagement::GetInstance().theThief.position = math::Vec2<int>(posActualX, posActualY);
                        }
                       
                    } else if(movementDir == 1) {
                        if(tab.get(posActualX, posActualY-1) == ai::Tablero::EMPTY) {
                            tNode->set_z(tNode->z() - offsetZ);
                            tab.set(posActualX, posActualY, ai::Tablero::EMPTY);
                            --posActualY;
                            tab.set(posActualX, posActualY, ai::Tablero::THIEF);
                            ai::ActorManagement::GetInstance().theThief.position = math::Vec2<int>(posActualX, posActualY);
                        }
                       
                    } else if(movementDir == 2) {
                        if(tab.get(posActualX-1, posActualY) == ai::Tablero::EMPTY) {
                            tNode->set_x(tNode->x() - offsetX);
                            tab.set(posActualX, posActualY, ai::Tablero::EMPTY);
                            --posActualX;
                            tab.set(posActualX, posActualY, ai::Tablero::THIEF);
                            ai::ActorManagement::GetInstance().theThief.position = math::Vec2<int>(posActualX, posActualY);
                        }
                    } else if(movementDir == 3) {
                        if(tab.get(posActualX, posActualY+1) == ai::Tablero::EMPTY) {
                            tNode->set_z(tNode->z() + offsetZ);
                            tab.set(posActualX, posActualY, ai::Tablero::EMPTY);
                            ++posActualY;
                            tab.set(posActualX, posActualY, ai::Tablero::THIEF);
                            ai::ActorManagement::GetInstance().theThief.position = math::Vec2<int>(posActualX, posActualY);
                        }
                    }

                   
                    //rPedofiloNode->set_angle(180);
                }
                else if(wParam == VK_DOWN) {
                    movementDir = (movementDir+2)%4;
                    rPedofiloNode->set_angle(rPedofiloNode->angle() + 180);
                }
                else if(wParam == VK_F3)
                    tNode->set_y(tNode->y() + 0.1);
                else if(wParam == VK_F4) {
                    tNode->set_y(tNode->y() - 0.1);
                    //PRINT_LOG(TYPE_WARNING, _T("val = %f"), tNode->y());
                }
				}
                processSpecialKeys(wParam);
                return 0; 		
			}

		// Has a key been released?
		case WM_KEYUP:
			{
				if (wParam != VK_CAPITAL) 
					KEY[wParam] = FALSE;	// If so, mark it as FALSE
				return 0;				// Return to the message loop
			}

		// Resize the window?
		case WM_SIZE:								
			{
				// TODO: definir dos width and height, uno es el tamaņo de la ventana y el otro el del render...

				WIDTH_SCREEN = LOWORD(lParam);
				HEIGHT_SCREEN = HIWORD(lParam);
				return 0;				// Return to the message loop
			}

		// Is the mouse being move?
		case WM_MOUSEMOVE:
			{
				int newX = LOWORD(lParam);
				int newY = HIWORD(lParam);

				if (AppWindow::GetInstance().gameState == AppWindow::GAME_RUN) {
				if(mousePressed) {
					//rXNode->set_angle(rXNode->angle() + (newY - mousePosY));
					rYNode->set_angle(rYNode->angle() + (newX - mousePosX));
				}
				}
								
				mousePosX = newX;
				mousePosY = newY;

				MOUSE_X = LOWORD(lParam);
				MOUSE_Y = HIWORD(lParam);
				//Mouse::GetInstance().isLeftButtonPressed = (LOWORD(wParam) & MK_LBUTTON) ? true : false;
				
				if(IS_MOUSE_DRAG) {
					MOUSE_DRAG_WINDOW->set_x(MOUSE_X - MOUSE_DRAG_X);
					MOUSE_DRAG_WINDOW->set_y(HEIGHT_SCREEN - MOUSE_Y - MOUSE_DRAG_Y);
				}
				return 0;				// Return to the message loop
			}

		// Has the left button mouse been released?
		case WM_LBUTTONUP:
			{
				Mouse::GetInstance().isLeftButtonPressed = false;
				mousePressed = false;
				//if(pWManagement->buttonPressed != NULL) {
				//	pWManagement->buttonPressed->isPressed = false;
				//}
				pWManagement->onMouseUp();

				return 0;				// Return to the message loop
			}

		// Has the right button mouse been released?
		case WM_RBUTTONUP:
			{
				Mouse::GetInstance().isRightButtonPressed = false;
				
				return 0;				// Return to the message loop
			}

		// Is the left button mouse being held down?
		case WM_LBUTTONDOWN:
			{
				if (AppWindow::GetInstance().gameState == AppWindow::START_SLIDE1) {
					AppWindow::GetInstance().gameState++;
					CreateSlide("./Data/Models/slide2.obj");
				} else if (AppWindow::GetInstance().gameState == AppWindow::START_SLIDE2) {
					AppWindow::GetInstance().gameState++;
					CreateSlide("./Data/Models/slide3.obj");	
				} else if (AppWindow::GetInstance().gameState == AppWindow::START_SLIDE3) {
					AppWindow::GetInstance().gameState++;
					CreateSlide("./Data/Models/slide4.obj");
				} else if (AppWindow::GetInstance().gameState == AppWindow::START_SLIDE4) {
					AppWindow::GetInstance().gameState = AppWindow::GAME_RUN;
					BuildSceneTree();
				} 

				bool clickOverWindow = false;

				Mouse::GetInstance().initX = LOWORD(lParam);
				Mouse::GetInstance().initY = HIWORD(lParam);

				for(int i = pWManagement->windows().size() - 1; i >= 0 && !clickOverWindow; --i) {
					clickOverWindow = pWManagement->onMouseDown(&pWManagement->windows()[i]);
				}
				
				if (!clickOverWindow) Mouse::GetInstance().isLeftButtonPressed = true;

				mousePressed = true;
 

				return 0;				// Return to the message loop
			}

		// Is the right button mouse being held down?
		case WM_RBUTTONDOWN:
			{
				Mouse::GetInstance().initX = LOWORD(lParam);
				Mouse::GetInstance().initY = HIWORD(lParam);
				Mouse::GetInstance().isRightButtonPressed = true;
				return 0;				// Return to the message loop
			}
    }

    // Handle any messages the switch statement didn't
    return DefWindowProc(hWnd, message, wParam, lParam);
}

void CreateSlide(const char* path) {
	std::vector<SmartPointer<ISceneNode> > vecSlide;
	const SmartPointer<IModel>& modelSlide = LOAD_MODEL(path);
    SmartPointer<GeometryNode> geometrySlide = new GeometryNode(modelSlide, true, true);
	SmartPointer<TranslateNode> translateSlide = new TranslateNode(0, 0, -2);
	SmartPointer<ScaleNode> scaleSlide = new ScaleNode(3, 3, 3);
	vecSlide.push_back((ISceneNode*)translateSlide);
	vecSlide.push_back((ISceneNode*)scaleSlide);
	vecSlide.push_back((ISceneNode*)geometrySlide);
	SmartPointer<GroupNode> groupSlide = new GroupNode(vecSlide);
	Scene::GetInstance().set_root((ISceneNode*)groupSlide);
}

void BuildSceneTree() {
	const SmartPointer<IModel>& model1 = LOAD_MODEL("./Data/Models/escenario.obj");

	//
	minMapX = model1->vMin.x;
	minMapZ = model1->vMin.z;

	//Se mapea el tablero al espacio
	float sizeX = abs(model1->vMin.x - model1->vMax.x);
	float sizeZ = abs(model1->vMin.z - model1->vMax.z);
	offsetX = sizeX/(float)tab.numberOfColumms;
	offsetZ = sizeZ/(float)tab.numberOfRows;

	const SmartPointer<IModel>& model2 = LOAD_MODEL("./Data/Models/nurse.obj");

	SmartPointer<GeometryNode> geometry1 = new GeometryNode(model1, true, true);
	SmartPointer<GeometryNode> geometry2 = new GeometryNode(model2, true, true);
	SmartPointer<GeometryNode> geometry3 = new GeometryNode(model2, true, true);

	//Armar arbol de escena
	

	//PARTES DE ESCENA
	std::vector<SmartPointer<ISceneNode> > vec;
	tNode = new TranslateNode(minMapX + offsetX*posActualX, 0.0, minMapZ + offsetZ*posActualY);
	SmartPointer<TranslateNode> tWorld = new TranslateNode(0, 0, 1);
	rXNode = new RotateNode(24, 1, 0, 0);
	rYNode = new RotateNode(39, 0, 1, 0);
	rZNode = new RotateNode(0, 0, 0, 1);

	// PARTES MAPA
	std::vector<SmartPointer<ISceneNode> > vecMapa;
	SmartPointer<ScaleNode> sMapNode = new ScaleNode(1.0, 0.5, 1.0);
	vecMapa.push_back((ISceneNode*) sMapNode);
	vecMapa.push_back((ISceneNode*) geometry1);
	SmartPointer<GroupNode> groupMapa = new GroupNode(vecMapa);

	//PARTES LUZ
	std::vector<SmartPointer<ISceneNode> > vecLuz;
	SmartPointer<TranslateNode> tLightNode = new TranslateNode(5, 5, 5);
	SmartPointer<LightNode> lightNode = new LightNode();
	vecLuz.push_back((ISceneNode*) tLightNode);
	vecLuz.push_back((ISceneNode*) lightNode);
	SmartPointer<GroupNode> grupoLuz = new GroupNode(vecLuz);

	// PARTES THIEF
	const SmartPointer<IModel>& modelThief = LOAD_MODEL("./Data/Models/vieja.obj");
	SmartPointer<GeometryNode> geometryThief = new GeometryNode(modelThief, true, true);
	SmartPointer<ScaleNode> sNode = new ScaleNode(0.08, 0.08, 0.08);
	rPedofiloNode = new RotateNode(0, 0, 1, 0);
	std::vector<SmartPointer<ISceneNode> > vecThief;
	vecThief.push_back((ISceneNode*)tNode);
	vecThief.push_back((ISceneNode*)sNode);
	vecThief.push_back((ISceneNode*) rPedofiloNode);
	vecThief.push_back((ISceneNode*)geometryThief);
	SmartPointer<GroupNode> grupoThief = new GroupNode(vecThief);


	// Parte Flecha del child..
	const SmartPointer<IModel>& modelArrow = LOAD_MODEL("./Data/Models/arrow.obj");
    geometryArrow = new GeometryNode(modelArrow, true, true);
	SmartPointer<ScaleNode> scaleArrow = new ScaleNode(0.02, 0.05, 0.02);
	SmartPointer<RotateNode> rotateArrow = new RotateNode(180, 1, 0, 0);
	translateArrow = new TranslateNode(0, 0.1, 0);
	std::vector<SmartPointer<ISceneNode> > vecArrow;
	vecArrow.push_back((ISceneNode*) translateArrow);
	vecArrow.push_back((ISceneNode*) scaleArrow);
	vecArrow.push_back((ISceneNode*) rotateArrow);
	vecArrow.push_back((ISceneNode*) geometryArrow);
	SmartPointer<GroupNode> groupArrow = new GroupNode(vecArrow);
	arrowAnim = 0;


	// PARTED CHILD
	const SmartPointer<IModel>& modelChild = LOAD_MODEL("./Data/Models/nino.obj");
	std::vector<SmartPointer<ISceneNode> > vecChild;
	SmartPointer<GeometryNode> geometryChild = new GeometryNode(modelChild, true, true);
	SmartPointer<ScaleNode> scaleChild = new ScaleNode(0.03, 0.03, 0.03);
	vecChild.push_back((ISceneNode*) ai::ActorManagement::GetInstance().childTranslate);
	vecChild.push_back((ISceneNode*) groupArrow);
	vecChild.push_back((ISceneNode*) scaleChild);
	vecChild.push_back((ISceneNode*) ai::ActorManagement::GetInstance().childRotate);
	vecChild.push_back((ISceneNode*) geometryChild);
	SmartPointer<GroupNode> groupChild = new GroupNode(vecChild);
	

	// Background
	std::vector<SmartPointer<ISceneNode> > vecBackground;
	const SmartPointer<IModel>& modelBackground = LOAD_MODEL("./Data/Models/background.obj");
    SmartPointer<GeometryNode> geometryBackground = new GeometryNode(modelBackground, true, true);
	SmartPointer<TranslateNode> translateBackground = new TranslateNode(0, 0, 0.4);
	SmartPointer<ScaleNode> scaleBackground = new ScaleNode(3, 3, 3);
	vecBackground.push_back((ISceneNode*)translateBackground);
	vecBackground.push_back((ISceneNode*)scaleBackground);
	vecBackground.push_back((ISceneNode*)geometryBackground);
	SmartPointer<GroupNode> groupBackground = new GroupNode(vecBackground);

	vec.push_back((ISceneNode*)groupBackground);

	//Escena
	vec.push_back((ISceneNode*)grupoLuz);
	vec.push_back((ISceneNode*)tWorld);
	vec.push_back((ISceneNode*)rXNode);
	vec.push_back((ISceneNode*)rYNode);
	vec.push_back((ISceneNode*)rZNode);


	vec.push_back((ISceneNode*) groupMapa);
	vec.push_back((ISceneNode*) groupChild);
	vec.push_back((ISceneNode*) grupoThief);


	for(int i=0; i<ai::ActorManagement::GetInstance().workers.size(); ++i) {
		SmartPointer<GeometryNode> geometryWorker = new GeometryNode(model2, true, true);
		SmartPointer<ScaleNode> scaleWorker = new ScaleNode(0.08, 0.08, 0.08);

		std::vector<SmartPointer<ISceneNode> > vecWorker;
		vecWorker.push_back((ISceneNode*) ai::ActorManagement::GetInstance().workerTranslate[i]);
		vecWorker.push_back((ISceneNode*) scaleWorker);
		vecWorker.push_back((ISceneNode*) ai::ActorManagement::GetInstance().workerRotate[i]);
		vecWorker.push_back((ISceneNode*) geometryWorker);

		SmartPointer<GroupNode> groupWorker = new GroupNode(vecWorker);
		vec.push_back((ISceneNode*) groupWorker);
	}
	SmartPointer<GroupNode> grupo = new GroupNode(vec);
	Scene::GetInstance().set_root((ISceneNode*)grupo);
}

/**
 * Do the basic configuration for the application that include load the
 * objects, etc...
 */
void init() {
	// The texture that define first is the default when can't load a texture
	// Load a texture to know when a texture don't load
	LOAD_TEXTURE("./Data/Textures/nonTexture.jpg");

	// Load the models and other information of the scene
	LOAD_SCENE();

	/// Test: create the interfaz
	createInterfaz();
	pWManagement->loadConfig();

	// Colocar un sonido de prueba..
	//SoundManagement::loadStaticWaveFile("./Data/sounds/Musica/ghost6.wav", "prueba");
	//SoundManagement::loadStaticWaveFile("./Data/sounds/Efectos/Bebe.wav", "bebe");
	//SoundManagement::playSoundLoop("prueba");
	//SoundManagement::setListenerAt(0, 0, -1, 0, 0, 0);

	SoundManager& soundmanager = SoundManager::instance();
	soundmanager.Create();

	Sound *sound = soundmanager.GetSound("./Data/sounds/Musica/ghost6.wav");
	//Sound *soundBebe = soundmanager.GetSound("./Data/sounds/Efectos/babyhappy_01.wav");


	soundmanager.SetListenerPosition(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f);
	sound->SetPosition(3.0f, 0.0f, -30.0f);
	//soundBebe->SetPosition(3.0f, 0.0f, -30.0f);

	sound->Play(false, true);

	//soundBebe->Play(false, true);


	//SoundManagement::playSound("prueba", true);
	
	gui::WindowManagement::GetInstance().set_is_console_enable(false);

	posActualX = 120;
	posActualY = 33;

	//Cargar tablero
	tab.loadMap("tableroConfig2.txt");
	ai::ActorManagement::GetInstance().InitializeWorkers(tab);

	//Se carga el mapa
	AppWindow::GetInstance().gameState = AppWindow::START_SLIDE1;

	CreateSlide("./Data/Models/slide1.obj");

	last = lastForChild = appTime =  clock();
}

/**
 *  Create the windows to manage the application.
 */
void createInterfaz() {
	// Window for test the frustumCulling

	// Create the windows.
	gui::Window wCull(0, 80, 280, 80, _T("FrustumCulling test"));
	gui::Window wCollision(0, 80, 200, 80, _T("CollisionDetection test"));

	// Add some text.
	wCull.addText(12, 35, _T("Number of objects inside of the frustum"));
	wCull.addText(250, 35, _T(" "));
	wCollision.addText(12, 35, _T("No collision detected!"));

	wCull.set_is_visible(false);
	wCollision.set_is_visible(false);

	// Add the window to the windwow management
	pWManagement->addWindow(wCull);
	pWManagement->addWindow(wCollision);

}

/*
void ff() {}

void createInterfaz() {
	// create de main Window
	GUI::Window wMain(300, 260, 300, 250, _T("prueba"));

	// Add some buttons
	wMain.addButton(185, 60, 75, 25, _T("Setup"));
	wMain.addButton(185, 90, 75, 25, _T("Exit"));

	// Add a panel
	wMain.addPanel(30, 50, 130, 60);             // create a panel on the window
	//wMain.addPanel(5, 26, 80, 198);             // create a panel on the window

	// Add some text
	wMain.addText(37, 55, _T("Sample app to show"));
	wMain.addText(37, 70, _T("how to use the "));
	wMain.addText(37, 85, _T("windows class."));

	// Add other function
	wMain.addPanel(30, 130, 230, 70);             // create a panel on the window
	wMain.addText(40, 140, _T("Adjust window Alpha blending level."));
	wMain.addButton(60, 165, 75, 25, _T("Up"));
	wMain.addButton(155, 165, 75, 25, _T("Down"));

///// Test for the functors!!!
	wMain.button[0].pFunc = newFunctor0(ff);
	wMain.button[1].pFunc = newFunctor0(ff);
	wMain.button[2].pFunc = newFunctor0(ff);
	wMain.button[3].pFunc = newFunctor0(ff);

	// Add the window to the windwow management
	pWManagement->addWindow(wMain);
	
	///
//	Scene::GetInstance().prueba();
}	
*/

void processSpecialKeys(int key_) {
  if (gui::WindowManagement::GetInstance().is_console_enable())
    gui::WindowManagement::GetInstance().console().process(key_);
  else
    KEY[key_] = TRUE;		// If so, mark it as TRUE
}

//END_TEG_NAMESPACE();
