/*
PROGRAM NAME	b4_mon.DLL

USED BY			BBC Academy Studio A/CTA installation

VERSION			1.0
DATE			14th March 2015
PROGRAMMER		Andy Woodhouse

Overview
========
This module provides a simple user interface to enable users to direct signals to the various monitor in room Bredon 4.

There are, at March 2015, 5 monitor destinations in the installation:
1)	Bay 4 with waveform monitor and PPM. A picture monitor is connected to the waveform monitor, and an audio monitor is connected to the PPM unit
2)	Bay 2 has a video monitor for use with the satellite RX kit
3)	Bay 3 has a video monitor for use with the satellite RX kit
4)	Bay 1 has an audio monitor, mostly for use with the satellite kit
5)	The control room table, adjacent to the wall to room B5, has a set of speakers.

*/

#include <windows.h>
#include <stdio.h>
#include <bncs_string.h>
#include <bncs_config.h>
#include "b4_mon.h"

#define MAIN_PANEL	1
#define MAIN_PANEL_NAME	"b4_mon.bncs_ui"
#define LEVEL_ENABLE	"/images/SmallTick.png"
#define LEVEL_DISABLE	"/images/SmallCross.png"
#define MON_SELECT		"WN_Tally_Red"
#define MON_DESELECT	"WN_Tally_Black"

// Define the fixed (non-user editable) package numbers of the video/audio monitors
// MON1 is in bay 4 (audio and video). WFM and PPM on the destinations
// MON2 is video only in bay 3
// MON3 is video only in bay 2
// MON4 is audio only in bay 1
// MON5 is audio only on control desk (by wall to room B5)
#define MON1DPKG 361	
#define MON2DPKG 388
#define MON3DPKG 389
#define MON4DPKG 387
#define MON5DPKG 390

#define SOURCE_CLEAR_TIMER	1
#define SOURCE_CLEAR_TIMEOUT 160

/////////////////////////////////////////////////
// Make our class visible to the outside world //
EXPORT_BNCS_SCRIPT(b4_mon)

// ++++++++++++++++++++++++++++++++++++++++++++ //
// Constructor - equivalent to ApplCore STARTUP //
// ++++++++++++++++++++++++++++++++++++++++++++ //
b4_mon::b4_mon( bncs_client_callback * parent, const char * path ) : bncs_script_helper( parent, path )
{
	// Initialise variables
	m_myParam = "";
	m_instance = "";

	video_id=0;			// BNCS driver id of video matrix
	audio_id=0;			// BNCS driver id of audio matrix
	package_id=0;		// BNCS driver id of package names
	package_xpts=0;		// BNCS driver id of package crosspoints
	mon_id=1;			// Holds the id of the monitor. 1=Bay 4, 2=Bay 3 3=Bay 2
	for (int i = 0; i < 6; i++) vid_dest[i] = 0;	// Holds the id of the monitor video destinations. vid_dest[x] is the id for monitor x
	for (int i = 0; i < 6; i++) aud_dest[i] = 0;	// Holds the id of the monitor audio destinations. aud_dest[x] is the id for monitor x

	// Get the driver ids from instances.xml
	getDev("B4 Package Names", &package_id);
	getDev("B4 Package XPTS", &package_xpts);
	getDev("B4 SDI Router", &video_id);
	getDev("B4 Audio Router", &audio_id);

	// Extract the video and audio destinations for the monitors
	extract_xpts(MON1DPKG, 1, &vid_dest[1], &aud_dest[1]);	// Monitor 1 (in Bay 4). Audio and Video
	extract_xpts(MON2DPKG, 1, &vid_dest[2], &aud_dest[2]);	// Monitor 2 (in bay 3). Video Only
	extract_xpts(MON3DPKG, 1, &vid_dest[3], &aud_dest[3]);	// Monitor 3 (in bay 2). Video Only
	extract_xpts(MON4DPKG, 1, &vid_dest[4], &aud_dest[4]);	// Monitor 4 (in bay 1). Audio Only
	extract_xpts(MON5DPKG, 1, &vid_dest[5], &aud_dest[5]);	// Monitor 5 (on control desk). Audio Only

	// Show our panel.
	panelShow(MAIN_PANEL, MAIN_PANEL_NAME);

	video_enabled = true;		// Start with the audio and video levels enabled.
	audio_enabled = true;
	textPut("", LEVEL_ENABLE, MAIN_PANEL, "VidLevel");
	textPut("", LEVEL_ENABLE, MAIN_PANEL, "AudLevel");

	// Set the selector highlights to Monitor 1
	textPut("statesheet", MON_SELECT, MAIN_PANEL, "ID_1");
	textPut("statesheet", MON_DESELECT, MAIN_PANEL, "ID_2");
	textPut("statesheet", MON_DESELECT, MAIN_PANEL, "ID_3");
	textPut("statesheet", MON_DESELECT, MAIN_PANEL, "ID_4");
	textPut("statesheet", MON_DESELECT, MAIN_PANEL, "ID_5");

	// Register for revertives from the routers, then poll our video destinations
	routerRegister(video_id, vid_dest[1], vid_dest[1]);			// Start with the first monitor in bay 4
	for (int i = 2; i <= 5; i++)
	{
		if (vid_dest[i] != 0) routerRegister(video_id, vid_dest[i], vid_dest[i], true);		// Add extra destinations
	}

	routerRegister(audio_id, aud_dest[1], aud_dest[1]);			// Start with the first monitor in bay 4
	for (int i = 2; i <= 5; i++)
	{
		if (aud_dest[i] != 0) routerRegister(audio_id, aud_dest[i], aud_dest[i], true);		// Add extra destinations
	}

	// Poll the video destinations that are non-zero
	for (int i = 1; i <= 5; i++)
	{
		if (vid_dest[i] != 0) routerPoll(video_id, vid_dest[i], vid_dest[i]);
	}

	// Poll the audio destinations that are non zero
	for (int i = 1; i <= 5; i++)
	{
		if (aud_dest[i] != 0) routerPoll(audio_id, aud_dest[i], aud_dest[i]);
	}
}	// End of Constructor.


