//===========================================================================//
// File:	controls.hpp                                                        //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  -----------------------------------------------------------//
// 12/12/94  CPB  Initial coding.                                            //
// 01/25/95  CPB  Major surgery! Removed Entities, added Receivers.          //
// 08/25/97  JMA  Infrastructure changes												  //
// 08/25/97  ECH	Infrastructure changes												  //
//---------------------------------------------------------------------------//
// Copyright (C) 1995-97, FASA Interactive. All rights reserved				  //
//                      PROPRIETARY and CONFIDENTIAL                         //
//===========================================================================//

#pragma once

#include "Adept.hpp"
#include "Receiver.hpp"
#include "Entity.hpp"

#pragma warning (push)
#include <stlport\vector>
#pragma warning (pop)

namespace Adept {

	class Controls;
	class ControlsInstance;
	class ControlsMappingGroup;
	class ControlsManager;
	class Joystick;
	class Interface;

	enum {
	MOUSE_WHEEL_DOWN=512,
	MOUSE_WHEEL_UP,
	MOUSEX_LEFT,
	MOUSEX_RIGHT,
	MOUSEY_UP,
	MOUSEY_DOWN,
	JOYX_LEFT,
	JOYX_RIGHT,
	JOYY_UP,
	JOYY_DOWN,
	JOYRUDDER_LEFT,
	JOYRUDDER_RIGHT,
	JOYTHROTTLE_UP,
	JOYTHROTTLE_DOWN,
	HAT_LEFT,
	HAT_RIGHT,
	HAT_UP,
	HAT_DOWN,

	LAST_AXIS_MAPID
	};

	struct ControlData
	{
// MSL 5.05 MFD Comm
		enum {
			Move_Control,
			Fire_Control,
			Misc_Control,
			Lancemate_Control,
			Comm_Control
		};

		enum {
			FirstDevice,
			Keyboard = FirstDevice,
			Mouse,
			Joystick,
			LastDevice = Joystick
		};

		Entity::AttributeID attr_id;
		Receiver::MessageID mesg_id;
		Plug *owner;
		int control_mask;
		int group;
		int element;
		int nameresid;
		int control_type;
		bool invert;

		ControlData ()
		{
			attr_id = 0;
			mesg_id = 0;
			owner = NULL;
			control_mask = group = element = nameresid = control_type = 0;
			invert = false;
		}
		ControlData (const Entity::AttributeID& p1,const Receiver::MessageID& p2,int p3,int p4,int p5,Plug *p6,bool p7,int p8,int p9)
		{
			attr_id = p1;
			mesg_id = p2;
			control_mask = p3;
			group = p4;
			element = p5;
			owner = p6;
			invert = p7;
			nameresid = p8;
			control_type = p9;
		}
	};


	//#########################################################################
	//######################### ControlsInstance ##############################
	//#########################################################################

	// The ControlsInstance object exists to serve the ControlsMappingGroup
	// object.  It maintains one instance of a mapping from a physical
	// input device to either an entity event message or a value.

	class _declspec(novtable) ControlsInstance :
		public Stuff::Plug
	{
		friend class ControlsMappingGroup;
		friend class ControlsManager;				// required for testing
		friend class L4MappableButtonManager;

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

	public:
		ControlsInstance(ClassData *class_data,int control_mask,Stuff::Plug *dependant);
		~ControlsInstance();

		void
			TestInstance();

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

		int controlMask;		// lots of objects (and templates) need access to this

	protected:
		virtual void Update(void *data_source)=0;

		Stuff::SlotOf<Stuff::Plug*> dependantPlug;
	};

	//#########################################################################
	//###################### DirectControlsInstance ###########################
	//#########################################################################

