/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MODULE NAME		SingleMtxDest.DLL

USED BY			BBC Academy Wood Norton BNCS installation.

VERSION			1.0
DATE			14th April 2017
PROGRAMMER		Andy Woodhouse

Overview
========
This module implements a combination of destination selection button and source mimic for use in
building panels that control a single layer of matrix (eg sdi only, or audio only).

The panel designer enters a instance name, a database id for name lookup, a statesheet for button
highlighted as active, and the statesheet when the button is not active into the script host.

The component uses the designer selected instance to find the matrix and destination it represents.
The matrix id is used to extract the name from the dev_xxx.ini detination database, using the 
database number entered in the script host parameter field. The panel designer can enter a
database number to use, or leave the selection at the default value of 1. The component uses the
services of another component, MtxDestMimic, that shows the current routed source name. When
SingleMtxDest receives an instance name, is sends that name to MtxDestMimic so that it can
register for revertives and poll for the current setting.

When the button is pressed, the component tells the host the destination value it extracted from
the instance name. This value should be sent to the other selectors in the panel as well as itself.
When the component receives a destination value it compares the destination id with its own 
destination. If these match, the component sets the highlight state provided by the design-time
date. If the button destination does not match, or if the value is -1, the highlight is removed.

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */

#include <windows.h>
#include <stdio.h>
#include <bncs_string.h>
#include <bncs_config.h>
#include "SingleMtxDest.h"

#define MY_PANEL	1
#define PANEL_NAME	"mtxDest.bncs_ui"
#define BTTNNAME	"myDest"
#define UMDNAME		"srcMimic"

#define BNCS_DRV_MIN 1
#define BNCS_DRV_MAX 999
#define BNCS_DEST_MIN 1

// Make our class visible to the outside world
EXPORT_BNCS_SCRIPT(SingleMtxDest)

////////////////////////////////////////////////
// Constructor - equivalent to ApplCore STARTUP
SingleMtxDest::SingleMtxDest( bncs_client_callback * parent, const char * path ) : bncs_script_helper( parent, path )
{
	// Initialise our working storage.
	m_instance = "";			// Set instance name to null string
	myBtnDeselectState = "";	// Statesheet name for selected state
	myBtnSelectState = "";		// Statesheet name for deselected state
	myMatrixID = 0;				// Set invalid BNCS driver ID for matrix number
	myDestID = -1;				// Set invalid BNCS destination ID for our destination
	myNamesDatabase = 1;		// Database id for destination name fetch
	iAmSelected = false;		// We are not currently selected

	// Show our intelligent button and mimic panel
	panelShow(MY_PANEL, PANEL_NAME);
}


/////////////////////////////////////////////////
// Destructor - equivalent to ApplCore CLOSEDOWN
SingleMtxDest::~SingleMtxDest()
{
	if (myMatrixID != 0) routerUnregister(myMatrixID);
}


/////////////////////////////////////////////////
// All button pushes and notifications come here
void SingleMtxDest::buttonCallback(buttonNotify *b)
{
	// Be defensive - check panel_id and button_id of sender
	if ((b->panel() == MY_PANEL) && (b->id() == BTTNNAME))
	{
		if (myDestID > BNCS_DEST_MIN)	// Only send reports for valid destination IDs
		{
			hostNotify(bncs_string("selected=%1").arg(myDestID));
		}
	}
}

// All revertives come here
int SingleMtxDest::revertiveCallback(revertiveNotify *r)
{
	// No revertives for this element.

	return 0;	// Default safe return.
}


////////////////////////////////////////////
// All database name changes come back here
void SingleMtxDest::databaseCallback(revertiveNotify *r)
{
	// May have a destination name change to manage.
	if ((r->device() == myMatrixID) && (r->database() == myNamesDatabase) && (r->index() == myDestID))
	{
		// Database name change is for our destination button, so update the text name shown.
		textPut("text", r->sInfo(), MY_PANEL, BTTNNAME);
	}
}


