#pragma once

#include "style.h"

class Controls;
class ControlsInstance;
class ControlsMappingGroup;
struct ControlsMapping;
class ControlsOwner;
class ControlsManager;

#include "slot.h"
#include "chain.h"
#include "vector2d.h"
#include "receiver.h"
#include "simulate.h"
#include "mode.h"

//########################################################################
//######################## Basic control typedefs ########################
//########################################################################

typedef Scalar				ControlsScalar;
typedef Vector2DOf<Scalar>	ControlsJoystick;
typedef int					ControlsKey;
typedef int					ControlsButton; // negative for release
typedef Vector2DOf<int>		ControlsMouse;

//#########################################################################
//######################### 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 ControlsInstance :
	public Node
{
	friend class ControlsMappingGroup;
	friend class ControlsManager;				// required for testing
	friend class L4MappableButtonManager;

public:
	ControlsInstance(
		ClassID class_id,
		ModeMask mode_mask,
		Plug *dependant
	);
	~ControlsInstance();

	ModeMask
		modeMask;		// lots of objects (and templates) need access to this

protected:
	virtual void Update(void *data_source);

	SlotOf<Plug*>
		dependantPlug;
	void
		ReleaseLinkHandler(
			Socket *socket,
			Plug *plug
		);
};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ControlsInstanceDirectOf ~~~~~~~~~~~~~~~~~~

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

public:
	ControlsInstanceDirectOf(
		ModeMask mode_mask,
		T* data_pointer,
		Plug *dependant
	);
	ControlsInstanceDirectOf(
		ControlsInstanceDirectOf<T> *original
	);
	~ControlsInstanceDirectOf();
	Logical
		TestInstance() const;

//	protected:
	void Update(void *data_source);

	T *dataPointer;
};

template <class T> ControlsInstanceDirectOf<T>::ControlsInstanceDirectOf(
	ModeMask mode_mask,
	T* data,
	Plug *dependant
):
	ControlsInstance(
		DirectControlsInstanceClassID,
		mode_mask,
		dependant
	),
	dataPointer(data)
		{}

template <class T> ControlsInstanceDirectOf<T>::ControlsInstanceDirectOf(
	ControlsInstanceDirectOf<T> *original
):
	ControlsInstance(
		DirectControlsInstanceClassID,
		original->modeMask,
		original->dependantPlug.GetCurrent()
	),
	dataPointer(original->dataPointer)
		{}

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

template <class T> void
	ControlsInstanceDirectOf<T>::Update(void *data_source)
{
	Check(this);
	Check_Pointer(data_source);
	Check_Pointer(dataPointer);
	*dataPointer = *(T*)data_source;
	Verify(*dataPointer == *(T*)data_source);
	Check_Fpu();
}

template <class T> Logical
	ControlsInstanceDirectOf<T>::TestInstance() const
{
	Check_Pointer(this);
	Check_Pointer(dataPointer);
	Check_Fpu();
	return Plug::TestInstance();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ControlsInstanceEventOf ~~~~~~~~~~~~~~~~~~

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

public:
	ControlsInstanceEventOf(
		ModeMask mode_mask,
		Receiver *receiver,
		Receiver::MessageID message_id,
		Plug *dependant
	);
	ControlsInstanceEventOf(
		ControlsInstanceEventOf<T> *original
	);

	~ControlsInstanceEventOf();
	Logical
		TestInstance() const;

//	protected:
	void Update(void *data_source);

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

template <class T> ControlsInstanceEventOf<T>::ControlsInstanceEventOf(
	ModeMask mode_mask,
	Receiver *receiver,
	Receiver::MessageID message_id,
	Plug *dependant
):
	ControlsInstance(
		EventControlsInstanceClassID,
		mode_mask,
		dependant
	),
	receiverPointer(receiver),
	messageID(message_id)
		{}

template <class T> ControlsInstanceEventOf<T>::ControlsInstanceEventOf(
	ControlsInstanceEventOf<T> *original
):
	ControlsInstance(
		EventControlsInstanceClassID,
		original->modeMask,
		original->dependantPlug.GetCurrent()
	),
	receiverPointer(original->receiverPointer),
	messageID(original->messageID)
		{}

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

template <class T> void
	ControlsInstanceEventOf<T>::Update(void *data_source)
{
	Check(this);
	Check_Pointer(data_source);
	Check(application);

	ReceiverDataMessageOf<T>
		update_message(
			messageID,
			sizeof(ReceiverDataMessageOf<T>),
			*(T*)data_source
		);

	application->Post(
		ControlsEventPriority,
		receiverPointer,
		&update_message
	);
}

template <class T> Logical
	ControlsInstanceEventOf<T>::TestInstance() const
{
	Check_Pointer(this);
	Check(receiverPointer);
	Check_Fpu();
	return Plug::TestInstance();
}

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

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

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

public:
	ControlsMappingGroup();
	~ControlsMappingGroup();

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

	virtual void
		Remove(ModeMask mode_mask);

	virtual void
		Update(void *value, ModeMask mode_mask);

	Logical				// returns true if at least one button active
		CurrentFilterStatus(ModeMask mode_mask);

protected:
	ChainOf<ControlsInstance*>
		instanceList;
};

