#include "munga.h"
#pragma hdrstop

#include "controls.h"
#include "app.h"

#if defined(DEBUG)
#	define Test_Tell(n) DEBUG_STREAM << n
#else
#	define Test_Tell(n)
#endif

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

ControlsInstance::ControlsInstance(
	ClassID class_ID,
	ModeMask mode_mask,
	Plug *dependant
):
	Node(class_ID),
	dependantPlug(this)
{
	Check_Pointer(this);
	modeMask = mode_mask;
	dependantPlug.Add(dependant);

	Check_Fpu();
}

ControlsInstance::~ControlsInstance()
{
	Check(this);
	Check_Fpu();
}

void
	ControlsInstance::Update(void *)
{
	Fail("ControlsInstance::Update not overridden!");
}

//
//#############################################################################
//#############################################################################
//
void
	ControlsInstance::ReleaseLinkHandler(
		Socket*,
		Plug*
	)
{
	Unregister_Object(this);
	delete this;
	Check_Fpu();
}

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

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

ControlsMappingGroup::ControlsMappingGroup():
	Node(ControlsMappingGroup::ControlsMappingGroupClassID),
	instanceList(this)
{
	Check_Pointer(this);
	Check_Fpu();
}

ControlsMappingGroup::~ControlsMappingGroup()
{
	Check(this);
	Remove(0);		// remove all mappings
	Check_Fpu();
}

void ControlsMappingGroup::Remove(ModeMask mode_mask)
{
	Check(this);

	ChainIteratorOf<ControlsInstance*>
		i(instanceList);

	ControlsInstance
		*controls_instance;

	while ((controls_instance=i.ReadAndNext()) != NULL)
	{
		Check(controls_instance);
		//---------------------------------------------
		// Remove mapping bit(s)
		//---------------------------------------------
		controls_instance->modeMask &= ~mode_mask;
		//---------------------------------------------
		// If no bits left, delete mapping
		//---------------------------------------------
		if (controls_instance->modeMask == (ModeMask)0)
		{
			Unregister_Object(controls_instance);
			delete controls_instance;
		}
	}
	Check_Fpu();
}

void
	ControlsMappingGroup::Update(void *data_source, ModeMask mode_mask)
{
	Check(this);
	Check_Pointer(data_source);

	ChainIteratorOf<ControlsInstance*>
		i(instanceList);

	ControlsInstance
		*controls_instance;

	while ((controls_instance=i.ReadAndNext()) != NULL)
	{
		//------------------------------------------------
		// Process only if at least one mode bit matches
		//------------------------------------------------
		Check(controls_instance);
		if (controls_instance->modeMask & mode_mask)
		{
			controls_instance->Update(data_source);
		}
	}
	Check_Fpu();
}

Logical
	ControlsMappingGroup::CurrentFilterStatus(ModeMask mode_mask)
{
	Check(this);

	ChainIteratorOf<ControlsInstance*>
		i(instanceList);

	ControlsInstance
		*controls_instance;

	while ((controls_instance=i.ReadAndNext()) != NULL)
	{
		Check(controls_instance);

		if (controls_instance->modeMask & mode_mask)
		{
			Check_Fpu();
			return True;
		}
	}
	Check_Fpu();
	return False;
}

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

//---------------------------------------------------------------------------
// Class derivation
//---------------------------------------------------------------------------
Derivation* ControlsManager::GetClassDerivations()
{
	static Derivation classDerivations(Receiver::GetClassDerivations(), "ControlsManager");
	return &classDerivations;
}

unsigned int
	ControlsManager::nextOwnerID=0;

ControlsManager
	*ControlsManager::headControlsManager = NULL;

//
//############################################################################
// ControlsManager
//
// Creator method
//----------------------------------------------------------------------------
// Enter: virtualDataPtr
//############################################################################
//
ControlsManager::ControlsManager(
	ClassID class_ID,
	SharedData &shared_data
):
	Receiver(
		class_ID,
		shared_data
	)
{
	activeDestination = NULL;
	activeReceiver = NULL;
	activeMessageID = (Receiver::MessageID) 0;
	activeDependant = NULL;
	//----------------------------------------------------
	// Add this object to the chain
	//----------------------------------------------------
	nextControlsManager = headControlsManager;
	headControlsManager = this;
	Check_Fpu();
}

