#pragma once

#include "Adept.hpp"
#include "VideoHeaders.hpp"

namespace Adept {

	class Interface;
	class Replicator;

	//#########################################################################
	//##########################  CameraComponent  ##############################
	//#########################################################################

	class CameraComponent:
		public GroupComponent
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		typedef GroupComponent BaseClass;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructor/Destructor
	//
	protected:
		CameraComponent(
			ClassData *class_data,
			MemoryStream *stream,
			VideoComponentWeb *owning_web,
			Interface *camera_interface
		);

		ElementRenderer::CameraElement*
			AllocateCamera();

	public:
		static CameraComponent*
			Make(
				MemoryStream *stream,
				VideoComponentWeb *owning_web,
				Replicator *replicator
			);

		~CameraComponent();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Virtual data
	//
	public:
		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Component support
	//
	public:
		void
			Execute();
		
		ElementRenderer::CameraElement*
			GetElement()
				{
					Check_Object(this);
					return
						Cast_Object(
							ElementRenderer::CameraElement*,
							componentElement
						);
				}

		void
			SetPerspective(
				Scalar near_clip,
				Scalar far_clip,
				const Radian &horizontal_fov,
				Scalar height_to_width = 0.75f
			)
				{
					Check_Object(this);
					GetElement()->SetPerspective(
						near_clip,
						far_clip,
						horizontal_fov,
						height_to_width
					);
				}

		void
			GetPerspective(
				Scalar &near_clip,
				Scalar &far_clip,
				Radian &horizontal_fov,
				Scalar &height_to_width
			)
				{
					Check_Object(this);
					GetElement()->GetPerspective(
						near_clip,
						far_clip,
						horizontal_fov.angle,
						height_to_width
					);
				}
		void
			SetViewPort(
				Scalar &left,
				Scalar &top,
				Scalar &width,
				Scalar &height
			)
				{
					Check_Object(this);
					GetElement()->SetViewport(
						left, 
						top, 
						left-width, 
						top-height
					);
				}
		void
			GetViewPort(
				Scalar &left,
				Scalar &top,
				Scalar &right,
				Scalar &bottom
			)
				{
					Check_Object(this);
					GetElement()->GetViewport(
						left, 
						top, 
						right, 
						bottom
					);
				}

		void
			ComputeEyeLine(
				Line3D *eye_line,
				const Vector2DOf<Scalar> &cursor
			);
		bool
			ComputeCursor(
				Vector2DOf<Scalar> *cursor,
				const Point3D &location
			);

	protected:
		bool
			m_isMainSceneCamera;
		bool
			m_drawSky;

		Stuff::Scalar
			m_LODOffset;
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test support
	//
	public:
		void
			TestInstance();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Tool-related Functions
	//
	public:
		static ClassData*
			CreateFactoryRequest(FactoryRequestParameters *parameters);
	};

}

