#include <windows.h>
#include <stdio.h>
#include <bncs_string.h>
#include <bncs_config.h>
#include "CARHD.h"

#define PNL_MAIN	1

#define TIMER_SETUP	1
#define TAKE_ENABLED_TIMER 2
#define TAKE_FLASHER 3

#define SOURCEDATABASE 0
#define DESTDATABASE 1
#define CARHD_ROUTER_NAME	"CAR HD-SDI Router"

#define TAKE_LOW	"WN_TakeLow"
#define TAKE_HIGH	"WN_TakeHigh"
#define SOURCE_SELECTED	"WNSourceSelected"
#define SOURCE_DESELCTED "WNSourceDeselected"

// ++++++++++++++++++++++++++++++++++++++++++++ //
// Make our class visible to the outside world. //
// ++++++++++++++++++++++++++++++++++++++++++++ //
EXPORT_BNCS_SCRIPT( CARHD )


// ++++++++++++++++++++++++++++++++++++++++++++ //
// Constructor - equivalent to ApplCore STARTUP //
// ++++++++++++++++++++++++++++++++++++++++++++ //
CARHD::CARHD( bncs_client_callback * parent, const char * path ) : bncs_script_helper( parent, path )
{
	// Show a panel from file p1.bncs_ui and we'll know it as our panel PNL_MAIN
	panelShow(PNL_MAIN, "p1.bncs_ui" );

	// Ensure we have some "safe" default values
	car_hdsdi = 0;

	// Find the device number of the CAR SDI Router package names
	getDev(CARHD_ROUTER_NAME, &car_hdsdi);

	// Extract the classroom= parameter from the workstation file
	ws_sl = getWorkstationSetting("classroom").upper();

	// Set up the router parameters in the source selection buttons
	textPut("device", car_hdsdi, PNL_MAIN, "HD_SRC");		// Provide the router number to the control for names
	textPut("device.map", car_hdsdi, PNL_MAIN, "HD_SRC");	// and the control mapping

	// V4 and V11 have 3 OS destinations, V7 has 2. Hide the OS3 button if we are running in V7.
	if (ws_sl == "V7")
	{
		controlHide(PNL_MAIN, "OS3");		// Hide the OS3 selection button
		controlHide(PNL_MAIN, "23");		// Hide the UMD label
		controlHide(PNL_MAIN, "BG_3");		// Hide the backpanel for 3 OS panel
	}
	else
	{
		controlHide(PNL_MAIN, "BG_2");		// Hide the backpanel for 2 OS panel
	}

	// Get the first and last HD-SDI values from wn_academy.xml
	myVals = bncs_config("wn_academy." + ws_sl + ".car_hd_os_first");		// First SD OS destination
	myFirstSDIOS = myVals.attr("value").toInt(); 

	myVals = bncs_config("wn_academy." + ws_sl + ".car_hd_os_last");		// Last SD OS destination
	myLastSDIOS = myVals.attr("value").toInt();

	// Set initial variable values.
	source_selected = false;
	source_index = 0;
	dest_selected = false;
	dest_index = 0;
	takeEnabled = false;
	controlDisable(PNL_MAIN, "TAKE");

	// Register for revertives and poll destinations to get initial displays
	routerRegister(car_hdsdi, myFirstSDIOS, myLastSDIOS);					// SDI OS destinations
	routerPoll(car_hdsdi, myFirstSDIOS, myLastSDIOS);

}	// End of Constructor code

// ++++++++++++++++++++++++++++++++++++++++++++++ //
// Destructor - equivalent to ApplCore CLOSEDOWN. //
// ++++++++++++++++++++++++++++++++++++++++++++++ //
CARHD::~CARHD()
{
	// Do some tidy up processing
	if (takeEnabled)						// If take mode enabled stop the timers
	{
		timerStop(TAKE_FLASHER);
		timerStop(TAKE_ENABLED_TIMER);
	}

	routerUnregister(car_hdsdi);			// Unregister for devices for revertives
}