//
//############################################################################
// ~ControlsManager
//
// Destructor method
//############################################################################
//
ControlsManager::~ControlsManager()
{
	//----------------------------------------------------
	// Unlink this object from the chain
	//----------------------------------------------------
	ControlsManager
		*controls_manager,
		*previous_controls_manager(NULL);

	//
	// Search for 'this' in the chain
	//
	for(
		controls_manager = headControlsManager;
		controls_manager != NULL;
		controls_manager = controls_manager->nextControlsManager
		)
	{
		if (controls_manager == this)
		{
			//
			// Found! head of list?
			//
			if (previous_controls_manager == NULL)
			{
				headControlsManager = nextControlsManager;
			}
			//
			// Not head, remove from chain
			//
			else
			{
				previous_controls_manager->nextControlsManager =
					nextControlsManager;
			}
			break;
		}
		//
		// Keep track of 'previous' object
		//
		previous_controls_manager = controls_manager;
	}
	Check_Fpu();
}

void
	ControlsManager::Remove(ModeMask /*mode_mask*/)
{
	Fail("ControlsManager::Remove should not be called!\n");
}

void
	ControlsManager::Execute()
{
	Fail("ControlsManager::Execute should not be called!\n");
}

void
	ControlsManager::StartMappableButtonsConfigure(
		void *active_direct_target,
		Receiver *target,
		Plug *dependant,
		Receiver::MessageID active_message_id,
		ModeMask remove_mode_mask,
		ModeMask add_mode_mask
	)
{
	Check(this);

	activeReceiver = target;
	activeMessageID = active_message_id;
	activeDestination = active_direct_target;
	activeDependant = dependant;

	Check(application);
	ModeManager
		*mode_manager = application->GetModeManager(); 
	Check(mode_manager); 

	mode_manager->RemoveModeMask(remove_mode_mask);
	mode_manager->AddModeMask(add_mode_mask);

	Check_Fpu();
}

void
	ControlsManager::StopMappableButtonsConfigure(
		ModeMask remove_mode_mask,
		ModeMask add_mode_mask
	)
{
	Check(this);

	Check(application);
	ModeManager
		*mode_manager = application->GetModeManager(); 
	Check(mode_manager); 

	mode_manager->RemoveModeMask(remove_mode_mask);
	mode_manager->AddModeMask(add_mode_mask);

	activeDestination = NULL;
	activeReceiver = NULL;
	activeMessageID = (Receiver::MessageID) 0;
	activeDependant = NULL;

	Check_Fpu();
}

void
	ControlsManager::AddOrEraseMappableButton(
		int /*button_number*/,
		ModeMask /*mode_mask*/
	)
{
	Check(this);
	Check_Fpu();
}

//
//############################################################################
// TestInstance
//
//############################################################################
//
Logical
	ControlsManager::TestInstance() const
{
	return IsDerivedFrom(*GetClassDerivations());
}

//
//############################################################################
// Shutdown
//
//############################################################################
//
void
	ControlsManager::Shutdown()
{
	ControlsManager
		*controls_manager;

	for(
		controls_manager = headControlsManager;
		controls_manager != NULL;
		controls_manager = controls_manager->nextControlsManager
		)
	{
		controls_manager->LocalShutdown();
	}
	Check_Fpu();
}

void
	ControlsManager::LocalShutdown()
{
	Check(this);
	Check_Fpu();
}

//#########################################################################
//############################# ControlsString ############################
//#########################################################################
int
	ControlsString::nextID = 1;

ControlsString::ControlsString(
	const char *new_string,
	int keypad_unit_number,
	Receiver *receiver_pointer,
	Receiver::MessageID message_id,
	int user_code
):
	Node(RegisteredClass::ControlsStringClassID)
{
	Test_Tell(
		"ControlsString creator('" new_string <<
		"'," << keypad_unit_number <<
		"," << receiver_pointer <<
		"," << message_id <<
		")\n"
	);
	Check_Pointer(this);
	Check_Pointer(new_string);
	Check(receiver_pointer);

	//----------------------------------------------
	// Assign unique ID
	//----------------------------------------------
	id = nextID++;
	matchStringPointer = new_string;
	keypadUnitNumber = keypad_unit_number; 
	//----------------------------------------------
	// Save message data
	//----------------------------------------------
	receiverPointer = receiver_pointer;
	messageID = message_id;
	userCode = user_code;
	//----------------------------------------------
	// Clear the buffer
	//----------------------------------------------
	string[0] = '\0';
	stringLength = 0;

	Check_Fpu();
}

ControlsString::~ControlsString()
{
	Test_Tell("ControlsString destructor\n");
	Check(this);
	Check_Fpu();
}

Logical
	ControlsString::TestInstance() const
{
	return True;
}

