//===========================================================================//
// File:	CameraShip.hpp												
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 09/09/98  JSE  Inital base class based off of Shadowrun/Adept     
//---------------------------------------------------------------------------//
// Copyright (C) 1998, Fasa Interactive										 //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#pragma once

#include "MW4.hpp"
#include <Adept\Entity.hpp>
#include <Adept\NameTable.hpp>
#include "path.hpp"
#include "SimpleChannelAnimator.hpp"

namespace MechWarrior4
{
	class CameraShip;
	class CameraShipManager;

	//##########################################################################
	//###############    CameraShip::ExecutionStateEngine    ##################
	//##########################################################################

	class CameraShip__ExecutionStateEngine:
		public Adept::Entity__ExecutionStateEngine
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		typedef Adept::Entity__ExecutionStateEngine BaseClass;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Run-time Construction and Destruction Support
	//
	public:
		typedef CameraShip__ExecutionStateEngine*
			(*Factory)(
				CameraShip *entity,
				FactoryRequest *request
			);

		static CameraShip__ExecutionStateEngine*
			Make(
				CameraShip *camera,
				FactoryRequest *request
			);

	protected:
		CameraShip__ExecutionStateEngine(
			ClassData *class_data,
			CameraShip *camera,
			FactoryRequest *request
		);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Class Data support
	//
	public:
		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// State stuff
	//
	public:
		enum {
			CameraMotionState = Adept::Entity::ExecutionStateEngine::StateCount,
			StateCount
		};