//#########################################################################
//########################## ControlsUpdateManager ########################
//#########################################################################

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

	Logical
		TestInstance() const;

	virtual ControlsInstance*
		Add(
			ModeMask mode_mask,
			Receiver *receiver_pointer,
			Receiver::MessageID id,
			Plug *dependant
		);

	virtual ControlsInstance*
		Add(
			ModeMask mode_mask,
			T *destination,
			Plug *dependant
		);

	virtual ControlsInstance*
		AddOrErase(
			ModeMask mode_mask,
			Receiver *target,
			Receiver::MessageID message_ID,
			Plug *dependant
		);

	virtual ControlsInstance*
		AddOrErase(
			ModeMask mode_mask,
			T *destination,
			Plug *dependant
		);

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

	virtual int
		GetMapState(
			void *direct_destination,
			Receiver *event_receiver,
			Receiver::MessageID message_id,
			ModeMask mode_mask
		);

	virtual void
		Update(void *sourcePointer, ModeMask mode_mask);

	void
		ForceUpdate(T *sourcePointer, ModeMask mode_mask);

	T
		previousValue;
};

template <class T> Logical
	ControlsUpdateManager<T>::TestInstance() const
{
	return True;
}

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

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

template <class T> void
	ControlsUpdateManager<T>::Update(
		void * source_pointer,
		ModeMask mode_mask
	)
{
	Check(this);
	Check_Pointer(source_pointer);

	if (previousValue != *(T*) source_pointer)
	{
		ForceUpdate((T*)source_pointer, mode_mask);
	}
	Check_Fpu();
}

template <class T> void
	ControlsUpdateManager<T>::ForceUpdate(
		T* source_pointer,
		ModeMask mode_mask
	)
{
	Check(this);
	Check_Pointer(source_pointer);
	previousValue = *source_pointer;
	ControlsMappingGroup::Update(source_pointer, mode_mask);
	Check_Fpu();
}

