/***********************************************************************
**					CueControl										  **
**					Written by Hild Watts							  **
***********************************************************************/



/************************************************************************
**** This is an addition to Andy Woodhouse's TakeA component.     ******
**** It has been written to provide automatic cue switching for    ******
**** the studios in Avon wing.  If the user has requested cue to   ******
**** be switched along with music, the code will first check that  ******
**** both the source and the destination selected are capable of   ******
**** producing/receiving cue - if they are not, an error will be   ******
**** displayed and music-only will be routed.  If they are capable ******
**** and the cue is not already routed elsewhere, the routes will  ******
**** be made on both music and cue routers.  If the cue is already ******
**** in use, the requesting studio will be told who currently has  ******
**** it and music-only will be routed.                             ******
****															   ******
**** This component is connected up with the TakeA component and   ******
**** needs a connection from the source grid, one from the dest    ******
**** name grid and a Take connection from the TakeA component.     ******
**** It is important that this connection appears in the connection******
**** list ahead of the clear-down messages, otherwise it won't work******
**** correctly.
************************************************************************/





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

#define PNL_MAIN	1

#define TIMER_SETUP	1

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

// constructor - equivalent to ApplCore STARTUP
CueControl::CueControl( 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" );
	m_iCueRouter = getObjectSetting("AVON_ROUTER","cue_router_number");
	m_iMusicRouter = getObjectSetting("AVON_ROUTER", "music_router_number");
	m_iInfoRouter = getObjectSetting("AVON_ROUTER", "cue_info_number");
	m_bCueActive = false;
	m_iCueTallyList[17] = { 0 };
	m_iMusicSource = -1;
	m_iMusicDest = -1;
	m_iCueSource = -1;
	m_iCueDest = -1;
	m_iCueSourceIndex = -1;
	m_iCueDestIndex = -1;
	m_iWhereSourceCueRouted = -1;
	m_iWhatRoutedToDestCue = -1;
	m_bIsDestCueRouted = false;
	m_bIsSourceCueRouted = false;
	m_iMusicOff = 31;
	m_iCueOffSource = getObjectSetting("AVON_ROUTER", "cue_OFF_source");
	routerRegister(m_iCueRouter, 1, 16, false);
	routerPoll(m_iCueRouter, 1, 16);

	m_sCueSources = getObjectSetting("AVON_ROUTER", "cuesources");
	m_sMusicDestinations = getObjectSetting("AVON_ROUTER", "musicdestinations");
	//m_sValidCueSources = getObjectSetting("AVON_ROUTER", "sources");
	m_sValidCueDestinations = getObjectSetting("AVON_ROUTER", "cuedestinations");
	m_sCueSourceNames = getObjectSetting("AVON_ROUTER", "sourcenames");
	// you may need this call to set the size of this component 
	//  if it's used in a popup window 
//	setSize( 1024,668 );		// set the size explicitly
//	setSize( PNL_MAIN );		// set the size to the same as the specified panel
}

// destructor - equivalent to ApplCore CLOSEDOWN
CueControl::~CueControl()
{
}

// all button pushes and notifications come here
void CueControl::buttonCallback( buttonNotify *b )
{
	if( b->panel() == PNL_MAIN )
	{
		if (b->id() == "ActivateCue")
		{
			if (m_bCueActive == false)
			{
				m_bCueActive = true;
				textPut("text", "Full Facs", PNL_MAIN, "ActivateCue");
				textPut("text", "Click to remove cue", PNL_MAIN, "CueText");
			}
			else
			{
				m_bCueActive = false;
				textPut("text", "Listen Only", PNL_MAIN, "ActivateCue");
				textPut("text", "Click to add cue", PNL_MAIN, "CueText");
			}

		}
	}
}

// all revertives come here
int CueControl::revertiveCallback( revertiveNotify * r )
{
	//Whenever a tally is received from the cue router
	//the list of where the cues are routed is updated

	if (r->device() == m_iCueRouter)
	{
		m_iCueTallyList[(r->index())] = r->info();
	}

	return 0;
}