	class DirectControlsInstance:
		public ControlsInstance
	{
		friend class ControlsMappingGroup;
		friend class ControlsManager;				// required for testing

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

	public:
		DirectControlsInstance(
			int control_mask,
			Entity *entity_to_control,
			Entity::AttributeID attribute_ID,
			RegisteredClass::ClassID attribute_type,
			Stuff::Plug *dependant,
			bool invert
		);
		~DirectControlsInstance();

		void
			Update(void *data_source);

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

		void TestInstance();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Public Data
	//
	public:
		Entity *entity;
		AttributeEntry *attributeEntry;
		bool m_Invert;
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~EventControlsInstanceOf ~~~~~~~~~~~~~~~~~~

	class EventControlsInstance:
		public ControlsInstance
	{
		friend class ControlsMappingGroup;
		friend class ControlsManager;				// required for testing

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

	public:
		EventControlsInstance(
			ClassData *class_data,
			int control_mask,
			Receiver *receiver,
			Receiver::MessageID message_id,
			Stuff::Plug *dependant
		);
		~EventControlsInstance();

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

		void TestInstance();

		Receiver *receiverPointer;
		Receiver::MessageID messageID;
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~EventControlsInstanceOf ~~~~~~~~~~~~~~~~~~

	template <class T> class EventControlsInstanceOf:
		public EventControlsInstance
	{
		friend class ControlsMappingGroup;
		friend class ControlsManager;				// required for testing

	public:
		EventControlsInstanceOf(
			int control_mask,
			Receiver *receiver,
			Receiver::MessageID message_id,
			Stuff::Plug *dependant
		);
		~EventControlsInstanceOf();

		void Update(void *data_source);
	};

	template <class T> EventControlsInstanceOf<T>::EventControlsInstanceOf(
		int control_mask,
		Receiver *receiver,
		Receiver::MessageID message_id,
		Stuff::Plug *dependant
	):
		EventControlsInstance(
			DefaultData,
			control_mask,
			receiver,
			message_id,
			dependant
		)
			{}

	template <class T> EventControlsInstanceOf<T>::~EventControlsInstanceOf()
		{}

	template <class T> void EventControlsInstanceOf<T>::Update(void *data_source)
	{
		Check_Object(this);
		Check_Pointer(data_source);

		ReceiverDataMessageOf<T>
			update_message(
				messageID,
				sizeof(ReceiverDataMessageOf<T>),
				-1,
				ReceiverDataMessageOf<T>::DefaultFlags,
				*Cast_Pointer(T*, data_source)
			);

		Check_Object(receiverPointer);
		receiverPointer->Receive(&update_message);
	}

	//#########################################################################
	//######################### ControlsMappingGroup ##########################
	//#########################################################################

	// The ControlsMappingGroup object maintains a group of ControlInstances.
	//
	// ControlsMappingGroup.Update() will call ControlsInstance.Update()
	// for each instance in the group.

	class ControlsMappingGroup :
		public Stuff::Plug
	{
		friend class ControlsManager;				// required for testing

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

	public:
		ControlsMappingGroup();
		~ControlsMappingGroup();

		void TestInstance();

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

		void Add(ControlsInstance *mapping)
		 {
					Check_Object(this);
					Check_Object(mapping);
					instanceList.Add(mapping);
				}

		virtual void Remove(int control_mask);
		virtual void Remove (const Entity::AttributeID& attr_id,const Receiver::MessageID& mesg_id);

		virtual void Update(void *value, int control_mask);

		bool CurrentFilterStatus(int control_mask);			// returns true if at least one button active

		void RemoveAll()
		{
			ChainIteratorOf<ControlsInstance *> iterator(&instanceList);
			ControlsInstance *plug = NULL;
			while ((plug=iterator.GetCurrent()) != NULL)
			{
				iterator.Remove();
				Unregister_Object(plug);
				delete plug;
			}
		}

	protected:
		Stuff::ChainOf<ControlsInstance*> instanceList;
	};

	//#########################################################################
	//######################### ControlsUpdateManagerOf #######################
	//#########################################################################

	template <class T> class ControlsUpdateManagerOf :
		public ControlsMappingGroup
	{
	public:
		ControlsUpdateManagerOf();
		~ControlsUpdateManagerOf();

		virtual ControlsInstance* Add(int control_mask,Receiver *receiver_pointer,Receiver::MessageID id,Stuff::Plug *dependant);

		virtual ControlsInstance* Add(int control_mask,Entity *entity_to_control,Entity::AttributeID attribute_ID,RegisteredClass::ClassID attribute_type,Stuff::Plug *dependant,bool invert);

		enum
		{
			unmapped = 0,
			mappedByOthers = 1,
			mappedByMe = 2
		};

		virtual void Update(void *sourcePointer, int control_mask);

		void ForceUpdate(T *sourcePointer, int control_mask);

		T previousValue;
	};

	template <class T>
		ControlsUpdateManagerOf<T>::ControlsUpdateManagerOf()
		: ControlsMappingGroup()
	{
	}

	template <class T> ControlsUpdateManagerOf<T>::~ControlsUpdateManagerOf()
	{
	}

	template <class T> void
		ControlsUpdateManagerOf<T>::Update(
			void * source_pointer,
			int control_mask
		)
	{
		Check_Object(this);
		Check_Pointer(source_pointer);

		if (previousValue != *Cast_Pointer(T*, source_pointer))
		{
			ForceUpdate(Cast_Pointer(T*, source_pointer), control_mask);
		}
	}

	template <class T> void
		ControlsUpdateManagerOf<T>::ForceUpdate(
			T* source_pointer,
			int control_mask
		)
	{
		Check_Object(this);
		Check_Pointer(source_pointer);
		previousValue = *source_pointer;
		ControlsMappingGroup::Update(source_pointer, control_mask);
	}

	template <class T> ControlsInstance*
		ControlsUpdateManagerOf<T>::Add(
			int control_mask,
			Receiver *receiver_pointer,
			Receiver::MessageID message_id,
			Stuff::Plug *dependant
		)
	{
		Check_Object(this);
		Check_Object(receiver_pointer);

		EventControlsInstanceOf<T> *instance =
			new EventControlsInstanceOf<T>(
					control_mask,
					receiver_pointer,
					message_id,
					dependant
				);
		Register_Object(instance);
		ControlsMappingGroup::Add(instance);
		return instance;
	}

	template <class T> ControlsInstance*
		ControlsUpdateManagerOf<T>::Add(
			int control_mask,
			Entity *entity_to_control,
			Entity::AttributeID attribute_ID,
			RegisteredClass::ClassID attribute_type,
			Stuff::Plug *dependant,
			bool invert
		)
	{
		Check_Object(this);

		DirectControlsInstance *instance =
			new DirectControlsInstance(
				control_mask,
				entity_to_control,
				attribute_ID,
				attribute_type,
				dependant,
				invert
			);

		Register_Object(instance);
		ControlsMappingGroup::Add(instance);
		return instance;
	}

	//#########################################################################
	//############################ ControlsManager ############################
	//#########################################################################

	//##########################################################################
	// The following classes must always be typedef'd or overriden by an
	// inheritor
	//
	typedef Receiver__ClassData	ControlsManager__ClassData;
	typedef Receiver__Message		ControlsManager__Message;

	class ControlsManager:
		public Receiver
	{
	public:
		friend class ControlsMappingGroup;	// for access to groupEnable

		static void
			InitializeClass();
		static void
			TerminateClass();

		static ClassData
			*DefaultData;

		typedef ControlsManager__ClassData	ClassData;
		typedef ControlsManager__Message		Message;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructors
	//
	public:
		ControlsManager();
		~ControlsManager();

		static ControlsManager *Instance;

		void Remove(int control_mask);
		int Remove(int group,int element,int control_mask);			// return actual number removed
		int Remove (const Entity::AttributeID& attr_id,const MessageID& mesg_id);		// return actual number removed
		void Remap (
			Entity *entity_to_control,
			Entity::AttributeID attribute_ID,
			Receiver *receiver,
			MessageID message,
			Stuff::Plug *owner,
			int control_mask,
			int group,
			int element,
			bool invert,
			int nameid,
			int type
		);				// will remove old mapping and create a new one with this data,
							// all mappings refering to attribute_id, message, group, and element will be removed

		void RemoveAllMappings();

		void Execute();

		void
			CreateMapping(
				Entity *entity_to_control,
				Entity::AttributeID attribute_ID,
				Receiver *receiver,
				MessageID message,
				Stuff::Plug *owner,
				int control_mask,
				int group,
				int element,
				bool invert,
				int nameid,
				int type
			);

		//-------------------------------------------------------------------
		// Gauge support
		//-------------------------------------------------------------------
		void *activeDestination;
		Receiver *activeReceiver;
		Receiver::MessageID activeMessageID;
		Stuff::Plug *activeDependant;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Control Groups
	//
	public:
		enum {
			JoystickAxisGroupID,
			JoystickButtonGroupID,
			JoystickHatID,
			MousePosXID,
			MousePosYID,
			MouseDeltaXID,
			MouseDeltaYID,
			MouseWheelDeltaID,
			MouseButtonGroupID,
			VirtualButtonGroupID,
			SystemKeyboardID
		};

		enum {
			JoystickButtonIDBase = 0x100
		};


		stlport::vector<ControlData> m_AllMappings;

		void SetJoystick (int id);
		void JoyStickShift (int value);
		bool m_ListChanged;
		bool m_IgnoreCommands;

		int m_JoyStickShiftButton;
		Joystick *systemJoystick;
		Adept::ControlsUpdateManagerOf<Stuff::Scalar> *joystickAxisGroup;
		Adept::ControlsUpdateManagerOf<int> *joystickButtonGroup;
		Adept::ControlsUpdateManagerOf<int> *joystickHat;

		Adept::ControlsUpdateManagerOf<float>	mousePosX,mousePosY;		
		Adept::ControlsUpdateManagerOf<float>	mouseDeltaX,mouseDeltaY;
		Adept::ControlsUpdateManagerOf<int> mouseWheelDelta;
		Adept::ControlsUpdateManagerOf<int>	mouseButtonGroup[5];										// new buttons
		void CenterMouse (void);
		void TowardsCenterMouse (Scalar amountx,Scalar amounty);

		Adept::ControlsUpdateManagerOf<int> virtualButtonGroup[LAST_AXIS_MAPID];
		Adept::ControlsUpdateManagerOf<int> systemKeyboard;

		void ActivateButton(int button);

		enum {
			PlainKeyMode,
			ShiftMode=1,
			CtrlMode=2,
			AltMode=4,
			CtrlShiftMode=ShiftMode|CtrlMode,
			ShiftAltMode=ShiftMode|AltMode,
			CtrlAltMode=CtrlMode|AltMode,
			CtrlShiftAltMode=ShiftMode|CtrlMode|AltMode
		};

		enum {
			PlainFlag = 1<<PlainKeyMode,
			ShiftFlag = 1<<ShiftMode,
			CtrlFlag = 1<<CtrlMode,
			AltFlag = 1<<AltMode,
			CtrlShiftFlag = 1<<CtrlShiftMode,
			ShiftAltFlag = 1<<ShiftAltMode,
			CtrlAltFlag = 1<<CtrlAltMode,
			CtrlShiftAltFlag = 1<<CtrlShiftAltMode,
			AlwaysActive = 0xFFFF
		};

		int controlMask;


		bool pressAnyKey;
		bool m_ChatMode;
		bool m_ClearingChatEnter;
		bool m_ClearingChatEscape;

		bool GetPressAnyKey()
		{
			return pressAnyKey;
		}

		void ClearPressAnyKey()
		{
			pressAnyKey = false;
		}

		SlotOf <Interface *> m_ChatInterface;
		void EnterChatMode (Interface *dest);
		void LeaveChatMode (void);
		
		static bool
			TestClass();

		void
			TestInstance();


	protected:
		Stuff::ChainOf< Adept::ControlsUpdateManagerOf<int>* >
			activeButtons;

		typedef
			Stuff::ChainIteratorOf< Adept::ControlsUpdateManagerOf<int>* >
				ButtonIterator;
	};

}


