/*
PROGRAM NAME	B4_xy.DLL

USED BY			BBC Academy Wood Norton BNCS installation.

VERSION			1.0
DATE			7th March 2015
PROGRAMMER		Andy Woodhouse

Overview
========
This DLL implements a scripted matrix selection panel for use with the B4 package router.
It extracts the driver numbers from the instances.xml file, and uses teh wn_matrix scripted component.
*/


#include <windows.h>
#include <stdio.h>
#include <bncs_string.h>
#include <bncs_config.h>
#include "b4_xy.h"

#define MAIN_PANEL	1
#define MAIN_PANEL_NAME "B4_xy.bncs_ui"

#define TICK	"/images/EnabledTick.png"
#define CROSS	"/images/DisabledTick.png"
#define TAKE_HIGH	"WN_TakeHigh"
#define TAKE_LOW	"WN_TakeLow"
#define TAKE_TIMER	1

// Make our class visible to the outside world.
EXPORT_BNCS_SCRIPT( b4_xy )

// ++++++++++++++++++++++++++++++++++++++++++++ //
// Constructor - equivalent to ApplCore STARTUP //
// ++++++++++++++++++++++++++++++++++++++++++++ //
b4_xy::b4_xy(bncs_client_callback * parent, const char *path ) : bncs_script_helper(parent, path)
{
	panelInit(MAIN_PANEL, MAIN_PANEL_NAME);

	// Initialise variables
	video_id = 0;			// BNCS driver id
	audio_id = 0;			// BNCS driver id
	pkg_name_id = 0;		// BNCS driver id
	pkg_xpts_id = 0;		// BNCS driver id
	srcpkg = 0;				// Current source package number
	destpkg = 0;			// Current destination package number
	videosrc = 0;			// Video element of current source package
	audiosrc = 0;			// Audio element of current source package
    newvideosrc=0;          // Video element of newly selected source package
    newaudiosrc=0;          // Audio element of newly selected source package
	videodest = 0;			// Video element of current destination package
	audiodest = 0;			// Audio element of current destination package
	undo_vid_src = 0;		// Used by undo process
	undo_aud_src = 0;		// Used by undo process
	undo_vid_dest = 0;		// Used by undo process
	undo_aud_dest = 0;		// Used by undo process
	take_count = 0;

	for (int i = 0; i <= MATRIXSIZE; i++) videoxystate[i] = 0;
	for (int i = 0; i <= MATRIXSIZE; i++) audioxystate[i] = 0;

	src_selected = false;	// No source package selected
	dest_selected = false;	// No destination package selected
	vid_enabled = true;		// Video level enabled in take operations
	aud_enabled = true;		// Audio level enabled in take operations
	undo_enabled = false;	// Flag to indicate if the UNDO action is available
	take_enabled = false;	// Flag to indicate if the TAKE button is enabled
	take_timer_active = false;

	take_high = TAKE_HIGH ;
	take_low = TAKE_LOW;

	// Get the BNCS driver numbers from instances.xml
	getDev("B4 SDI Router", &video_id);
	getDev("B4 Audio Router", &audio_id);
	getDev("B4 Package Names", &pkg_name_id);
	getDev("B4 Package XPTS", &pkg_xpts_id);

	// Show the panel
	panelShow(MAIN_PANEL, MAIN_PANEL_NAME);

	// Disable the TAKE and UNDO buttons
	controlDisable(MAIN_PANEL, "Take");
	controlDisable(MAIN_PANEL, "Undo");

	// Register for revertives from video matrix and audio matrix. Smart panels will manage database changes of names on the package systems.
	if (video_id != 0)	routerRegister(video_id, 1, MATRIXSIZE);
	if (audio_id != 0)	routerRegister(audio_id, 1, MATRIXSIZE);

	// Poll for the initial state
	if (video_id != 0) routerPoll(video_id, 1, MATRIXSIZE);
	if (audio_id != 0) routerPoll(audio_id, 1, MATRIXSIZE);
}


// +++++++++++++++++++++++++++++++++++++++++++++ //
// Destructor - equivalent to ApplCore CLOSEDOWN //
// +++++++++++++++++++++++++++++++++++++++++++++ //
b4_xy::~b4_xy()
{
}