// all database name changes come back here
void CueControl::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 CueControl::parentCallback( parentNotify *p )
{
	if( p->command() == "return" )
	{
		if( p->value() == "all" )
		{	// Persisting values for bncs_vis_ed
			bncs_stringlist sl;
			
			sl << bncs_string("CueRouter=%1").arg(m_iCueRouter);
			
			return sl.toString( '\n' );
		}

/*		else if( p->value() == "CueRouter" )
		{	// Specific value being asked for by a textGet
			return( bncs_string( "%1=%2" ).arg( p->value() ).arg( m_iCueRouter ) );
		}*/

	}
	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() == "CueRouter" )
	{	// Persisted value or 'Command' being set here
		m_iCueRouter = p->value();
	}
	else if (p->command() == "Source")
	{
		//A source grid button has been clicked, now check if there is cue associated with this source
		//If there is, set m_cueDest to value of music source and set m_cueDestValid to true

		m_bCueDestValid = false;
		m_iMusicSource = p->value();
		m_checkCueDest(m_iMusicSource);


	}
	else if (p->command() == "Destination")
	{
		//A dest grid button has been clicked, now check if there is cue associated with this destination
		//If there is, set m_cueSource to value of music destination and set m_cueSceValid to true

		m_bCueSourceValid = false;
		m_iMusicDest = p->value();
		m_checkCueSource(m_iMusicDest);

	}
	else if (p->command() == "Take")
	{
timerStart(TIMER_SETUP,5000);

		if (m_iMusicSource == m_iMusicOff)	//Routing to OFF, regardless of whether you've asked for cue or not
		{
			infoWrite(m_iInfoRouter, "grey", m_iCueSource, true);
			debug("cueoffsource=");
			debug(m_iCueOffSource);
			debug("\n");
			debug("wheresourcecuerouted=");
			debug(m_iWhereSourceCueRouted);
			debug("\n");
			routerCrosspoint(m_iCueRouter, m_iCueOffSource, m_iWhereSourceCueRouted, "", true);	//Make sure you're not feeding cue elsewhere
		}
		
		else if (m_bCueActive == false)	//You've not selected cue
		{
			infoWrite(m_iInfoRouter, "grey", m_iCueSource, true);
			debug("not even thinking cue is selected \n");
			routerCrosspoint(m_iCueRouter, m_iCueOffSource, m_iWhereSourceCueRouted, "", true);	//Make sure you're not feeding cue elsewhere
		}
		else if(m_bCueActive==true)                      //You have selected cue
		{
			if ((m_bCueSourceValid==true) && (m_bCueDestValid == false))	//Music dest can produce cue, music source can't receive it
			{
				infoWrite(m_iInfoRouter, "grey", m_iCueSource, true);
				textPut("text", "This music source |can not receive cue |You are getting listen-only", PNL_MAIN, "CueInfo");
				routerCrosspoint(m_iCueRouter, m_iCueOffSource, m_iWhereSourceCueRouted, "", true);	//Make sure you're not feeding cue elsewhere
			}
			if ((m_bCueSourceValid == false) && (m_bCueDestValid==true))	//Music source can receive cue, music dest can't produce it
			{
					textPut("text", "This music destination | can not produce cue |You are getting listen-only", PNL_MAIN, "CueInfo");
			}
			if ((m_bCueSourceValid == false) && (m_bCueDestValid==false))	//Music source can receive cue, music dest can't produce it
			{
				textPut("text", "Neither source nor |destination is cue capable |You are getting listen-only", PNL_MAIN, "CueInfo");
			}
			if (m_bCueSourceValid && m_bCueDestValid)	// both source and destination are cue-capable
			{
				if (m_bIsDestCueRouted!=true)				//DestCue isn't routed - have some cue!
				{
					routerCrosspoint(m_iCueRouter, m_iCueOffSource, m_iWhereSourceCueRouted, "", true); //Make sure wherever you were feeding cue last is switched off
					routerCrosspoint(m_iCueRouter, m_iCueSource, m_iCueDest, "",true);
					infoWrite(m_iInfoRouter, "green", m_iCueSource, true);
				}
				else //here the cue is already routed elsewhere so you get listen-only
				{
					bncs_string message = "";
					message.append(m_sCueSourceNames[m_iWhatRoutedToDestCue-1]);
					message.append(" has the cue | You are getting listen-only");
					infoWrite(m_iInfoRouter, "grey", m_iCueSource, true);
					textPut("text", message, PNL_MAIN, "CueInfo");
					routerCrosspoint(m_iCueRouter, m_iCueOffSource, m_iWhereSourceCueRouted, "", true);
				}
			}
		}		
		m_bCueActive = false;													//Reset cue request back to the default
		textPut("text", "Listen Only", PNL_MAIN, "ActivateCue");				//so unless you've specifically requested
		textPut("text", "Click to add cue", PNL_MAIN, "CueText");				//cue you get listen-only
	}
	// ***** 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 << "Source=[value]";
		sl << "Destination=[value]";
		sl << "Take=[value]";
		
		
		return sl.toString( '\n' );
	}

	return "";
}

