/*
PROGRAM NAME	CAR\video_xy.DLL

USED BY			BBC Academy Wood Norton BNCS installation.

VERSION			1.0
DATE			6th April 2015
PROGRAMMER		Andy Woodhouse

Overview
========
This DLL implements a X-Y router for the CAR SDI 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	(Uses 0001 to 0012)
Destination Maps		0101 to 0199	(Uses 0101 to 0112)
Source Group Maps		0201 to 0250	(Just uses 0201)
Destination Groups Maps	0251 to 0300	(Just uses 0251)

*/

#include <windows.h>
#include <stdio.h>
#include <bncs_string.h>
#include <bncs_config.h>
#include "video_xy.h"

#define MAIN_PANEL	1
#define MAIN_PANEL_NAME "car_vidxy.bncs_ui"
#define ROUTERNAME		"CAR SDI Router"		// As used in Instances.xml

#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( video_xy )


// ++++++++++++++++++++++++++++++++++++++++++++ //
// Constructor - equivalent to ApplCore STARTUP //
// ++++++++++++++++++++++++++++++++++++++++++++ //
video_xy::video_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 a panel from file p1.bncs_ui and we'll know it as our panel PNL_MAIN
	panelShow(MAIN_PANEL, MAIN_PANEL_NAME);
	if (take_enabled) controlEnable(MAIN_PANEL, "Take");
	else controlDisable(MAIN_PANEL, "Take");

	// Get the device number for the B4 SDI instance
	getDev(ROUTERNAME, &matrix_id);
	if (matrix_id != 0)
	{
		routerRegister(matrix_id, 1, MATRIXSIZE);
		routerPoll(matrix_id, 1, MATRIXSIZE);
	}
}


// +++++++++++++++++++++++++++++++++++++++++++++ //
// Destructor - equivalent to ApplCore CLOSEDOWN //
// +++++++++++++++++++++++++++++++++++++++++++++ //
video_xy::~video_xy()
{
}

// all button pushes and notifications come here
void video_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 video_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 video_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 video_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 video_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 video_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");
		}
	}

}