void
	ControlsString::Update(int keypad_unit_number, ControlsKey new_key)
{
	Test_Tell(
		"ControlsString::Update(" << keypad_unit_number <<
		"," << new_key <<
		"\n"
		);
	Check(this);

	//----------------------------------------------
	// Update only if proper keyboard unit
	//----------------------------------------------
	if (keypad_unit_number == keypadUnitNumber)
	{
		//--------------------------------------
		// Get string length
		//--------------------------------------
		Check_Pointer(matchStringPointer);
		int
			length = strlen(matchStringPointer);
		if (length > maxStringLength)
		{
			length = maxStringLength;
		}

		if (stringLength > length)		// in case matchString changes
		{
			stringLength = length;
			string[stringLength] = '\0';
		}
		//--------------------------------------
		// Update string buffer
		//--------------------------------------
		if (stringLength < length)
		{
			string[stringLength++] = (char) new_key;
			string[stringLength] = '\0';
		}
		else
		{
			if (length > 1)
			{
				memmove(&string[0],&string[1], length-1);
			}
			string[length-1] = (char) new_key;
		}
		Test_Tell("string=" << string << "\n");
		//--------------------------------------
		// Check for match
		//--------------------------------------
		if (strnicmp(string, matchStringPointer, length) == 0)
		{
			Test_Tell(
				"ControlsString::Update, '" << matchStringPointer <<
				"' matched!\n"
			);
			//--------------------------------------
			// Match found, send message
			//--------------------------------------
			Check(receiverPointer);
			Check(application);

			ControlsStringMessage
				message(messageID, this->userCode);
			receiverPointer->Dispatch(&message);
			//--------------------------------------
			// Clear the string
			//--------------------------------------
			string[0] = '\0';
			stringLength = 0;
		}
	}
	Check_Fpu();
}

//#########################################################################
//######################## ControlsStringManager ##########################
//#########################################################################
ControlsStringManager::ControlsStringManager() :
	Node(RegisteredClass::ControlsStringManagerClassID),
	instanceList(this)
{
	Test_Tell("ControlsStringManager creator\n");
	Check_Pointer(this);
}

ControlsStringManager::~ControlsStringManager()
{
	Test_Tell("ControlsStringManager destructor\n");
	Check(this);
	//----------------------------------------------
	// Remove all ControlStrings
	//----------------------------------------------
	Remove(0);

	Check_Fpu();
}

Logical
	ControlsStringManager::TestInstance() const
{
	return True;
}

ControlsStringID
	ControlsStringManager::Add(
		const char *new_string,
		int keypad_unit_number,
		Receiver *receiver_pointer,
		Receiver::MessageID message_id,
      int user_code
	)
{
	Test_Tell("ControlsStringManager::Add(" << new_string <<
		"," << keypad_unit_number <<
		"," << receiver_pointer <<
		"," << message_id <<
		"\n"
	);
	Check(this);
	Check_Pointer(new_string);
	Check(receiver_pointer);

	//----------------------------------------------
	// Create the ControlsString
	//----------------------------------------------
	ControlsString
		*string_item = new ControlsString(
			new_string,
			keypad_unit_number,
			receiver_pointer,
			message_id,
			user_code
		);
	Check(string_item);
	Register_Object(string_item);
	//----------------------------------------------
	// Add to the instance list
	//----------------------------------------------
	instanceList.Add(string_item);
	//----------------------------------------------
	// return the new string's (unique) ID
	//----------------------------------------------
	Check_Fpu();
	return string_item->id;
}

void
	ControlsStringManager::Remove(ControlsStringID string_id)
{
	Test_Tell("ControlsStringManager::Remove(" << string_id << ")\n");
	Check(this);

	ChainIteratorOf<ControlsString*>
		i(instanceList);

	ControlsString
		*controls_string;

	//----------------------------------------------
	// Search for the given ID (or universal match)
	//----------------------------------------------
	while ((controls_string=i.ReadAndNext()) != NULL)
	{
		Check(controls_string);
		if (
				(string_id == 0) ||
				(controls_string->id == string_id)
			)
		{
			Unregister_Object(controls_string);
			delete controls_string;
			//------------------------------------------
			// If this is not a 'universal' remove,
			// we're done (ID's are unique)
			//------------------------------------------
			if (string_id != 0)
			{
				break;
			}
		}
	}
	Check_Fpu();
}

void
	ControlsStringManager::Update(
		int keypad_unit_number,
		ControlsKey new_key
	)
{
	Test_Tell("ControlsStringManager::Update(" << keypad_unit_number <<
		"," << new_key <<
		")\n"
	);
	Check(this);

	//--------------------------------------
	// Update all matching string items
	//--------------------------------------
	ChainIteratorOf<ControlsString*>
		i(instanceList);

	ControlsString
		*controls_string;

	while ((controls_string=i.ReadAndNext()) != NULL)
	{
		Check(controls_string);
		controls_string->Update(keypad_unit_number, new_key);
	}
	Check_Fpu();
}


#if defined(TEST_CLASS)
	#include "controls.tcp"
#endif