// timer events come here
void CueControl::timerCallback( int id )
{
	switch( id )
	{
	case TIMER_SETUP:
    	textPut("text", "", PNL_MAIN, "CueInfo");
		timerStop(id);
		break;

	default:	// Unhandled timer event
		timerStop(id);
		break;
	}
}


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


int CueControl::m_checkCueSource(int m_iMusicDest)
{	//if the music destination is in the list of m_sValidCueSources
	//assign the value of the cue source to m_iCueSource and set m_iCueSourceValid to true
	m_iCueSourceIndex = m_sMusicDestinations.find(m_iMusicDest, false);
	if (m_iCueSourceIndex >= 0)
	{
		//int myIndex = 0;	//interim index for finding relationship between cue source and music destination
		//myIndex = m_sMusicDestinations[m_iMusicDest];
		m_iCueSource = m_sCueSources[m_iCueSourceIndex];

		//m_iCueSource = m_sValidCueSources[m_iCueSourceIndex];   //not strictly necessary - could have said m_iCueSource=m_iMusicDest 
																//but wanted to make it obvious that we were getting these values from the 
																//objectsettings via the stringlist
		m_bCueSourceValid = true;
		m_checkCueSourceRouting(m_iCueSource);	//You've established the source is valid, now check if it's routed anywhere
	}
	else
	{
		m_bCueSourceValid = false;
		m_iCueSource = -1;
	}
	return 0;
}
void CueControl::m_checkCueDest(int m_iMusicSource)
{	//if the music source is in the list of m_sValidCueDestinations
	//assign the value of the cue dest to m_iCueDest and set m_iCueDestValid to true

	m_iCueDestIndex = m_sValidCueDestinations.find(m_iMusicSource, false);
	m_iCueDest = m_sValidCueDestinations[m_iCueDestIndex];		//not strictly necessary - could have said m_iCueDest=m_iMusicSource 
																//but wanted to make it obvious that we were getting these values from the 
																//objectsettings via the stringlist
	if (m_iCueDestIndex >= 0)
	{
		m_bCueDestValid = true;
		m_checkCueDestRouting(m_iCueDest);	//The cue destination exists, this checks if anything is routed to it
	}
	else
	{
		m_bCueDestValid = false;
		m_iCueDest = -1;
	}
		
}

void CueControl::m_checkCueDestRouting(int cueDest)
//Look up the list of cue tallies and see what is listed against the index
//of the cue destination.  If this is equal to or greater than zero (but not equal to the off source
//the dest cue is routed 
{
	m_iWhatRoutedToDestCue = m_iCueTallyList[cueDest];

	if ((m_iWhatRoutedToDestCue >= 0) && (m_iWhatRoutedToDestCue != m_iCueOffSource))
	{
		m_bIsDestCueRouted = true;
	}
	else
		m_bIsDestCueRouted = false;

}

void CueControl::m_checkCueSourceRouting(int cueSource)
//Look through the list of cue tallies and see if any of the entries are equal
//to the cueSource.  If it is, the source cue is routed to the destination
//given by the index of this list.
{
	m_iWhereSourceCueRouted = -1;
	m_bIsSourceCueRouted = false;
	for (int i = 1; i < 15; i++)
	{
		if (cueSource == m_iCueTallyList[i])
		{
			m_iWhereSourceCueRouted = i;
			m_bIsSourceCueRouted = true;
		}
	}
}