//////////////////////////////////////////////////////////////////////////////
//
// AVP_External_Camera.h
//
// Created by Anthony Gregson - 09/11/07
//
// Copyright (c) 2007 Rebellion. All rights reserved.
//
//		Generic camera for all game situations where we're not in first-person.
//		Includes spectating, AVPTV, and multiplayer limbo states.
//		Can either be a flycam, or can be attached to actors as a freely-rotated third-person camera.
//		If the user wants to spectate in first person, we'll create the normal actor first-person cameras to handle that, and go through them instead.
//
//////////////////////////////////////////////////////////////////////////////

// B E G I N   F I L E   W R A P P E R ///////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef ___AVP_EXTERNAL_CAMERA_H___
#define ___AVP_EXTERNAL_CAMERA_H___ 1

//////////////////////////////////////////////////////////////////////////
// I N C L U D E   F I L E S /////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#include "Core/Asura_Maths.h"

//////////////////////////////////////////////////////////////////////////
// F O R W A R D   D E C L A R A T I O N S ///////////////////////////////
//////////////////////////////////////////////////////////////////////////
class AVP_ClientEntity_Actor;
class Asura_ControlMap;

//////////////////////////////////////////////////////////////////////////
// C L A S S   D E C L A R A T I O N S ///////////////////////////////////
//////////////////////////////////////////////////////////////////////////
class AVP_External_Camera
{
public:
	enum AVP_EXTERNAL_CAMERA_CONTROL_MAPPINGS
	{
		// Look mappings...
		LOOK_LEFT_RIGHT,
		LOOK_UP_DOWN,
		// TODO - would a twist control be useful for AVPTV?

		// Movement mappings...
		MOVE_FORWARDS_BACKWARDS,
		MOVE_LEFT_RIGHT,
		MOVE_UP_DOWN,

		// View entity controls. Next and previous implicitly connect the camera.
		NEXT_PLAYER,
		PREVIOUS_PLAYER,
		TOGGLE_FOLLOW_PLAYER,	// Turn follow mode on and off. If turning it on, pick a sensible entity in some way (under cursor, nearest on camera, most recent previous, or something).
		TOGGLE_FIRST_PERSON,	// If following, enter first-person mode. This effectively deactivates this camera and reroutes through the actor camera handlers (which will need creating/destroying as applicable).

		// Other controls, some of which will only be applicable in certain modes or at certain times.
		RESPAWN,	// Request a respawn in a multiplayer game.
		TOGGLE_MENU,	// Pause menu.
		TOGGLE_OBJECTIVES,	// Objectives menu.
		SCOREBOARD,			// Multiplayer scoreboard
		TOGGLE_DVS,			// DVS Menu

#ifdef AVP_SECOND_CONTROL_FLY_CAM
		// Controls to be used in the flycam mode
		SCREENSHOT,
		TOGGLE_FLY_CAM,
		TOGGLE_FREEZE,
		TOGGLE_RENDER_ALL,
		TOGGLE_TIME,
		TOGGLE_WIREFRAME,
#endif

		NUM_AVP_EXTERNAL_CAMERA_MAPPINGS,
	};

	AVP_External_Camera();
	virtual ~AVP_External_Camera();

	// Two ways to start off - connected to an entity, or at some position in space.
	// If neither are called, we'll start at the origin, which is probably a bad idea in many levels.
	void Initialise(const Asura_Vector_3& xInitialPosition, const Asura_Matrix_3x3 xInitialOrientation);
	void Initialise(Asura_Guid uTargetEntity, float fInitialDistance); // May want an orientation too, but we'll take that from the entity to start with.

	void Update();

	// Update the actual Asura_Camera with our data.
	void SetCamera();

	// Camera reset
	void ResetCameraToTarget(); 

	// Functions to create and destroy the control map when needed.
	void CreateControlMap(u_int uIdentifier);
	void DestroyControlMap();

	// Control map accessors.
	bool HasControlMap() const { return m_pxControlMap != NULL; }
	float GetControlMapValue(u_int uMapping) const;

#ifdef AVP_SECOND_CONTROL_FLY_CAM
	bool GetUsingFlyCam(){ return m_bUsingFlyCam; }
	void SetRecreateFlyCamControlMap( bool bTrue ){ m_bRecreateFlyCamControlMap = bTrue; }
#endif

	// Camera behaviour
	void SetFirstPersonCamera(bool bIsFirstPersonCamera)		{ m_bFirstPersonCamera = bIsFirstPersonCamera; }
	bool GetFirstPersonCamera()	const							{ return m_bFirstPersonCamera; }

	void SetTargetEntity(Asura_Guid uGuid)						{ m_uTargetEntity = uGuid; }
	Asura_Guid GetTargetEntity() const							{ return m_uTargetEntity; }

	void SetLastKnownTarget(Asura_Guid uGuid)					{ m_uLastKnownTarget = uGuid; }
	Asura_Guid GetLastKnownTarget() const						{ return m_uLastKnownTarget; }

	void SetCameraOrientation(Asura_Matrix_3x3& xOri)			{ m_xOrientation = xOri; }

private:
	// Normal movement controls (flycam and following entity)
	void UpdateRotationControls();
	void UpdateDistanceControls(); 
	void UpdateFlyCamControls();

	// Spectator mode
	void ToggleFollowPlayer(); 
	void FollowNextPlayer( Asura_Guid uPlayerGuid ); 
	void FollowPreviousPlayer( Asura_Guid uPlayerGuid ); 
	void ToggleFirstPerson(); 
	
	// Player rotation
	void RotatePlayer( Asura_Guid uPlayerGuid, int iIncrement ); 

	void SetPositionAndOrientationFromActor(AVP_ClientEntity_Actor& xActor);
	void SetPositionFromActor(AVP_ClientEntity_Actor& xActor);

	void Platform_FillControlMap();
#ifdef AVP_SECOND_CONTROL_FLY_CAM
	void Platform_FillSecondControlMap();
#endif

	// Position data.
	// Could (should?) replace the following two members with a physics object.
	Asura_Vector_3 m_xPosition;
	Asura_Matrix_3x3 m_xOrientation;

	// Target entity data.
	Asura_Guid m_uTargetEntity;
	Asura_Guid m_uLastKnownTarget;
	float m_fTargetDistance; // If we use physics, we may not actually reach this distance.
	float m_fCurrentDistance; // User can can move along the spherical radius up to the target distance
	bool m_bFirstPersonCamera;
#ifdef AVP_SECOND_CONTROL_FLY_CAM
	bool m_bRecreateFlyCamControlMap;
	bool m_bUsingFlyCam;
#endif

	// Control data. Create and destroy as needed with the provided functions.
	Asura_ControlMap* m_pxControlMap;
	u_int m_uControlMapIdentifier;	// Could be a hash, or the Guid of our owner, or even just an index (although that last one probably runs the risk of doubling up with another stack).

	// TODO - I'm sure there's far more options we want to add to this.
};


// E N D   F I L E   W R A P P E R ///////////////////////////////////////////

#endif // #ifndef ___AVP_EXTERNAL_CAMERA_H___
