/// 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.

/// @file Runner.h
/// This source file is part of CUDA Ray Casting test.
/// The file holds the CUDARayCasting class interface.
/// @author Ruben Penalva (ruben.penalva@rpenalva.com)
#ifndef _RUNNER_H_
#define _RUNNER_H_

#include "IRunner.h"
#include "IMenuListener.h"
#include "IMouseListener.h"
#include "MenuEntry.h"

#include "Render.h"
#include "Logic.h"

namespace CUDARayCasting
{

/// @brief It acts as a controller between render, logic and 
/// user interaction. It's executed by GlutWrapper::Window 
/// through GlutWrapper::IRunner interface.
/// Also the right mouse menus are defined through 
/// GlutWrapper::IMenuListener (GetMenuEntries method)
class Runner :
	public GlutWrapper::IRunner, public GlutWrapper::IMenuListener, public GlutWrapper::IMouseListener
{
public:
	/// Constructor
	Runner(int width, int height);

	/// Destructor
	~Runner(void);

	/// @brief Creates opengl context and initialize 
	/// some opengl states.
	/// @see GlutWrapper::IRunner
	void InitializeOpengl(void);

	/// @brief It runs a step of the test. It renders
	/// the string points, segments or triangles (if
	/// they are enabled).
	/// @see GlutWrapper::IRunner
	void Run(float elapsedTime);

	/// @brief It configs opengl with the new render
	/// window width and height
	/// @param width new render window width
	/// @param height new render window height
	/// @see GlutWrapper::IRunner
	void Reshape(int width, int height);

	/// @brief It process the events sent from
	/// right button mouse menu. Depending on the event
	/// it calls logic methods.
	/// @param option the menu option
	/// @see GlutWrapper::IMenuListener
	void ProcessMenuEvents(int option);

	/// @brief It processes the mouse events
	/// @param mouseState state of the mouse
	void ProcessMouse(const GlutWrapper::MouseState& mouseState);

	/// @brief It gets the entries of the right button 
	/// mouse menu.
	/// @return entries of the right button mouse menu.
	/// @see GlutWrapper::IMenuListener
	const std::vector<GlutWrapper::MenuEntry>& GetMenuEntries(void) const;

private:
	static const Vector3 m_fontColor;

	/// Entries of the right mouse button menu
	std::vector<GlutWrapper::MenuEntry> m_entries;

	/// 2d render of the test
	Render m_render;

	/// Logic of the test
	Logic m_logic;

	int m_width;
	
	int m_height;

	float m_lastElapsedTime;

	/// @note hide copy constructor from interface user
	Runner(const Runner&);

	/// @note hide assignment operator from interface user
	Runner& operator=(const Runner&);

	/// @brief Renders one frame of the test
	void Render(float elapsedTime);

	void Update(float elapsedTime);

	void DisplayMetrics(float elapsedTime);
};

}
#endif