//////////////////////////////////////////////////////////////////////////
// All parent notifications come here i.e. when this script is just one 
// component of another dialog then our host might want to tell us things
bncs_string SingleMtxDest::parentCallback( parentNotify *p )
{
	if (p->command() == "selected")
	{
		// Parent is telling us a selection destination value. If this ID is ours,
		// we must show the selected statesheet, if it is another destination or
		// -1 we must set the deselected state.

		if (p->value().toInt() == myDestID)
		{
			textPut("statesheet", myBtnSelectState, MY_PANEL, BTTNNAME);
			iAmSelected = true;
		}
		else
		{
			textPut("statesheet", myBtnDeselectState, MY_PANEL, BTTNNAME);
			iAmSelected = false;
		}

		return "";
	}

	else if( p->command() == "return" )
	{
		if( p->value() == "all" )
		{	
			// Persisting values for bncs_vis_ed
			bncs_stringlist sl;
			
			sl << bncs_string("namesDatabase=%1").arg(myNamesDatabase);
			sl << bncs_string("buttonlow=%1").arg(myBtnDeselectState);
			sl << bncs_string("buttonhigh=%1").arg(myBtnSelectState);
			sl << bncs_string("umdstatesheet=%1").arg(myUMDstatesheet);
			
			return sl.toString( '\n' );
		}
	}


	else if (p->command() == "instance" && p->value() != m_instance)
	{	
		// Our instance is being set or changed.
		int d_id = 0;
		int offset = 0;

		if ((myMatrixID >= BNCS_DRV_MIN) && (myMatrixID <= BNCS_DRV_MAX))
		{
			// Delete registration that we hold for database name change reports
			routerUnregister(myMatrixID);
		}

		m_instance = p->value();							// Save the new instance value
		textPut("instance", p->value(), MY_PANEL, UMDNAME);	// Notify the source mimic component

		myMatrixID = 0;				// Set safe values for destination ID 
		myDestID = -1;				// and matrix ID

		getDev(m_instance, &d_id, &offset);	// Get the new device and offset

		// Validate values and save to working variables
		if ((d_id >= BNCS_DRV_MIN) && (d_id <= BNCS_DRV_MAX) && (offset >= BNCS_DEST_MIN))
		{
			bncs_string destName = "";

			myMatrixID = d_id;	// Save the extracted router ID and destination ID
			myDestID = offset;

			// Get the destination name and place it on the button
			routerName(myMatrixID, myNamesDatabase, myDestID, destName);
			textPut("text", destName, MY_PANEL, BTTNNAME);

			// Register a destination so we get datbase name changes reported
			routerRegister(myMatrixID, 1,1);	
		}
		else
		{
			// Remove name from button, set deselected state
			textPut("text=Unknown|Destination", MY_PANEL, BTTNNAME);
			textPut("statesheet", myBtnDeselectState, MY_PANEL, BTTNNAME);
			hostNotify("selection=-1");
		}

	}	// end else if (p->command() == "instance" && p->value() != m_instance)

	
	else if (p->command() == "namesDatabase")
	{
		// Name database to use for destination is being changed
		if (p->value().toInt() > 0)
		{
			myNamesDatabase = p->value().toInt();
			// Validate values and save to working variables
			if ((myMatrixID >= BNCS_DRV_MIN) && (myMatrixID <= BNCS_DRV_MAX) && (myDestID >= BNCS_DEST_MIN))
			{
				bncs_string destName = "";

				// Get the destination name and place it on the button
				routerName(myMatrixID, myNamesDatabase, myDestID, destName);
				textPut("text", destName, MY_PANEL, BTTNNAME);
			}
		}
	}


	else if( p->command() == "buttonlow" )
	{	
		// Deselected state sheet name being set
		myBtnDeselectState = p->value();
		if (!iAmSelected)
		{
			// Update state sheet for button
			textPut("statesheet", myBtnDeselectState, MY_PANEL, BTTNNAME);
		}
	}


	else if (p->command() == "buttonhigh")
	{	
		// Selected state sheet name being set
		myBtnSelectState = p->value();
		
		if (iAmSelected)
		{
			// Update state sheet for button
			textPut("statesheet", myBtnSelectState, MY_PANEL, BTTNNAME);
		}
	}

	else if (p->command() == "umdstatesheet")
	{
		// umd state sheet name being set
		myUMDstatesheet = p->value();									// Keep local copy
		textPut("myStatesheet", myUMDstatesheet, MY_PANEL, UMDNAME);	// Update state sheet for button
	}


	// ***** CONNECTIONS EVENTS HELPER LIST *****
	else if( p->command() == "_events" )
	{	// Helper-list of everything in this component generated by hostNotify's
		bncs_stringlist sl;

		sl << "selected=*";		
		
		return sl.toString( '\n' );
	}

	// ***** CONNECTIONS COMMANDS HELPER LIST *****
	else if( p->command() == "_commands" )
	{	// Helper-list of any commands/parameters you might want to set at run-time
		bncs_stringlist sl;
		
		sl << "selected=[value]";
		
		return sl.toString( '\n' );
	}

	return "";
}

/////////////////////////////////////////
// Timer events come here
// No timers used - minimse catchall code
void SingleMtxDest::timerCallback(int id)
{
		timerStop(id);
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////// Callbacks above - Methods below ///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////