	protected:
		static const StateEntry
			StateEntries[];

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test Support
	//
	public:
		void
		  	TestInstance() const;
	};

	//##########################################################################
	//##################    CameraShip::CreateMessage    #######################
	//##########################################################################


	class CameraShip__CreateMessage:
		public Adept::Entity__CreateMessage
	{
	public:

		CameraShip__CreateMessage(
			size_t length,
			int priority,
			int message_flags,
			Stuff::RegisteredClass::ClassID class_id,
			int replicator_flags,
			const Adept::ResourceID& instance_id,
			const Stuff::LinearMatrix4D &creation_matrix,
			Stuff::Scalar age,
			int execution_state,
			int name_id,
			int entity_alignment
		):
			Adept::Entity__CreateMessage(
				length, 
				priority, 
				message_flags, 
				class_id, 
				replicator_flags,
				instance_id,
				creation_matrix,
				age,
				execution_state,
				name_id,
				entity_alignment
			)
		{};

		static void
			ConstructCreateMessage(Script *script);
	};



	//##########################################################################
	//############################    CameraShipManager
	//##########################################################################
	


	class CameraShipManager:
		public Stuff::Plug
	{
	public:
		
		static CameraShipManager
			*Instance;

		CameraShipManager():
			Plug(DefaultData),
			camerasInWorld(NULL),
			activeCamera(NULL)
		{
			cinemaStarted = false;
			internalCamera = false;
			hudOn = true;
		};
	
		~CameraShipManager(){};

	private:
		Stuff::ChainOf<CameraShip*> camerasInWorld;
		Stuff::SlotOf<CameraShip*> activeCamera;

		bool cinemaStarted;
		bool internalCamera;
		bool hudOn;

	public:
		Stuff::Scalar nearClip;
		Stuff::Scalar farClip;
		Stuff::Radian horFOV;
		Stuff::Scalar aspectRatio;

	public:
		void AddCamera(CameraShip *camera)
		{
			Check_Object(camera);
			camerasInWorld.Add(camera);
		}


		void TurnOnCameras();
		void TurnOffCameras();
		void InterruptCinema();
		void SetActiveCamera(CameraShip *camera);
		void SetInternalCamera(bool show_hud);


		void ToggleHud(bool active);
		void ToggleInternal(bool active);

		CameraShip *GetActiveCamera(void);


	};


	//##########################################################################
	//############################    CameraShip 
	//##########################################################################

	//-------------------------------------------------------------------------
	// The following helper classes must always be typedef'd or overriden by an
	// inheritor
	//
	typedef Adept::Entity__ClassData		CameraShip__ClassData;
	typedef Adept::Entity__Message		CameraShip__Message;
	typedef Adept::Entity__GameModel		CameraShip__GameModel;
	typedef Adept::Entity__UpdateMessage	CameraShip__UpdateMessage;
	
	//-----------------------  End of inheritance stuff ------------------------

	class CameraShip:
		public Adept::Entity
	{
		friend class MovementClass;

	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		typedef Adept::Entity BaseClass;

	//##########################################################################
	// Inheritance support
	//
	public:
		typedef CameraShip__ClassData				ClassData;
		typedef CameraShip__Message				Message;
		typedef CameraShip__ExecutionStateEngine	ExecutionStateEngine;
		typedef CameraShip__CreateMessage			CreateMessage;
		typedef CameraShip__GameModel				GameModel;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Run-time Construction and Destruction Support
	//
	public:
		static CameraShip* 
			Make(
				CreateMessage *message,
				Adept::ReplicatorID *base_id
			);

		void
			SaveInstanceText(Stuff::Page *page);

	protected:

		CameraShip(
			ClassData *class_data,
			CreateMessage *message,
			Adept::ReplicatorID *base_id,
			ElementRenderer::Element *element
		);


		~CameraShip();
	
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Class Data support
	//
	public:
		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Execution Support
	//
	public:
 
		void PostCollisionExecute(Stuff::Time till);

		void TurnOn(void);
		void TurnOff(void);

		void CameraFollowObject(Adept::Entity *entity);
		void CameraFollowPath(float speed_mps, Path *path);
		void CameraPosition(float x, float y, float z, float time);
		void CameraDetach();
		void CameraOffset(float x, float y, float z, float time, bool local);
		
		void OverrideCameraPitch(float degrees, float time);
		void OverrideCameraRoll(float degrees, float time);
		void OverrideCameraYaw(float degrees, float time);
		void ResetCameraOverrides(void);

		void TargetFollowObject(Adept::Entity *entity);
		void TargetFollowPath(float speed_mps, Path *path);
		void TargetPosition(float x, float y, float z, float time);
		void TargetDetach();
		void TargetOffset(float x, float y, float z, float time, bool local);
		
		void SetCameraFOV(float degrees, float time);
		void FadeToBlack(float time);
		void FadeToWhite(float time);
		void FadeFromBlack(float time);
		void FadeFromWhite(float time);
	
		void SetFootShakeParams(Adept::ObjectID id, int meters);
		void UpdateFootShaking(Stuff::YawPitchRoll& camera_rotation);

		int
			GetTableArray()
		{Check_Object(this); return Adept::NameTable::CameraShipArray;}
	
		void SetActive()
		{
			activeCamera = true;
		}

		void ClearActive()
		{
			activeCamera = false;
		}

	private:

		
		enum {
			FollowInitialPositionMovementType = 0,
			FollowObjectMovementType,
			FollowPathMovementType,
			FollowPositionMovemntType
		};

		int cameraMovement;
		int targetMovement;

		Adept::Entity *cameraFollowObject;
		Adept::Entity *targetFollowObject;

		Path *cameraPath;
		Path *targetPath;

		
		int cameraCurrentWayPoint;
		int targetCurrentWayPoint;

		float cameraPathSpeed;
		float targetPathSpeed;

		SimpleChannelAnimatorOf<Stuff::Point3D> cameraWaypointAnimation;
		SimpleChannelAnimatorOf<Stuff::Point3D> targetWaypointAnimation;



		bool cameraOffsetLocal;
		bool targetOffsetLocal;

		Stuff::Point3D currentTargetPosition;


		SimpleChannelAnimatorOf<Stuff::Point3D> cameraPosition;
		SimpleChannelAnimatorOf<Stuff::Point3D> targetPosition;


		SimpleChannelAnimatorOf<Stuff::Point3D> cameraOffset;
		SimpleChannelAnimatorOf<Stuff::Point3D> targetOffset;

		bool overridePitchFlag;
		bool overrideYawFlag;
		bool overrideRollFlag;

		SimpleChannelAnimatorOf<Stuff::Scalar> cameraPitch;
		SimpleChannelAnimatorOf<Stuff::Scalar> cameraYaw;
		SimpleChannelAnimatorOf<Stuff::Scalar> cameraRoll;

		enum {
			FadeBlackType = 0,
			FadeWhiteType
		};
		int fadeState;

		SimpleChannelAnimatorOf<Stuff::Scalar> cameraFOV;
		SimpleChannelAnimatorOf<Stuff::Scalar> fadeLevel;
		

		bool
			activeCamera;

		int
			m_ShakeDistance;

		Adept::ObjectID
			m_ShakeSource;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test Support
	//
	public:
		void
      	TestInstance() const;
	};

	inline
		CameraShip__ExecutionStateEngine::CameraShip__ExecutionStateEngine(
			ClassData *class_data,
			CameraShip *camera,
			FactoryRequest *request
		):
			Entity__ExecutionStateEngine(class_data, camera, request)
	{
	}

}