// ++++++++++++++++++++++++++++++++++++++++++++++ //
// All button pushes and notifications come here. //
// ++++++++++++++++++++++++++++++++++++++++++++++ //
void b4_xy::buttonCallback(buttonNotify *b)
{
	if(b->panel() == MAIN_PANEL)
	{
		// ***************************************************
		// Check for a report from the source selection panel.
		if (b->id() == "Sources")
		{
			if (undo_enabled)
			{
				controlDisable(MAIN_PANEL, "Undo");
				undo_enabled = false;
			}

			if (b->command() == "index")
			{
				// Have a new button selection. A value of "-1" means button deselected
				if (b->value() == "-1")
				{
					src_selected = false;
					srcpkg = 0;
					videosrc = 0;
					audiosrc = 0;

					// Need to manage UNDO TAKE etc.
					checkTake();
				}
				else
				{
					bncs_string sp, p1, p2, newvidsrc, newaudsrc;

					src_selected = true;			// Note we have a selection
					srcpkg = b->value().toInt();	// Note the package number

					// Get the video and audio elements of the package
					routerName(pkg_xpts_id, 0, srcpkg, sp);
					sp.split(',', p1, p2);
					if (p1 == "-") videosrc = 0;
					else videosrc = p1.toInt();
					if (p2 == "-") audiosrc = 0;
					else audiosrc = p2.toInt();
                    routerName(video_id,0,videosrc,newvidsrc);
                    routerName(audio_id,0,audiosrc,newaudsrc);
                    textPut("text",newvidsrc,MAIN_PANEL,"NewVidTally");
                    textPut("text",videosrc,MAIN_PANEL,"NewVidTallyNo");
                    textPut("text",newaudsrc,MAIN_PANEL,"NewAudTally");
                    textPut("text",audiosrc,MAIN_PANEL,"NewAudTallyNo");
					
					// Need to check for source and dest, enable take etc
					checkTake();
				}
			}
			return;
		}

		// *************************************
		// Check for Destinations button pushed.
		if (b->id() == "Destinations")
		{
			if (b->command() == "index")
			{
				if (undo_enabled)
				{
					controlDisable(MAIN_PANEL, "Undo");
					undo_enabled = false;
				}

				// Have a new button selection. A value of "-1" means button deselected
				if (b->value() == "-1")
				{
					dest_selected = false;
					destpkg = 0;
					videodest = 0;
					audiodest = 0;
					textPut("text=", MAIN_PANEL, "VidTally");		// Clear the video tally display
					textPut("text=", MAIN_PANEL, "AudTally");		// Clear the audio tally display
                    textPut("text=",MAIN_PANEL,"VidTallyNo");
                    textPut("text=",MAIN_PANEL,"AudTallyNo");
                    textPut("text=",MAIN_PANEL,"NewVidTally");
					textPut("text=", MAIN_PANEL, "NewAudTally");		
                    textPut("text=",MAIN_PANEL,"NewVidTallyNo");
                    textPut("text=",MAIN_PANEL,"NewAudTallyNo");	
                    textPut("text=",MAIN_PANEL,"AudDest");
                    textPut("text=",MAIN_PANEL,"VidDest");
                    textPut("text=",MAIN_PANEL,"AudDestNo");
                    textPut("text=",MAIN_PANEL,"VidDestNo");						

					// Need to manage UNDO TAKE etc.
					checkTake();

				}
				else
				{
					bncs_string sp, p1, p2, srcvidname, srcaudname, auddestname, viddestname;

					dest_selected = true;			// Note we have a selection
					destpkg = b->value().toInt();	// Note the package number

					// Get the video and audio elements of the package
					routerName(pkg_xpts_id, 1, destpkg, sp);
					sp.split(',', p1, p2);
					if (p1 == "-") videodest = 0;
					else videodest = p1.toInt();
					if (p2 == "-") audiodest = 0;
					else audiodest = p2.toInt();

					// Show the current source selections in the tally displays
					routerName(video_id, 0, videoxystate[videodest], srcvidname);
					textPut("text", srcvidname, MAIN_PANEL, "VidTally");
                    textPut("text",videoxystate[videodest],MAIN_PANEL,"VidTallyNo");
					routerName(audio_id, 0, audioxystate[audiodest], srcaudname);
					textPut("text", srcaudname, MAIN_PANEL, "AudTally");
                    textPut("text",audioxystate[audiodest],MAIN_PANEL,"AudTallyNo");
                    routerName(audio_id,1,audiodest,auddestname);
                    textPut("text",audiodest,MAIN_PANEL,"AudDestNo");
                    textPut("text",auddestname,MAIN_PANEL,"AudDest");
                    routerName(video_id,1,videodest,viddestname);
                    textPut("text",viddestname,MAIN_PANEL, "VidDest");
                    textPut("text",videodest,MAIN_PANEL,"VidDestNo");

					// Need to check for source and dest, enable take etc
					checkTake();
				}
			}
			return;
		}

		// *********************
		// Check for TAKE button
		if (b->id() == "Take")
		{
			// Only get to this code if a source and a destination have been selected
			doTake();
			return;
		}


		// *********************
		// Check for UNDO button
		if (b->id() == "Undo")
		{
			// As soon as UNDO is pressed - it must be disabled.
			controlDisable(MAIN_PANEL, "Undo");
			undo_enabled = false;

			// Send crosspoints to retore old route
			if ((vid_enabled) && (undo_vid_src != 0) && (undo_vid_dest != 0)) routerCrosspoint(video_id, undo_vid_src, undo_vid_dest);
			if ((aud_enabled) && (undo_aud_src != 0) && (undo_aud_dest != 0)) routerCrosspoint(audio_id, undo_aud_src, undo_aud_dest);

			return;
		}

		// **********************
		// Check for CLEAR button
		if (b->id() == "Clear")
		{
			// Request to cleardown any selections.
			if (undo_enabled)
			{
				controlDisable(MAIN_PANEL, "Undo");
				undo_enabled = false;
			}

			// Is the take timer running?
			if (take_timer_active)
			{
				timerStop(TAKE_TIMER);
				take_timer_active = false;
			}

			if (take_enabled)
			{
				textPut("statesheet", take_high, MAIN_PANEL, "Take");
				controlDisable(MAIN_PANEL, "Take");
				take_enabled = false;
			}

			if (src_selected)
			{
				textPut("select=-1", MAIN_PANEL, "Sources");
				src_selected = false;
			}

			if (dest_selected)
			{
				textPut("select=-1", MAIN_PANEL, "Destinations");
				dest_selected = false;
			}

			textPut("text=", MAIN_PANEL, "VidTally");
			textPut("text=", MAIN_PANEL, "AudTally");
		}

		// *****************************************
		// Check for video level enable button push.
		if (b->id() == "videolevel")
		{
			if (undo_enabled)
			{
				controlDisable(MAIN_PANEL, "Undo");
				undo_enabled = false;
			}
			vid_enabled = vid_enabled ? false : true;	// Toggle state of vid enabled flag
			textPut("pixmap", vid_enabled ? TICK : CROSS, MAIN_PANEL, "videolevel");
			return;
		}

		// Check for video level enable button push
		if (b->id() == "audiolevel")
		{
			if (undo_enabled)
			{
				controlDisable(MAIN_PANEL, "Undo");
				undo_enabled = false;
			}
			aud_enabled = aud_enabled ? false : true;	// Toggle tate of vid enabled flag
			textPut("pixmap", aud_enabled ? TICK : CROSS, MAIN_PANEL, "audiolevel");
			return;
		}

	}	// End of if(b->panel() == MAIN_PANEL)
}	// End of buttonCallback()


