/// Copyright (c) 2010 Ruben Penalva. All rights reserved.
/// Redistribution and use in source and binary forms, with or without modification, 
/// are permitted provided that the following conditions are met:
///    1. Redistributions of source code must retain the above copyright notice, this 
///    list of conditions and the following disclaimer.
///    2. Redistributions in binary form must reproduce the above copyright notice,
///    this list of conditions and the following disclaimer in the documentation and/or
///    other materials provided with the distribution.
///    3. The name of the author may not be used to endorse or promote products derived
///    from this software without specific prior written permission.
///
/// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
/// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
/// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 
/// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 
/// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
/// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
/// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
/// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "Application.h"

#include <QT\QApplication.h>

#include <boost/utility.hpp>

#include "ISubsystemsAllocator.h"
#include "Window.h"
#include "Thread.h"
#include "AppWindowListener.h"
#include "Logic.h"
#include "Render.h"
#include "SettingsTab.hxx"
#include <boost\thread\barrier.hpp>

using namespace TestFrameWork;

Application::Application(int argc, char** argv, 
						 const std::wstring& windowTitle,
						 const TestFrameWork::ISubsystemsAllocator* subsystemsAllocator)
																								
{
	QApplication qtApplication(argc, argv);

	/// Scene W
	/// SceneBuffer R
	ScenePtr scene(subsystemsAllocator->AllocateScene());
	ScenePtr sceneBuffer(subsystemsAllocator->AllocateScene());

	ILogicCallablePtr logicCallable(subsystemsAllocator->AllocateLogic(scene));
	LogicPtr logic(new Logic(logicCallable, scene, sceneBuffer));

	ITabVector tabs(subsystemsAllocator->AllocateSettingsTabs(logic->GetEventQueue()));
	AppWindowListener windowListener(this);
	Window window(windowTitle, tabs, &windowListener, logic->GetEventQueue());

	IRenderCallablePtr renderCallable(subsystemsAllocator->AllocateRender(sceneBuffer, window.GetRenderCanvasContext(), 
																		  window.GetWidth(), window.GetHeight()));
	RenderPtr render(new Render(renderCallable, sceneBuffer));

	boost::barrier preSetupBarrier(2);
	boost::barrier postSetupBarrier(2);
	m_renderThread.reset(new Thread(render, preSetupBarrier, postSetupBarrier));
	m_logicThread.reset(new Thread(logic, preSetupBarrier, postSetupBarrier));

	ITabVector::iterator it = tabs.begin();
	ITabVector::iterator itEnd = tabs.end();
	while (it != itEnd)
	{
		(*it)->LoadDefaultSceneParameters(scene);

		++it;
	}
	scene.reset();
	sceneBuffer.reset();
	logicCallable.reset();
	logic.reset();
	tabs.clear();
	renderCallable.reset();
	render.reset();

	// Run
	qtApplication.exec();
}

Application::~Application(void)
{
}
