/*
PROGRAM NAME	B4\audio_xy.DLL

USED BY			BBC Academy Wood Norton BNCS installation.

VERSION			1.0
DATE			12th March 2015
PROGRAMMER		Andy Woodhouse

Overview
========
This DLL implements a X-Y router for the B4 audio router.

Requirements:
Database 5 and Database 6 of the selected instance hold the names for the groups.
Database 8 configured for mapping:
Source Maps				0001 to 0099
Destination Maps		0101 to 0199
Source Group Maps		0201 to 0250
Destination Groups Maps	0251 to 0300

*/

#include <windows.h>
#include <stdio.h>
#include <bncs_string.h>
#include <bncs_config.h>
#include "audio_xy.h"

#define MAIN_PANEL	1
#define MAIN_PANEL_NAME "audio_xy.bncs_ui"
#define ROUTERNAME		"CAR Audio Router"

#define TAKE_HIGH "WN_TakeHigh"
#define TAKE_LOW "WN_TakeLow"
#define TAKE_TIMER	1
#define TAKE_TIMEOUT 10

// ++++++++++++++++++++++++++++++++++++++++++++ //
// Make our class visible to the outside world. //
// ++++++++++++++++++++++++++++++++++++++++++++ //
EXPORT_BNCS_SCRIPT(audio_xy)


// ++++++++++++++++++++++++++++++++++++++++++++ //
// Constructor - equivalent to ApplCore STARTUP //
// ++++++++++++++++++++++++++++++++++++++++++++ //
audio_xy::audio_xy(bncs_client_callback *parent, const char *path) : bncs_script_helper(parent, path)
{
	// Initialise variables
	matrix_id = 0;
	source_id = -1;
	dest_id = -1;
	take_timeout = 0;
	for (int i = 0; i <= MATRIXSIZE; i++) matrix_state[i] = 0;

	source_selected = false;
	dest_selected = false;
	take_enabled = false;					// Want the TAKE button disabled
	take_timer_enabled = false;

	// Show our panel.
	panelShow(MAIN_PANEL, MAIN_PANEL_NAME);
	if (take_enabled) controlEnable(MAIN_PANEL, "Take");
	else controlDisable(MAIN_PANEL, "Take");

	// Get the device number for the CAR Audio instance
	getDev(ROUTERNAME, &matrix_id);
	if (matrix_id != 0)
	{
		routerRegister(matrix_id, 1, MATRIXSIZE);
		routerPoll(matrix_id, 1, MATRIXSIZE);
	}
}	// End of Constructor


// +++++++++++++++++++++++++++++++++++++++++++++ //
// Destructor - equivalent to ApplCore CLOSEDOWN //
// +++++++++++++++++++++++++++++++++++++++++++++ //
audio_xy::~audio_xy()
{
}

// all button pushes and notifications come here
void audio_xy::buttonCallback( buttonNotify *b )
{
	if (b->panel() == MAIN_PANEL)
	{
		if (b->id() == "Sources")
		{
			// User has selected (or deselected!) a source. Update displayed tally data

			source_id = b->value().toInt();	// Extract the new source data
			if (source_id == -1)
			{
				textPut("text=-", MAIN_PANEL, "New");
				textPut("text=---", MAIN_PANEL, "NewSrcName");
				source_selected = false;
			}
			else
			{
				bncs_string sourcename;

				textPut("text", bncs_string("%1").arg(source_id), MAIN_PANEL, "New");	// Show the "Old" source number
				routerName(matrix_id, 0, source_id, sourcename);
				textPut("text", sourcename, MAIN_PANEL, "NewSrcName");
				source_selected = true;
			}

			// Check for both source and destination being selected.
			checkSrcDest();

			return;
		}	// End of if (b->id() == "Sources")


		if (b->id() == "Destinations")
		{
			// User has selected (or deselected!) a destination. Update displayed tally data
			dest_id = b->value().toInt();	// Extract the new destination data
		
			if (dest_id == -1)
			{
				textPut("text=-", MAIN_PANEL, "Did");
				textPut("text=---", MAIN_PANEL, "DestName");
				textPut("text=-", MAIN_PANEL, "Old");
				textPut("text=---", MAIN_PANEL, "OldSrcName");
				dest_selected = false;
			}
			else
			{
				bncs_string destname, srcname;

				// Update the destination tally displays
				textPut("text", bncs_string("%1").arg(dest_id), MAIN_PANEL, "Did");
				routerName(matrix_id, 1, dest_id, destname);
				textPut("text", destname, MAIN_PANEL, "DestName");

				// Update the old source tally displays
				textPut("text", bncs_string("%1").arg(matrix_state[dest_id]), MAIN_PANEL, "Old");
				routerName(matrix_id, 0, matrix_state[dest_id], srcname);
				textPut("text", srcname, MAIN_PANEL, "OldSrcName");
				dest_selected = true;
			}
			// Check for both source and destination selected
			checkSrcDest();

			return;
		}	// End of if (b->id() == "Sources")


		if (b->id() == "Take")
		{
			// Only enter here if there is a source and a destination selected.
			take_enabled = false;
			textPut("statesheet", TAKE_HIGH, MAIN_PANEL, "Take");
			controlDisable(MAIN_PANEL, "Take");
			if (take_timer_enabled)
			{
				timerStop(TAKE_TIMER);
				take_timer_enabled = false;
			}

			// Action the TAKE, if both source and destination IDs are positive values.
			if ((source_id > 0) && (dest_id > 0))
			{
				routerCrosspoint(matrix_id, source_id, dest_id);
				source_selected = false;
				source_id = 0;
				dest_selected = false;
				dest_id = 0;
				textPut("select=-1", MAIN_PANEL, "Sources");
				textPut("select=-1", MAIN_PANEL, "Destinations");
				textPut("text=-", MAIN_PANEL, "Old");
				textPut("text=-", MAIN_PANEL, "New");
				textPut("text=-", MAIN_PANEL, "Did");
				textPut("text=---", MAIN_PANEL, "OldSrcName");
				textPut("text=---", MAIN_PANEL, "NewSrcName");
				textPut("text=---", MAIN_PANEL, "DestName");
			}

			return;
		}

		if (b->id() == "Clear")
		{
			if (take_enabled)
			{
				textPut("statesheet", TAKE_HIGH, MAIN_PANEL, "Take");
				controlDisable(MAIN_PANEL, "Take");
				take_enabled = false;
			}

			if (take_timer_enabled)
			{
				timerStop(TAKE_TIMER);
				take_timer_enabled = false;
			}

			source_selected = false;
			source_id = 0;
			dest_selected = false;
			dest_id = 0;
			textPut("select=-1", MAIN_PANEL, "Sources");
			textPut("select=-1", MAIN_PANEL, "Destinations");
			textPut("text=-", MAIN_PANEL, "Old");
			textPut("text=-", MAIN_PANEL, "New");
			textPut("text=-", MAIN_PANEL, "Did");
			textPut("text=---", MAIN_PANEL, "OldSrcName");
			textPut("text=---", MAIN_PANEL, "NewSrcName");
			textPut("text=---", MAIN_PANEL, "DestName");

			return;
		}

	}	// End of if (b->panel() == MAIN_PANEL)
}

