/*
PROGRAM NAME	SysControl.dll

USED BY			BBC Academy Studio A/CTA installation

VERSION			1.0
DATE			5th December 2014
PROGRAMMER		Andy Woodhouse

TARGET SCREEN SIZE	1024 x 768
        PANEL SIZE	1024 x 668

Overview
========
SysControl is a BNCS version 4.5 panel that is used to control the switching of the studio rehearse/transmit state.

Using Rehearse and Transmit buttons on the control panel the user can change the studio state between three conditions:
	
	State		Properties
	=====		==========
	Off			Comms System disabled, blue lights off, red lights off.
	Rehearse	Comms System enabled, blue lights on, red lights off.
	Transmit	Comms System enabled, blue lights off, red lights on.

	State		Action					New State
	=====		======					=========
	Off			Push Rehearse button	Rehearse	
	Off			Push Transmit button	Transmit
	Rehearse	Push Rehearse button	Off
	Rehearse	Push Transmit button	Transmit
	Transmit	Push Rehearse button	Rehearse

The control of the necessary relays is implemented by an automatic panel. The messaging between the SysControl panel
and the automatic is through a slot (slot 1) in the "Tally Infodriver" (BNCS Driver 661). The allowed values and their
meanings are:
	
	Value	State
	  0		Off
	  1		Rehearse
	  2		Transmit

There are three more slots in the "Tally Infodriver" that are used to drive indicators on this panel. Each slot indicates
which gallery is the controlling agency for the associated area. The control values are:

	Value	Meaning
	  0		Area control is unallocated
	  1		Area is controlled by Gallery A
	  2		Area is controlled by Gallery C

The infodriver slots that use the above codes and the associated areas are:

	Slot	Area
	  4		Studio A and B floor (also red and blue lights in studio galleries 
	  5		Studio C floor
	  6		Studio C News Studio

Setting the area allocations is done by another panel.

The other control feature that is enabled in the panel is switching the colour bars and stereo audio line-up tone to line output.


*/



#include <windows.h>
#include <stdio.h>
#include <bncs_string.h>
#include <bncs_config.h>
#include "SysControl.h"

#define PNL_MAIN	1

#define TIMER_SETUP	1

// Define the infodriver slots
#define STATESLOT 1			// Mode of Studio A
#define STA_VID_LINE 97		// SDI destination for Studio Line output
#define STA_AUD_LINE 62		// Audio destination for Studio Line Output
#define STA_BARS_LINE 98	// Source number for colour bars
#define STA_TONE_LINE 63	// Source number for Glits tone
#define STA_VMIX_OUT 1
#define STA_AMIX_OUT 1

// Define the value indications in the area control slots
#define STATE_OFF 0
#define STATE_REH 1
#define STATE_TX 2

// this nasty little macro to make our class visible to the outside world
EXPORT_BNCS_SCRIPT( SysControl )

// constructor - equivalent to ApplCore STARTUP
SysControl::SysControl( bncs_client_callback * parent, const char * path ) : bncs_script_helper( parent, path )
{
	// Initialise local variables
	currentState = 0;					// The current Off/Reh/Tx state value
	tallyInfodriver = 0;				// BNCS driver id for tally infodiver
	sdiRouterdriver = 0;				// BNCS driver id for the SDI router
	audioRouterdriver = 0;				// BNCS driver id for the audio router
	defaultAudio = STA_AMIX_OUT;		// Assume initial default to line sources of studio mixer outputs
	defaultVideo = STA_VMIX_OUT;
	lineupAllowed = true;				// Flag to indicate if bars to line or tone to line allowed
	tallyReg = false;					// Flags to show if driver is registered. Used by destructor code
	SDIReg = false;
	audioReg = false;
	video_to_line = false;				// Set true when revertive reports audio line output source is colour bars
	audio_to_line = false;				// Set true when revertive reports audio line output source is Glits

	// Show the panel SysControl.bncs_ui We'll know it as our panel PNL_MAIN
	panelShow( PNL_MAIN, "SysControl.bncs_ui" );

	// Get the driver numbers from instances.xml and register for revertives.
	getDev("CTA Tally Infodriver", &tallyInfodriver);				// Tally infodriver
	infoRegister(tallyInfodriver, STATESLOT, STATESLOT);			// Register for current Tx status
	tallyReg = true;
	
	getDev("CTA SDI Router", &sdiRouterdriver);						// Read CTA SD-SDI router driver ID
	routerRegister(sdiRouterdriver, STA_VID_LINE, STA_VID_LINE);
	SDIReg = true;
	
	getDev("CTA Audio Router", &audioRouterdriver);					// Read CTA stereo audio router driver ID
	routerRegister(audioRouterdriver, STA_AUD_LINE, STA_AUD_LINE);
	SDIReg = true;

	infoPoll(tallyInfodriver, STATESLOT, STATESLOT);				// Ask for current state
	routerPoll(sdiRouterdriver, STA_VID_LINE, STA_VID_LINE);		// Check current line output setting
	routerPoll(audioRouterdriver, STA_AUD_LINE, STA_AUD_LINE);
}

// +++++++++++++++++++++++++++++++++++++++++++++ //
// Destructor - equivalent to ApplCore CLOSEDOWN //
// +++++++++++++++++++++++++++++++++++++++++++++ //
SysControl::~SysControl()
{
	if (tallyReg) infoUnregister(tallyInfodriver);
	if (SDIReg) routerUnregister(sdiRouterdriver);
	if (audioReg) routerUnregister(audioRouterdriver);
}