// ++++++++++++++++++++++++++++++++++++++++++++++ //
// All button pushes and notifications come here. //
// ++++++++++++++++++++++++++++++++++++++++++++++ //
void CARHD::buttonCallback( buttonNotify *b )
{
	if( b->panel() == PNL_MAIN )
	{
		
		if (b->id() == "HD_SRC")					// Source selection button pressed. Index in b->value()
		{
			if (b->value() > 0)
			{
				source_selected = true;
				source_index = b->value().toInt();
				checkTake();						// Do we need to enable the TAKE button?
			}
			else
			{
				source_selected = false;
				source_index = 0;
				// If TAKE is enabled - deselect it
				if (takeEnabled)
				{
					takeEnabled = false;
					textPut("stylesheet", TAKE_LOW, PNL_MAIN, "TAKE");
					timerStop(TAKE_FLASHER);
					timerStop(TAKE_ENABLED_TIMER);
					controlDisable(PNL_MAIN, "TAKE");
				}
			}

			return;
		}

		if (b->id() == "OS1")			// Destination OS1 pressed
		{
			if (dest_selected)
			{
				textPut("statesheet", SOURCE_DESELCTED, PNL_MAIN, selected_os);		// Clear old highlight
			}
			selected_os = b->id();													// Define new button
			dest_selected = true;
			dest_index = myFirstSDIOS;												// Note the active destination package number
			textPut("statesheet", SOURCE_SELECTED, PNL_MAIN, selected_os);			// Highlight the new active destination
			checkTake();

			return;
		}

		if (b->id() == "OS2")			// Destination OS2 pressed
		{
			if (dest_selected)
			{
				textPut("statesheet", SOURCE_DESELCTED, PNL_MAIN, selected_os);		// Clear old highlight
			}
			selected_os = b->id();													// Define new button
			dest_selected = true;
			dest_index = myFirstSDIOS + 1;											// Note the active destination package number
			textPut("statesheet", SOURCE_SELECTED, PNL_MAIN, selected_os);			// Highlight the new active destination
			checkTake();

			return;
		}

		if (b->id() == "OS3")			// Destination OS3 pressed
		{
			if (dest_selected)
			{
				textPut("statesheet", SOURCE_DESELCTED, PNL_MAIN, selected_os);		// Clear old highlight
			}
			selected_os = b->id();													// Define new button
			dest_selected = true;
			dest_index = myFirstSDIOS + 2;											// Note the active destination package number
			textPut("statesheet", SOURCE_SELECTED, PNL_MAIN, selected_os);			// Highlight the new active destination
			checkTake();

			return;
		}

		if (b->id() == "TAKE")			// Take button pressed
		{
			// Process the actions for the TAKE button. Note that the take button can only generate an event when both a source and
			// a destination have already been activated. 

			timerStop(TAKE_FLASHER);				// Stop the flasher timer
			timerStop(TAKE_ENABLED_TIMER);			// Stop the timeout timer
			textPut("stylesheet", TAKE_LOW, PNL_MAIN, "TAKE");
			controlDisable(PNL_MAIN, "TAKE");		// Disable the TAKE button

			// Make the crosspoints. Only need to issue a crosspoint command if both source and destination indicies
			// are greater than 0
			if ((source_index != 0) && (dest_index != 0))
			{
				routerCrosspoint(car_hdsdi, source_index, dest_index);
			}

			// Clear the sources, destinations, and flags
			textPut("index=0", PNL_MAIN, "HD_SRC");								// Clear source info
			textPut("statesheet", SOURCE_DESELCTED, PNL_MAIN, selected_os);		// Clear destination highlight
			source_selected = false;
			source_index = 0;
			selected_os = "";
			dest_selected = false;
			dest_index = 0;
			takeEnabled = false;

			return;
		}

		if (b->id() == "CANCEL")		// Cancel button pressed
		{
			if (source_selected)					// Is there an active source?
			{
				textPut("index=0", PNL_MAIN, "HD_SRC");
				source_selected = false;
				source_index = 0;
			}

			if (dest_selected)						// Is there an active destination?
			{
				textPut("statesheet", SOURCE_DESELCTED, PNL_MAIN, selected_os);		// Clear highlight
				selected_os = "";
				dest_selected = false;
				dest_index = 0;
			}

			// Check if TAKE button enabled - if so cancel it
			if (takeEnabled)
			{
				takeEnabled = false;
				textPut("stylesheet", TAKE_LOW, PNL_MAIN, "TAKE");
				timerStop(TAKE_FLASHER);
				timerStop(TAKE_ENABLED_TIMER);
				controlDisable(PNL_MAIN, "TAKE");
			}

			return;
		}

	}	// End of "if (b->panel() == 1)"
}	// End of button callback