// +++++++++++++++++++++++++ //
// All revertives come here. //
// +++++++++++++++++++++++++ //
int audio_xy::revertiveCallback( revertiveNotify * r )
{

	if (r->device() == matrix_id)
	{
		// Record the source number on local array
		matrix_state[r->index()] = r->info();

		if (dest_selected)
		{
			if (r->index() == dest_id)
			{
				textPut("text", bncs_string("%1") .arg(r->info()), MAIN_PANEL, "Old");	// Show the "Old" source number
				textPut("text", r->sInfo(), MAIN_PANEL, "OldSrcName");
			}
		}
	}

	return 0;
}


// +++++++++++++++++++++++++++++++++++++++++ //
// All database name changes come back here. //
// +++++++++++++++++++++++++++++++++++++++++ //
void audio_xy::databaseCallback( revertiveNotify * r )
{
}


// +++++++++++++++++++++++++++++++++++++++++++++++++ //
// All parent notifications come here.               //
// When this script is just one component of another //
// dialog then our host might want to tell us things //
// +++++++++++++++++++++++++++++++++++++++++++++++++ //
bncs_string audio_xy::parentCallback( parentNotify *p )
{
	if( p->command() == "return" )
	{
		if( p->value() == "all" )
		{	// Persisting values for bncs_vis_ed
			bncs_stringlist sl="";
			
			return sl.toString( '\n' );
		}
	}

	// ***** CONNECTIONS EVENTS HELPER LIST *****
	else if( p->command() == "_events" )
	{	// Helper-list of everything in this component generated by hostNotify's
		bncs_stringlist sl = "";

		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 = "";
		return sl.toString( '\n' );
	}

	return "";
}

// timer events come here
void audio_xy::timerCallback( int id )
{
	switch( id )
	{
	case TAKE_TIMER:
		take_timeout--;
		if ((take_timeout & 1) == 0)
		{
			// take_timeout counter is an even number (lsb == 0)
			textPut("statesheet", TAKE_HIGH, MAIN_PANEL, "Take");
		}
		else
		{
			// take_timeout is an odd value
			textPut("statesheet", TAKE_LOW, MAIN_PANEL, "Take");
		}

		if (take_timeout == 0)
		{
			timerStop(TAKE_TIMER);
			take_timer_enabled = false;
			controlDisable(MAIN_PANEL, "Take");	// Disable the TAKE button
			take_enabled = false;
		}

		break;

	default:	// Unhandled timer event
		timerStop(id);
		break;
	}
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////// Callbacks above - Methods below ///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////

void audio_xy::checkSrcDest(void)
{

	if (source_selected && dest_selected)
	{
		// Take should be active
		if (take_enabled)
		{
			// Take was already enabled
			if (take_timer_enabled)
			{
				timerStop(TAKE_TIMER);
				take_timer_enabled = false;
				textPut("statesheet", TAKE_HIGH , MAIN_PANEL, "Take");
			}
		}

		// Set the TAKE burtton as enabled
		take_timeout = TAKE_TIMEOUT;		// Set the timeout period in the counter variable.
		controlEnable(MAIN_PANEL, "Take");	// Enable the TAKE button
		take_enabled = true;				// Keep a note of the state
		timerStart(TAKE_TIMER, 1000);		// Start the tiemout counter
		take_timer_enabled = true;			// Note that the timer is enabled
	}
	else
	{
		// Take should be inactive.
		if (take_enabled)
		{
			textPut("statesheet", TAKE_HIGH, MAIN_PANEL, "Take");
			controlDisable(MAIN_PANEL, "Take");
			take_enabled = false;
		}
		if (take_timer_enabled)
		{
			timerStop(TAKE_TIMER);
			take_timer_enabled = false;
			textPut("statesheet", TAKE_HIGH, MAIN_PANEL, "Take");
		}
	}

}