// +++++++++++++++++++++++++++++++++++++++++++++ //
// Destructor - equivalent to ApplCore CLOSEDOWN //
// +++++++++++++++++++++++++++++++++++++++++++++ //
b4_mon::~b4_mon()
{
	// Unregister from router revertive
	routerUnregister(video_id);
	routerUnregister(audio_id);
}


// ++++++++++++++++++++++++++++++++++++++++++++++ //
// All button pushes and notifications come here. //
// ++++++++++++++++++++++++++++++++++++++++++++++ //
void b4_mon::buttonCallback(buttonNotify *b)
{
	if( b->panel() == MAIN_PANEL)
	{
		// Check for new source package selection
		if (b->id() == "Sources")
		{
			if (b->value().toInt() > 0)
			{
				// Make the crosspoints
				int vid_src, aud_src;

				extract_xpts(b->value().toInt(), 0, &vid_src, &aud_src);	// Extract the source audio and video crosspoints

				// Check the active monitor. Monitor 1 has level switch enables, other do not.
				if (mon_id == 1)
				{
					// Include the audio/video level ebables in the test of if the crosspoint should be made.
					if (video_enabled && (vid_src != 0) && (vid_dest[mon_id] != 0)) routerCrosspoint(video_id, vid_src, vid_dest[mon_id]);
					if (audio_enabled && (aud_src != 0) && (aud_dest[mon_id] != 0)) routerCrosspoint(audio_id, aud_src, aud_dest[mon_id]);
				}
				else
				{
					// Just use non-zero crosspoints as the test for issuing a take crosspoint.
					if ((vid_src != 0) && (vid_dest[mon_id] != 0)) routerCrosspoint(video_id, vid_src, vid_dest[mon_id]);
					if ((aud_src != 0) && (aud_dest[mon_id] != 0)) routerCrosspoint(audio_id, aud_src, aud_dest[mon_id]);
				}

				// Clear down the source selector. Start a timer that will issue the clear upon timeout
				timerStart(SOURCE_CLEAR_TIMER, SOURCE_CLEAR_TIMEOUT);	// Start the timer
			}
			return;
		}	// End of if (b->id() == "Sources")


		// Check for new monitor activation
		if (b->id().startsWith("Mon_"))
		{
			int newmon = 0;

			newmon = b->id().firstInt();
			if (mon_id != newmon)
			{
				textPut("statesheet", MON_DESELECT, MAIN_PANEL, bncs_string("ID_%1").arg(mon_id));	// De-select old monitor
				mon_id = newmon;
				textPut("statesheet", MON_SELECT, MAIN_PANEL, bncs_string("ID_%1").arg(newmon));	// Highlight new monitor
			}
			return;
		}


		// Check for Video level enable/disable
		if (b->id() == "VidLevel")
		{
			// Toggle the video level enable
			if (video_enabled == false)
			{
				// Set to enabled
				textPut("pixmap", LEVEL_ENABLE, MAIN_PANEL, "VidLevel");
				video_enabled = true;
			}
			else
			{
				// Set to disabled
				textPut("pixmap", LEVEL_DISABLE, MAIN_PANEL, "VidLevel");
				video_enabled = false;
			}
			return;
		}

		// Check for Audio level enable/disable
		if (b->id() == "AudLevel")
		{
			// Toggle the video level enable
			if (audio_enabled == false)
			{
				// Set to enabled
				textPut("pixmap", LEVEL_ENABLE, MAIN_PANEL, "AudLevel");
				audio_enabled = true;
			}
			else
			{
				// Set to disabled
				textPut("pixmap", LEVEL_DISABLE, MAIN_PANEL, "AudLevel");
				audio_enabled = false;
			}
			return;
		}
	}
}


