/*
   render/camera.h
   This file is part of the Osirion project and is distributed under
   the terms and conditions of the GNU General Public License version 2
*/

#ifndef __INCLUDED_RENDER_CAMERA_H__
#define __INCLUDED_RENDER_CAMERA_H__

#include "core/range.h"
#include "math/vector3f.h"
#include "math/axis.h"

namespace core
{
	class Entity;
}

namespace render
{

const float WORLDSCALE = 4.0f;

const float FRUSTUMSIZE = 0.5f;
const float FRUSTUMFRONT = 1.0f;
const float FARPLANE = core::range::maxdistance * WORLDSCALE;

/**
 * @brief The Camera class draws a camera transformation determined by its current settings
 * */
class Camera
{
public:
	/**
	 * @brief enum indicating the camera mode
	 * */
	enum Mode {Track, Cockpit, Free, Overview};
	
	/**
	 * @brief default constructor
	 * */
	Camera(const Mode mode = Track);
	
	/**
	 * @brief destructor
	 * */
	~Camera();
	
	/* --- inspectors ------------------------------------------ */
	
	/**
	 * @brief current camera mode
	 * */
	inline const Mode mode() const
	{
		return _mode;
	}
	
	/**
	 * @brief distance between the camera eye and the target
	 * */
	inline const float distance() const
	{
		return _distance;
	}
	
	/**
	 * @brief distance multiplier
	 * The distance multiplier can be used to zoom the camera in or out
	 * */
	inline const float multiplier() const
	{
		return _multiplier;
	}
	
	/**
	 * @brief camera eye location, translation part of the camera transformation
	 * */
	inline const math::Vector3f & location() const
	{
		return _location;
	}
	
	/**
	 * @brief camera target location,point the camera is looking at
	 * */
	inline const math::Vector3f & target_location() const
	{
		return _target_location;
	}
	
	/**
	 * @brief camera eye axis, rotation part of the camera transformation
	 * */
	inline const math::Axis & axis() const
	{
		return _axis;
	}
	
	/**
	 * @brief the entity the camera is currently looking at
	 * */
	inline const core::Entity *target()
	{
		return _target_entity;
	}
	
	/**
	 * @brief free look direction angle, in degrees
	 * */
	inline const float freelook_direction() const
	{
		return _freelook_direction;
	}
	
	/**
	 * @brief free look pitch angle, in degrees
	 * */
	inline const float freelook_pitch() const
	{
		return _freelook_pitch;
	}
	
	/**
	 * @brief free look direction rotation speed, -1..1
	 * */
	inline const float movement_direction() const
	{
		return _movement_direction;
	}
	
	/**
	 * @brief free look pitch rotation speed, -1..1
	 * */
	inline const float movement_pitch() const
	{
		return _movement_pitch;
	}
	
	/* --- mutators -------------------------------------------- */
		
	/**
	 * @brief set the current camera mode
	 * */
	void set_mode(const Mode mode);
	
	/**
	 * @brief set next camera mode
	 * */
	void cycle_mode_next();
	
	/**
	 * @brief set previous camera mode
	 * */
	void cycle_mode_previous();

	/**
	 * @brief set camera target
	 * */
	void set_target(const core::Entity *entity = 0);
	
	/**
	 * @brief set distance multiplier
	 * */
	void set_multiplier(const float multiplier);
	
	/**
	 * @brief set the free look direction angle, in degrees
	 * */
	void set_freelook_direction(const float angle);
	
	/**
	 * @brief set the free look pitch angle, in degrees
	 * */
	void set_freelook_pitch(const float angle);
	
	/**
	 * @brief set the free look direction rotation  speed, -1..1
	 * */
	void set_movement_direction(const float speed);
	
	/**
	 * @brief set the free look pitch rotation speed, -1..1
	 * */
	void set_movement_pitch(const float speed);
		
	/* --- actors ---------------------------------------------- */
	
	void reset();
	
	/**
	 * @brief update the camera location and axis.
	 * */
	void frame(const float elapsed);
	
	/**
	 * @brief draw the actual camera transformation
	 * This method is used to draw the camera projection for the world render
	 * and applies WORLDSCALE.
	 * */
	void draw();
	
	/**
	 * @brief draw the actual camera transformation
	 * This method variant is used by the user interface 3D model widget
	 * and ignores WORLDSCALE.
	 * */
	void draw(const float center_x, const float center_y);
	
	/* --- static ---------------------------------------------- */
	
	/**
	 * @brief set the current transformation matrix to a orthographic projection
	 * This method is used while drawing the user interface.
	 * */
	static void ortho();

private:
	Mode			_mode;
	
	float			_distance;
	float 			_multiplier;
	math::Vector3f		_location;
	math::Axis		_axis;	
		
	const core::Entity *	_target_entity;
	math::Vector3f		_target_location;
	math::Axis		_target_axis;	

	float 			_freelook_direction;	
	float 			_freelook_pitch;
	
	float			_movement_direction;
	float			_movement_pitch;

	
}; 	// class camera

} 	// namespace render

#endif 	// __INCLUDED_RENDER_CAMERA_H__