// +++++++++++++++++++++++++++++++++++++++++++++ //
// All button pushes and notifications come here //
// +++++++++++++++++++++++++++++++++++++++++++++ //
void SysControl::buttonCallback( buttonNotify *b )
{
	// There are 4 buttons that require servicing - "Reh", "TX", "Bars", "Tone". These all exist on PNL_MAIN.
	
	if( b->panel() == PNL_MAIN )
	{
		// The action of the Rehearse button depends on the current state of the studio. If Rehearse mode is active, then the
		// mode is set to off. If the current mode is off or transmit, the mode is set to rehearse. If we were in TX mode, then
		// the bars and tone to line buttons must be re-activated.
		if (b->id() == "Reh")
		{
			if (currentState == STATE_REH)
			{
				infoWrite(tallyInfodriver, STATE_OFF, STATESLOT);
				return;
			}

			if (currentState==STATE_OFF)
			{
				infoWrite(tallyInfodriver, STATE_REH, STATESLOT);
				return;
			}

			if (currentState == STATE_TX)
			{
				infoWrite(tallyInfodriver, STATE_REH, STATESLOT);
				return;
			}
			return;
		}

		// Was the Transmission button pushed? If so, then the tally infodriver control slot must be set to TX state (value=2)
		if (b->id() == "TX")
		{
			if (currentState == STATE_TX)
			{
				// Already in TX state, so do nothing
				return;
			}
			else
			{
				// Enter TX state
				infoWrite(tallyInfodriver, STATE_TX, STATESLOT);

				// As we initiated the TX status, we must make sure that the video and audio lien outputs are correct
				if (currentVideo != STA_VMIX_OUT) routerCrosspoint(sdiRouterdriver, STA_VMIX_OUT, STA_VID_LINE, true);
				if (currentAudio != STA_AMIX_OUT) routerCrosspoint(audioRouterdriver, STA_AMIX_OUT, STA_AUD_LINE, true);
				return;
			}
		}

		if (b->id() == "Bars")
		{
			if (video_to_line)
			{
				routerCrosspoint(sdiRouterdriver, defaultVideo, STA_VID_LINE);
			}
			else
			{
				routerCrosspoint(sdiRouterdriver, STA_BARS_LINE, STA_VID_LINE);
			}
			return;
		}

		if (b->id() == "Tone")
		{
			if (audio_to_line)
			{
				routerCrosspoint(audioRouterdriver, defaultAudio, STA_AUD_LINE);
			}
			else
			{
				routerCrosspoint(audioRouterdriver, STA_TONE_LINE, STA_AUD_LINE);
			}
			return;
		}

	}	// End of if (b->panel() == PNL MAIN)
	 
}	// End of button callback function


// ++++++++++++++++++++++++ //
// All revertives come here //
// ++++++++++++++++++++++++ //
int SysControl::revertiveCallback( revertiveNotify * r )
{
	// Can get calls back from tally infodriver status slot, and from the video and	audio routers

	if ((r->device() == tallyInfodriver) && ( r->index() == STATESLOT))
	{
		currentState = r->sInfo().toInt();		// Extract the new state

		// 
		if (currentState == STATE_TX)
		{
			// Disable the video and audio to line buttons
			controlDisable(PNL_MAIN, "Bars");
			controlDisable(PNL_MAIN, "Tone");
		}
		else
		{
			// Allow Bars to line and Tone to line when in Reh or TX
			controlEnable(PNL_MAIN, "Bars");
			controlEnable(PNL_MAIN, "Tone");
		}
	}

	if (r->device() == sdiRouterdriver)
	{
		// Display the current source name
		textPut("text", r->sInfo(), PNL_MAIN, "Video_to_Line");
		currentVideo = r->info();

		// Compare the source ID withh the Colour Bars source Id. Set colour of button as required
		if (r->info() == STA_BARS_LINE)
		{
			textPut("statesheet", "WN_TakeHigh", PNL_MAIN, "Bars");
			video_to_line = true;
		}
		else
		{
			textPut("statesheet", "WNSourceDeselected", PNL_MAIN, "Bars");
			defaultVideo = r->info();		// Set default source for Bars to Line released action 
			video_to_line = false;
		}
	}

	if (r->device() == audioRouterdriver)
	{
		// Display the current source name
		textPut("text", r->sInfo(), PNL_MAIN, "Audio_to_Line");
		currentAudio = r->info();

		// Compare the source ID with the Audio Glits source Id. Set colour of button as required
		if (r->info() == STA_TONE_LINE)
		{
			textPut("statesheet", "WN_TakeHigh", PNL_MAIN, "Tone");
			audio_to_line = true;
		}
		else
		{
			textPut("statesheet", "WNSourceDeselected", PNL_MAIN, "Tone");
			defaultAudio = r->info();
			audio_to_line = false;
		}
	}

	return 0;

}	// End of revertive callback function


// ++++++++++++++++++++++++++++++++++++++++ //
// All database name changes come back here //
// ++++++++++++++++++++++++++++++++++++++++ //
void SysControl::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 SysControl::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 "";
}	// End of parent Callback function

// ++++++++++++++++++++++ //
// Timer events come here //
// ++++++++++++++++++++++ //
void SysControl::timerCallback( int id )
{
	switch( id )
	{
	case TIMER_SETUP:
		timerStop(id);
		break;

	default:	// Unhandled timer event
		timerStop(id);
		break;
	}
}	// End of timer events callback function


///////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////// Callbacks above - Methods below ///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////