template <class T> ControlsInstance*
	ControlsUpdateManager<T>::Add(
		ModeMask mode_mask,
		Receiver *receiver_pointer,
		Receiver::MessageID message_id,
		Plug *dependant
	)
{
	Check(this);
	Check(receiver_pointer);

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

template <class T> ControlsInstance*
	ControlsUpdateManager<T>::Add(
		ModeMask mode_mask,
		T *destination,
		Plug *dependant
	)
{
	Check(this);
	Check_Pointer(destination);

	ControlsInstanceDirectOf<T> *instance =
		new ControlsInstanceDirectOf<T>(
				mode_mask,
				destination,
				dependant
			);
	Register_Object(instance);
	ControlsMappingGroup::Add(instance);
	Check_Fpu();
	return instance;
}

template <class T> ControlsInstance*
	ControlsUpdateManager<T>::AddOrErase(
		ModeMask mode_mask,
		Receiver *receiver_pointer,
		Receiver::MessageID message_id,
		Plug *dependant
	)
{
	Check(this);
	Check(receiver_pointer);

	ChainIteratorOf<ControlsInstance*>
		i(instanceList);
	ControlsInstance
		*controls_instance;
	ControlsInstanceEventOf<T>
		*event_mapping;

	//-----------------------------------------------
	// Search through all mappings
	//-----------------------------------------------
	while ((controls_instance=i.ReadAndNext()) != NULL)
	{
		Check(controls_instance);
		//-----------------------------------------------
		// Process only the event mappings
		//-----------------------------------------------
		if (controls_instance->GetClassID() == EventControlsInstanceClassID)
		{
			event_mapping = (ControlsInstanceEventOf<T> *)controls_instance;
			Check(event_mapping);
			//-----------------------------------------------
			// Process only if the target is correct, AND
			// if the mapping is allowed under the given
			// mode mask
			//-----------------------------------------------
			if (
					(event_mapping->receiverPointer == receiver_pointer) &&
					(event_mapping->messageID == message_id) &&
					(event_mapping->modeMask & mode_mask)
				)
			{
				//-----------------------------------------------
				// Found! Remove mode enable bit(s)
				//-----------------------------------------------
				event_mapping->modeMask &= ~mode_mask;
				//-----------------------------------------------
				// If this mapping no longer matches ANY mode
				// (i.e., all bits cleared), delete it, 'cuz
				// it doesn't do anything anymore.
				//-----------------------------------------------
				if (event_mapping->modeMask == (ModeMask)0)
				{
					Unregister_Object(event_mapping);
					delete event_mapping;
				}
				//-----------------------------------------------
				// We found the match, break out of the loop
				//-----------------------------------------------
				break;
			}
		}
	}

	//----------------------------------------------------------
	// If the mapping wasn't found (controls_instance == NULL),
	// then create one.
	//----------------------------------------------------------
	if (controls_instance == NULL)
	{
		event_mapping =
			new ControlsInstanceEventOf<T>(
					mode_mask,
					receiver_pointer,
					message_id,
					dependant
				);
		Register_Object(event_mapping);
		ControlsMappingGroup::Add(event_mapping);
		Check_Fpu();
		return event_mapping;
	}
	Check_Fpu();
	return NULL;
}

template <class T> ControlsInstance*
	ControlsUpdateManager<T>::AddOrErase(
		ModeMask mode_mask,
		T *destination,
		Plug *dependant
	)
{
	Check(this);
	Check_Pointer(destination);

	ChainIteratorOf<ControlsInstance*>
		i(instanceList);
	ControlsInstance
		*controls_instance;
	ControlsInstanceDirectOf<T>
		*direct_mapping;

	//-----------------------------------------------
	// Search through all mappings
	//-----------------------------------------------
	while ((controls_instance=i.ReadAndNext()) != NULL)
	{
		Check(controls_instance);
		//-----------------------------------------------
		// Process only the direct mappings
		//-----------------------------------------------
		if (controls_instance->GetClassID() == DirectControlsInstanceClassID)
		{
			direct_mapping = (ControlsInstanceDirectOf<T> *)controls_instance;
			Check(direct_mapping);
			//-----------------------------------------------
			// Process only if the target is correct, AND
			// if the mapping is allowed under the given
			// mode mask
			//-----------------------------------------------
			if (
					(direct_mapping->dataPointer == destination) &&
					(direct_mapping->modeMask & mode_mask)
				)
			{
				//-----------------------------------------------
				// Found! Remove mode enable bit(s)
				//-----------------------------------------------
				direct_mapping->modeMask &= ~mode_mask;
				//-----------------------------------------------
				// If this mapping no longer matches ANY mode
				// (i.e., all bits cleared), delete it, 'cuz
				// it doesn't do anything anymore.
				//-----------------------------------------------
				if (direct_mapping->modeMask == (ModeMask)0)
				{
					Unregister_Object(direct_mapping);
					delete direct_mapping;
				}
				//-----------------------------------------------
				// We found the match, break out of the loop
				//-----------------------------------------------
				break;
			}
		}
	}
	//----------------------------------------------------------
	// If the mapping wasn't found (controls_instance == NULL),
	// then create one.
	//----------------------------------------------------------
	if (controls_instance == NULL)
	{
		direct_mapping =
			new ControlsInstanceDirectOf<T>(
					mode_mask,
					destination,
					dependant
				);
		Register_Object(direct_mapping);
		ControlsMappingGroup::Add(direct_mapping);
		Check_Fpu();
		return direct_mapping;
	}
	Check_Fpu();
	return NULL;
}

template <class T> int
	ControlsUpdateManager<T>::GetMapState(
		void *direct_destination,
		Receiver *event_receiver,
		Receiver::MessageID message_id,
		ModeMask mode_mask
	)
{
	Check(this);

	ChainIteratorOf<ControlsInstance*>
		i(instanceList);
	ControlsInstance
		*controls_instance;
	int
		map_state = 0; 

	//-----------------------------------------------
	// Search through all mappings
	//-----------------------------------------------
	while ((controls_instance=i.ReadAndNext()) != NULL)
	{
		Check(controls_instance);
		//------------------------------------
		// Process if allowed mode
		//------------------------------------
		if (controls_instance->modeMask & mode_mask)
		{
			//------------------------------------
			// Process direct mappings
			//------------------------------------
			if (controls_instance->GetClassID() ==
					DirectControlsInstanceClassID
				)
			{
				ControlsInstanceDirectOf<T>
					*direct_mapping = (ControlsInstanceDirectOf<T> *)
						controls_instance;

				Check(direct_mapping);
				if (direct_mapping->dataPointer == direct_destination)
				{
					map_state |= mappedByMe;
				}
				else
				{
					map_state |= mappedByOthers;
				}
			}
			//------------------------------------
			// Process event mappings
			//------------------------------------
			else
			{
				Verify(controls_instance->GetClassID() ==
						EventControlsInstanceClassID
				);

				ControlsInstanceEventOf<T>
					*event_mapping = (ControlsInstanceEventOf<T> *)
						controls_instance;

				Check(event_mapping);
				if (
						(event_mapping->receiverPointer == event_receiver) &&
						(event_mapping->messageID == message_id)
					)
				{
					map_state |= mappedByMe;
				}
				else
				{
					map_state |= mappedByOthers;
				}
			}
		}
	}
	Check_Fpu();
	return map_state;
}

//#########################################################################
//############################ ControlsManager ############################
//#########################################################################
class ControlsManager:
	public Receiver
{
	friend class ControlsMappingGroup;	// for access to groupEnable
	//-------------------------------------------------------------------
	// Shared data support
	//-------------------------------------------------------------------
public:
	static Derivation *GetClassDerivations();
//		static SharedData DefaultData;

	//-------------------------------------------------------------------
	// Construction/destruction/verification
	//-------------------------------------------------------------------
protected:      
	ControlsManager(
		ClassID class_ID = ControlsManagerClassID,
		SharedData &shared_data = ControlsManager::DefaultData
	);
public:
	~ControlsManager();

	unsigned int
		UniqueOwnerID()
			{
				if ((nextOwnerID+1)==0) { ++nextOwnerID; }
				Check_Fpu();
				return (++nextOwnerID);
			}

	virtual void
		Remove(ModeMask mode_mask);

	virtual void
		Execute();

	static Logical
		TestClass();

	Logical
		TestInstance() const;

	static void
		Shutdown();

	virtual void
		LocalShutdown();

	//-------------------------------------------------------------------
	// Mode control
	//-------------------------------------------------------------------
	virtual void
		StartMappableButtonsConfigure(
			void *active_direct_target,
			Receiver *target,
			Plug *dependant,
			Receiver::MessageID active_message_id,
			ModeMask remove_mode_mask,
			ModeMask add_mode_mask
		);

	virtual void
		StopMappableButtonsConfigure(
			ModeMask remove_mode_mask,
			ModeMask add_mode_mask
		);

	virtual void
		AddOrEraseMappableButton(
			int button_number,
			ModeMask mode_mask
		);
	//-------------------------------------------------------------------
	// Gauge support
	//-------------------------------------------------------------------
	void
		*activeDestination;
	Receiver
		*activeReceiver;
	Receiver::MessageID
		activeMessageID;
	Plug
		*activeDependant;

private:
	static ControlsManager
		*headControlsManager;

	ControlsManager
		*nextControlsManager;

	static unsigned int
		nextOwnerID;
};


//#########################################################################
//############################ ControlsMapping ############################
//#########################################################################
// Used by tools for building/reading control map streams
struct ControlsMapping
{
public:
	enum {
		DirectMapping=0,
		EventMapping=1
	};

	Enumeration
		controlsGroup,
		controlsElement,
		mappingType,
		subsystemID;
	ModeMask
		modeMask;
	union
	{
		Simulation::AttributeID attributeID;
		Receiver::MessageID messageID;
	};
};

//#########################################################################
//############################ ControlsString #############################
//#########################################################################

typedef int ControlsStringID;

class ControlsString :
	public  Node
{
	friend class ControlsStringManager;
protected:

	enum
	{
		maxStringLength=16
	};

	ControlsString(
		const char *new_string,
		int keypad_unit_number,
		Receiver *receiver_pointer,
		Receiver::MessageID message_id,
		int user_code
	);
	~ControlsString();

	Logical
		TestInstance() const;
	void
		Update(int keypad_unit_number, ControlsKey new_key);

	ControlsStringID
		id;
	const char
		*matchStringPointer;
	char
		string[maxStringLength+1];
	int
		stringLength,
		keypadUnitNumber,
		userCode;
	Receiver
		*receiverPointer;
	Receiver::MessageID
		messageID;

	static ControlsStringID
		nextID;
};



//#########################################################################
//######################## ControlsStringMessage ##########################
//#########################################################################
// This is sent by the controlsString object when a match is detected

class ControlsStringMessage:
	public Receiver::Message
{
public:
	ControlsStringMessage(
		Receiver::MessageID message_ID,
		int user_code
	):
		Receiver::Message(message_ID, sizeof(ControlsStringMessage)),
		userCode(user_code)
			{}

	int
		userCode;
};

//#########################################################################
//######################## ControlsStringManager ##########################
//#########################################################################
// This class matches strings from a keypad.  When the given string
// is matched, it sends an event to the given receiver.

class ControlsStringManager :
	public Node
{
public:
	ControlsStringManager();
	~ControlsStringManager();

	Logical
		TestInstance() const;

	ControlsStringID
		Add(
			const char *new_string,
			int keypad_unit_number,
			Receiver *receiver_pointer,
			Receiver::MessageID id,
			int user_code = 0
		);
	void
		Remove(ControlsStringID string_id);

	void
		Update(int keypad_unit_number, ControlsKey new_key);

	ChainOf<ControlsString*>
		instanceList;
};
