/// Copyright (c) 2009 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.cpp
/// This source file is part of Gpu Quadratic Curve Render test.
/// The file holds the Runner class implementation.
/// @author Ruben Penalva (ruben.penalva@rpenalva.com)
#include "Runner.h"

using namespace GpuQuadraticCurveRender;

Runner::Runner(void)	:	m_selectedPointIndex(-1)
{
	m_entries.push_back(GlutWrapper::MenuEntry("ShowPoints", ShowPoints));
	m_entries.push_back(GlutWrapper::MenuEntry("ShowLines", ShowLines));
	m_entries.push_back(GlutWrapper::MenuEntry("ShowTriangles", ShowTriangles));
}

Runner::~Runner(void)
{
}
	
void Runner::InitializeOpengl(int width, int height)
{
	m_render.Initialize(width, height);
}

void Runner::Run(void)
{
	Render();
}

void Runner::Reshape(int width, int height)
{
	m_render.Reshape(width, height);
}

void Runner::ProcessMenuEvents(int option)
{
	switch (option)
	{
		case ShowPoints:
			m_logic.EnablePoints();
			break;

		case ShowLines:
			m_logic.EnableLines();
			break;

		case ShowTriangles : 
			m_logic.EnableTriangles();
			break;
	}
}

void Runner::ProcessMouse(const GlutWrapper::MouseState& mouseState)
{
	if (mouseState.m_buttonState == GlutWrapper::Up ||
		mouseState.m_button != GlutWrapper::Left)
	{
		m_selectedPointIndex = -1;

		return;
	}

	double x, y, z;
	m_render.UnProjectScreenPoint(Point(mouseState.m_x, mouseState.m_y), x, y, z);
	Point unProjectedMousePoint(x, y);

	if (m_selectedPointIndex == -1)
	{
		float pointSize = m_render.GetPointSize();

		int pointIndex = 0;
		if (m_logic.AreQuadraticControlPointsIntersected(unProjectedMousePoint, pointIndex, pointSize))
		{
			m_logic.SetQuadraticControlPoint(pointIndex, unProjectedMousePoint);
			m_selectedPointIndex = pointIndex;
		}
	}
	else
	{
		m_logic.SetQuadraticControlPoint(m_selectedPointIndex, unProjectedMousePoint);
	}
}

const std::vector<GlutWrapper::MenuEntry>& Runner::GetMenuEntries(void) const
{
	return m_entries;
}

void Runner::Render(void)
{
	m_render.BeginFrame();
	
	m_render.DrawQuadraticSpline(m_logic.GetQuadraticControlPoints());

	if (m_logic.AreLinesEnabled())
	{
		m_render.SetMaterial(0.0f, 1.0f, 0.0f);
		m_render.DrawLines(m_logic.GetQuadraticLines());
	}

	if (m_logic.AreTrianglesEnabled())
	{
		m_render.SetMaterial(0.0f, 0.0f, 1.0f);
		m_render.DrawTriangles(m_logic.GetQuadraticControlPoints(), 
							   m_logic.GetQuadraticIndices());
	}

	if (m_logic.ArePointsEnabled())
	{
		m_render.SetMaterial(1.0f, 0.0f, 0.0f);
		m_render.DrawPoints(m_logic.GetQuadraticControlPoints());
	}

	m_render.EndFrame();
}