// +++++++++++++++++++++++++ //
// All revertives come here. //
// +++++++++++++++++++++++++ //
int CARHD::revertiveCallback( revertiveNotify * r )
{
	if (r->device() == car_hdsdi)		// Process CAR HD-SDI Revertives
	{
		textPut("text", r->sInfo(), PNL_MAIN, (21 + r->index() - myFirstSDIOS));
	}

	return 0;
}


// +++++++++++++++++++++++++++++++++++++++++ //
// All database name changes come back here. //
// +++++++++++++++++++++++++++++++++++++++++ //
void CARHD::databaseCallback( revertiveNotify * r )
{
}


// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //
// 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 CARHD::parentCallback( parentNotify *p )
{
	if( p->command() == "return" )
	{
		if( p->value() == "all" )
		{	// Persisting values for bncs_vis_ed
			bncs_stringlist sl;
			
			sl << bncs_string( "myParam=%1" ).arg( m_myParam );
			
			return sl.toString( '\n' );
		}

		else if( p->value() == "myParam" )
		{	// Specific value being asked for by a textGet
			return( bncs_string( "%1=%2" ).arg( p->value() ).arg( m_myParam ) );
		}

	}
	else if( p->command() == "instance" && p->value() != m_instance )
	{	// Our instance is being set/changed
		m_instance = p->value();
		//Do something instance-change related here
	}

	else if( p->command() == "myParam" )
	{	// Persisted value or 'Command' being set here
		m_myParam = p->value();
	}

	// ***** CONNECTIONS EVENTS HELPER LIST *****
	else if( p->command() == "_events" )
	{	// Helper-list of everything in this component generated by hostNotify's
		bncs_stringlist sl;

		sl << "notify=*";		
		
		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 << "myParam=[value]";
		
		return sl.toString( '\n' );
	}

	return "";
}


// +++++++++++++++++++++++ //
// Timer events come here. //
// +++++++++++++++++++++++ //
void CARHD::timerCallback( int id )
{
	switch (id)
	{
	case TIMER_SETUP:
		timerStop(id);
		break;

	case TAKE_ENABLED_TIMER:
		if (takeEnabled)
		{
			timerStop(TAKE_ENABLED_TIMER);			// Stop the TAKE timeout counter
			timerStop(TAKE_FLASHER);				// Stop the take state toggle time
			textPut("statesheet", TAKE_HIGH, PNL_MAIN, "TAKE");
			controlDisable(PNL_MAIN, "TAKE");
			takeEnabled = false;
		}
		break;

	case TAKE_FLASHER:								// Toggle the bacground and text colours
		if (takeState)
			textPut("statesheet", TAKE_LOW, PNL_MAIN, "TAKE");
		else
			textPut("statesheet", TAKE_HIGH, PNL_MAIN, "TAKE");

		takeState = !takeState;
		break;

	default:	// Unhandled timer event
		timerStop(id);
		break;
	}
}	// End of timer callback.


///////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////// Callbacks above - Methods below ///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////


void CARHD::checkTake(void)
{
	// Enable the take button if there is both a source and a destination enabled
	if (source_selected && dest_selected)
	{
		controlEnable(PNL_MAIN, "TAKE");
		timerStart(TAKE_ENABLED_TIMER, 10000);		// Enable the timer for 10 seconds
		timerStart(TAKE_FLASHER, 1000);				// Enable the high/low state flash timer
		textPut("statesheet", TAKE_HIGH, PNL_MAIN, "TAKE");
		takeEnabled = true;
		takeState = false;
	}
}