// +++++++++++++++++++++++++ //
// All revertives come here. //
// +++++++++++++++++++++++++ //
int b4_mon::revertiveCallback(revertiveNotify *r)
{
	if (r->device() == video_id)	// Check for response from the video router.
	{
		if (r->index() == vid_dest[1])	// Bay 4 video monitor?
		{
			textPut("text", r->sInfo(), MAIN_PANEL, "Vidtally_1");
			return 0;
		}

		if (r->index() == vid_dest[2])	// Bay 3 video monitor?
		{
			textPut("text", r->sInfo(), MAIN_PANEL, "Vidtally_2");
			return 0;
		}

		if (r->index() == vid_dest[3])	// Bay 2 video monitor?
		{
			textPut("text", r->sInfo(), MAIN_PANEL, "Vidtally_3");
			return 0;
		}
	}	// End of if (r->device() == video_id)

	if (r->device() == audio_id)	// Check for response from the audio router.
	{
		if (r->index() == aud_dest[1])	// Bay 4 audio monitor?
		{
			textPut("text", r->sInfo(), MAIN_PANEL, "Audtally_1");
			return 0;
		}

		if (r->index() == aud_dest[4])	// Bay 1 audio monitor?
		{
			textPut("text", r->sInfo(), MAIN_PANEL, "Audtally_4");
			return 0;
		}

		if (r->index() == aud_dest[5])	// Control desk monitor?
		{
			textPut("text", r->sInfo(), MAIN_PANEL, "Audtally_5");
			return 0;
		}
	}	// End of if (r->device() == audio_id)

	return 0;
}

// +++++++++++++++++++++++++++++++++++++++++ //
// All database name changes come back here. //
// +++++++++++++++++++++++++++++++++++++++++ //
void b4_mon::databaseCallback(revertiveNotify *r)
{
	// All database changes should be handled by the "smart" source panel selector.
}


// ++++++++++++++++++++++++++++++++++++++++++++++++++ //
// 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 b4_mon::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 b4_mon::timerCallback(int id)
{
	switch( id )
	{
	case SOURCE_CLEAR_TIMER:
		timerStop(SOURCE_CLEAR_TIMER);
		textPut("select=-1", MAIN_PANEL, "Sources");		// Send clear command to sources panel.
		break;

	default:	// Unhandled timer event
		timerStop(id);
		break;
	}
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////// Callbacks above - Methods below ///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////


void b4_mon::extract_xpts(int pkg_id, int database, int *viddest, int *auddest)
{
	// pkg is the page number to process, databases is 0 for sources, 1 for destinations
	// viddest and auddest are the addresses for the results.
	bncs_string xptlist, p1, p2;

	routerName(package_xpts, database, pkg_id, xptlist);	// Read comma delimited string
	xptlist.split(',', p1, p2);								// Divide into two parts
	if (p1 == "-") *viddest = 0;
	else *viddest = p1.toInt();
	if (p2 == "-") *auddest = 0;
	else *auddest = p2.toInt();

}