// +++++++++++++++++++++++++ //
// All revertives come here. //
// +++++++++++++++++++++++++ //
int b4_xy::revertiveCallback(revertiveNotify *r)
{
	if (r->device() == video_id)
	{
		videoxystate[r->index()] = r->info();	// Record the revertive data
		// Check if the destination is displayed on the tally display. Update display as needed.
		if ((dest_selected) && (videodest == r->index()))
		{
			textPut("text", r->sInfo(), MAIN_PANEL, "VidTally");
		}
	}

	if (r->device() == audio_id)
	{
		audioxystate[r->index()] = r->info();	// Record the revertive data
		if ((dest_selected) && (audiodest == r->index()))
		{
			textPut("text", r->sInfo(), MAIN_PANEL, "AudTally");
		}
	}

	return 0;
}


// ++++++++++++++++++++++++++++++++++++ //
// All database name changes come here. //
// ++++++++++++++++++++++++++++++++++++ //
void b4_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 b4_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' );
		}
	}

	return "";
}

// +++++++++++++++++++++++ //
// Timer events come here. //
// +++++++++++++++++++++++ //
void b4_xy::timerCallback(int id)
{
	switch(id)
	{
	case TAKE_TIMER:
		// Decrement the take counter, then toggle the Take button state
		take_count--;
		if ((take_count & 1) == 0)	// Change teh Take button highlighting
			textPut("statesheet", take_high, MAIN_PANEL, "Take");
		else
			textPut("statesheet", take_low, MAIN_PANEL, "Take");
		if (take_count == 0)
		{
			timerStop(TAKE_TIMER);
			controlDisable(MAIN_PANEL, "Take");
			take_timer_active = false;
		}
		
		break;

	default:	// Unhandled timer event
		timerStop(id);
		break;
	}
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////// Callbacks above - Methods below ///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////

// +++++++++++++++++++++++++++++++++++++++++++++++++++++ //
// checkTake() looks at the source and destination data, //
// and enables the TAKE button if valid data present.    //
// +++++++++++++++++++++++++++++++++++++++++++++++++++++ //
void b4_xy::checkTake(void)
{
	if (src_selected && dest_selected)
	{
		// Have source and destination packages available.
		if (take_enabled)
		{
			textPut("statesheet", take_high, MAIN_PANEL, "Take");
			timerStop(TAKE_TIMER);
		}

		controlEnable(MAIN_PANEL, "Take");
		take_enabled = true;
		take_count = 10;
		timerStart(TAKE_TIMER, 1000);
		take_timer_active = true;
	}
	else
	{
		// Stop any TAKE enables etc
		if (take_timer_active)
		{
			timerStop(TAKE_TIMER);
			take_timer_active = false;
		}

		if (take_enabled)
		{
			textPut("statesheet", take_high, MAIN_PANEL, "Take");
			controlDisable(MAIN_PANEL, "Take");
			take_enabled = false;
		}
	}
}	// End of function checkTake()


// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //
// Function doTake() is called to action the Take function. //
// A source package and destination package are selected.   //
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //
void b4_xy::doTake(void)
{
	// Compute the video and audio elements of the source. Destination elements were computed when the destination was selected
	bncs_string sp, p1, p2;

	// Clear down the TAKE button and counter
	if (take_timer_active)
	{
		timerStop(TAKE_TIMER);			// Stop the take timer
		take_timer_active = false;
	}
	textPut("statesheet", take_high, MAIN_PANEL, "Take");
	controlDisable(MAIN_PANEL, "Take");

	routerName(pkg_xpts_id, 0, srcpkg, sp);	// Get the comma delimited data for teh source package
	sp.split(',', p1, p2);
	if (p1 == "-") videosrc = 0; 
	else videosrc = p1.toInt();
	if (p2 == "-") audiosrc = 0;
	else audiosrc = p2.toInt();

	// Make copies of source and destination data for the UNDO operation
	undo_vid_src = videoxystate[videodest];
	undo_aud_src = audioxystate[audiodest];
	undo_vid_dest = videodest;
	undo_aud_dest = audiodest;

	// Issue the router crosspoint commands. Requires level enable, and non-zero sources and destinations
	if (vid_enabled && (videosrc != 0) && (videodest !=0))	routerCrosspoint(video_id, videosrc, videodest);
	if (aud_enabled && (audiosrc != 0) && (audiodest != 0))	routerCrosspoint(audio_id, audiosrc, audiodest);

	// Clear the tally displays
	textPut("text=", MAIN_PANEL, "VidTally");
	textPut("text=", MAIN_PANEL, "AudTally");

	// Clear the selections
	textPut("select=-1", MAIN_PANEL, "Sources");
	textPut("select=-1", MAIN_PANEL, "Destinations");

	// Enable the UNDO button
	controlEnable(MAIN_PANEL, "Undo");
	undo_enabled = true;

}	// End of function doTake()

