#pragma once

#include "volumeshop.h"

#include "Environment.h"
#include "Volume.h"
#include "Renderer.h"
#include "Vector.h"
#include "Quaternion.h"
#include "Matrix.h"
#include "Color.h"

class RendererBox : public Renderer
{
public:

	RendererBox(Environment & envEnvironment) : m_envEnvironment(envEnvironment)
	{
	};

	virtual ~RendererBox()
	{
	};

	Environment & GetEnvironment()
	{
		return m_envEnvironment;
	};

	virtual void idle()
	{
	};

	virtual void underlay()
	{
	};

	virtual void display()
	{
		glPushAttrib(GL_ALL_ATTRIB_BITS);

		glMatrixMode(GL_PROJECTION);
		glPushMatrix();
		glMultMatrixf(GetEnvironment().GetProjectionTransformation().Get());
		
		glMatrixMode(GL_MODELVIEW);
		glPushMatrix();
		glMultMatrixf(GetEnvironment().GetViewingTransformation().Get());

		glDepthMask(GL_TRUE);
		glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
		glEnable(GL_DEPTH_TEST);
		glDepthFunc(GL_LESS);

		glPushMatrix();
		glMultMatrixf(GetEnvironment().GetDataTransformation().Get());
		Volume<DataVoxel>::Octree::Iterator iterDataVolume(GetEnvironment().GetDataVolume().GetOctree());
		displayBounds((*iterDataVolume).GetBounds().GetTranslated((*iterDataVolume).GetPosition()));
		glPopMatrix();

		glPushMatrix();
		glMultMatrixf(GetEnvironment().GetSelectionTransformation().Get());		
		Volume<SelectionVoxel>::Octree::Iterator iterSelectionVolume(GetEnvironment().GetSelectionVolume().GetOctree());
		displayBounds((*iterSelectionVolume).GetBounds().GetTranslated((*iterSelectionVolume).GetPosition()));
		glPopMatrix();

		glMatrixMode(GL_MODELVIEW);
		glPopMatrix();

		glMatrixMode(GL_PROJECTION);
		glPopMatrix();

		glPopAttrib();
	};

	virtual void overlay()
	{
	};

	virtual void reshape(const unsigned int uWidth, const unsigned int uHeight)
	{
	};

	virtual void mousePress(const MouseEvent & mouEvent)
	{
	};

	virtual void mouseRelease(const MouseEvent & mouEvent)
	{	
	};

	virtual void mouseMove(const MouseEvent & mouEvent)
	{
	};

	virtual void keyboardPress(const KeyboardEvent & keyEvent)
	{
	};

	virtual void keyboardRelease(const KeyboardEvent & keyEvent)
	{
	};

protected:

	virtual void displayBounds(const Box & boxBounds)
	{
		if (boxBounds.IsEmpty())
			return;

		const float fStartX = boxBounds.GetMinimum().GetX();
		const float fStartY = boxBounds.GetMinimum().GetY();
		const float fStartZ = boxBounds.GetMinimum().GetZ();

		const float fEndX = boxBounds.GetMaximum().GetX();
		const float fEndY = boxBounds.GetMaximum().GetY();
		const float fEndZ = boxBounds.GetMaximum().GetZ();

		const float vfCube[2][4][3] =
		{
			// Left
			{
				{ fStartX,fEndY,fEndZ }, 
				{ fStartX,fEndY,fStartZ }, 
				{ fStartX,fStartY,fStartZ }, 
				{ fStartX,fStartY,fEndZ }, 
			},

			// Right
			{
				{ fEndX,fEndY,fStartZ }, 
				{ fEndX,fEndY,fEndZ }, 
				{ fEndX,fStartY,fEndZ }, 
				{ fEndX,fStartY,fStartZ }, 
			},
		};

		const float vfCubeStrips[10][3] =
		{
			{ fStartX,fEndY,fEndZ }, 
			{ fEndX,fEndY,fEndZ }, 

			{ fStartX,fEndY,fStartZ }, 
			{ fEndX,fEndY,fStartZ }, 

			{ fStartX,fStartY,fStartZ }, 
			{ fEndX,fStartY,fStartZ }, 

			{ fStartX,fStartY,fEndZ}, 
			{ fEndX,fStartY,fEndZ}, 

			{ fStartX,fEndY,fEndZ }, 
			{ fEndX,fEndY,fEndZ }, 
		};

		glPushAttrib(GL_ALL_ATTRIB_BITS);
		glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);

		glEnable(GL_POLYGON_OFFSET_LINE);
		glPolygonOffset(1.0, 1.0);

		glColor4f(0.0f,0.0f,0.0f,1.0f);
		glLineWidth(5.0f);

		glBegin(GL_QUADS);

		glVertex3fv(vfCube[0][0]);
		glVertex3fv(vfCube[0][1]);
		glVertex3fv(vfCube[0][2]);
		glVertex3fv(vfCube[0][3]);

		glVertex3fv(vfCube[1][0]);
		glVertex3fv(vfCube[1][1]);
		glVertex3fv(vfCube[1][2]);
		glVertex3fv(vfCube[1][3]);

		glEnd();

		glBegin(GL_QUAD_STRIP);

		glVertex3fv(vfCubeStrips[0]);
		glVertex3fv(vfCubeStrips[1]);
		glVertex3fv(vfCubeStrips[2]);
		glVertex3fv(vfCubeStrips[3]);
		glVertex3fv(vfCubeStrips[4]);
		glVertex3fv(vfCubeStrips[5]);
		glVertex3fv(vfCubeStrips[6]);
		glVertex3fv(vfCubeStrips[7]);
		glVertex3fv(vfCubeStrips[8]);
		glVertex3fv(vfCubeStrips[9]);

		glEnd();

		glDisable(GL_POLYGON_OFFSET_LINE);

		glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
		glEnable(GL_LINE_SMOOTH);
		glEnable(GL_BLEND);
		glBlendFuncSeparate(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA,GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

		glColor4f(0.75f,0.75f,0.75f,1.0f);
		glLineWidth(2.0f);

		glBegin(GL_QUADS);

		glVertex3fv(vfCube[0][0]);
		glVertex3fv(vfCube[0][1]);
		glVertex3fv(vfCube[0][2]);
		glVertex3fv(vfCube[0][3]);

		glVertex3fv(vfCube[1][0]);
		glVertex3fv(vfCube[1][1]);
		glVertex3fv(vfCube[1][2]);
		glVertex3fv(vfCube[1][3]);

		glEnd();

		glBegin(GL_QUAD_STRIP);

		glVertex3fv(vfCubeStrips[0]);
		glVertex3fv(vfCubeStrips[1]);
		glVertex3fv(vfCubeStrips[2]);
		glVertex3fv(vfCubeStrips[3]);
		glVertex3fv(vfCubeStrips[4]);
		glVertex3fv(vfCubeStrips[5]);
		glVertex3fv(vfCubeStrips[6]);
		glVertex3fv(vfCubeStrips[7]);
		glVertex3fv(vfCubeStrips[8]);
		glVertex3fv(vfCubeStrips[9]);

		glEnd();

		glPopAttrib();
	};

private:
	
	Environment & m_envEnvironment;
};