/* Rtr_Trig.cpp - custom program file for project Rtr_Trig */

#include "stdafx.h"
#include "Rtr_Trig.h"



/* TODO: place references to your functions and global variables in the Rtr_Trig.h file */

// local function prototypes
// this function is called when a valid slotchange notification is extracted from the InfoNotify
BOOL SlotChange(UINT iDriver,UINT iSlot, LPCSTR szSlot);

//
//  FUNCTION: InfoNotify()
//
//  PURPOSE: Callback function from an infodriver, notifying event
//
//  COMMENTS: the pointer pex references the infodriver which is notifying
//			  iSlot and szSlot are provided for convenience
//			
void InfoNotify(extinfo* pex,UINT iSlot,LPCSTR szSlot)
{
	//
	char sSlotContents[256];
//	Debug("message from InfoExt");
	switch (pex->iStatus) {
	case CONNECTED: // this is the "normal" situation
		UpdateCounters();
		wsprintf(sSlotContents,szSlot);
		if (!SlotChange(pex->iDevice,iSlot,szSlot)) 
			pex->setslot(iSlot,sSlotContents);
		break;

	case DISCONNECTED:
		Debug("Infodriver %d has disconnected", pex->iDevice);
		PostMessage( hWndMain, WM_CLOSE, 0, 0 );
		return;
				
	case TO_RXONLY:
		Debug("Infodriver %d received request to go RX Only",pex->iDevice);
		SetDlgItemText(hWndDlg,IDC_INFO_TXRXMODE,"RX Only");
		break;

	case TO_TXRX:
		Debug("Infodriver %d received request to go TXRX",pex->iDevice);
		SetDlgItemText(hWndDlg,IDC_INFO_TXRXMODE,"TX/RX");
		break;

	default:
		Debug("iStatus=%d",pex->iStatus);
		
	}
}

//
//  FUNCTION: SlotChange()
//
//  PURPOSE: Function called when slot change is notified
//
//  COMMENTS: All we need here are the driver number, the slot, and the new contents
//		
//	RETURNS: TRUE for processed (don't update the slot),
//			 FALSE for ignored (so calling function can just update the slot 
//								like a normal infodriver)
//			

BOOL SlotChange(UINT iDevice,UINT iSlot, LPCSTR szSlot)
{
	
	// TODO: Add slot processing and return TRUE if processed
	
	
	Debug("slot change");
	
	if(iSlot < MAX_NUMBER_OF_SOURCES +1)
	{
		int iTemp=0;
		iTemp = atoi(szSlot);
		iSourceArray[iSlot] = iTemp;
		if(!strncmp(szSlot, "Router=", 7))
		{
			Debug("Destination button %d changed to %s",iSlot, szSlot);
			iTielineSourceArray[iSlot] = 0;
		}
		else
			if(!strncmp(szSlot, "Tieline", 7))
			{
				// Rtr_Trig_Pnl puts 'Tieline=n' when source n is on the Studer router
				Debug("Source button %d changed to %s",iSlot, szSlot);
				bncs_string p1;
				bncs_string p2;
				bncs_string s = szSlot;
				s.split( '|', p1, p2 );
				iTemp = atoi(p2);
				iTielineSourceArray[iSlot] = iTemp;
			}
			else
			{
				Debug("Source button %d assigned to router source %d",iSlot, iTemp);
				iTielineSourceArray[iSlot] = 0;
			}
			
			if(fQuartz_Label == 1)
			{
				// source names for quartz button labels written to driver slots 21 - 36
				char sTemp[BUFFER_LENGTH];
				char sdbName[BUFFER_LENGTH];
				/*if(!strncmp(szSlot, "Tieline", 7))
				ec.getdbname( TIELINED_ROUTER, 0, iTemp, sdbName, BUFFER_LENGTH);
				else*/
				ec.getdbname(atoi(sRouter), 0, iTemp, sdbName, BUFFER_LENGTH);
				Debug("Writing to Quartz Label %d, name is %s",iSlot, sdbName);
				wsprintf(sTemp, "IW %d '%s' %d", iTriggerDevice, sdbName, iSlot + 20);
				ec.txinfocmd(sTemp);
			}
			
			return FALSE;
	}
	
	switch (iSlot)
	{
	case RELOAD_DEFAULTS_SLOT:
		if(!strcmp(szSlot, "Default"))
		{
			Debug("");
			Debug("Default requested - reloading ini file configuration settings..");
			LoadConfig();
			return true;
		}
		break;
		
	case ROUTER_SLOT:
	//	if (iReRoute_LastSource == 1)
			// Re Register with router
		{
		/*	wsprintf(sRouter, "%s", szSlot);
		if(atoi(sRouter))
		ec.unregtallyrange(atoi(sRouter));
		ec.regtallyrange(atoi(sRouter),atoi(sDest),atoi(sDest));
		char sTemp[256];
		wsprintf(sTemp, "RP %s %s %s",sRouter,sDest,sDest);
		ec.txrtrcmd(sTemp);
		Debug("Router device id changed to %s", sRouter);
			Debug("Re Registered with router device number %s, destination number %s", sRouter, sDest);*/
			char szTemp[BUFFER_LENGTH];
			strcpy(szTemp, sDest);
			RouterReRegister(szSlot, szTemp);
		}
		return FALSE;
		break;
		
	case DESTINATION_SLOT:
	//	if (iReRoute_LastSource == 1)
			// Re Register with router
		{
		/*wsprintf(sDest, "%s", szSlot);
		if(atoi(sRouter))
		ec.unregtallyrange(atoi(sRouter));
		ec.regtallyrange(atoi(sRouter),atoi(sDest),atoi(sDest));
		ReturnDatabaseSizes( atoi(sRouter), &iRouterSize, &x );
		Debug("router db size is %d", iRouterSize);
		
		  char sTemp[256];
		  wsprintf(sTemp, "RP %s %s %s",sRouter,sDest,sDest);
		  ec.txrtrcmd(sTemp);
		  Debug("Router destination index changed to %s", sDest);
			Debug("Re Registered with router device number %s, destination number %s", sRouter, sDest);*/
			char szTemp[BUFFER_LENGTH];
			strcpy(szTemp, sRouter);
			RouterReRegister(szTemp, szSlot);
		}
		return FALSE;
		break;
		
	case LAST_SOURCE_SLOT:
		if (iReRoute_LastSource == 1)
			// Re Register with router
		{
			//			wsprintf(sLastSource, "%s", szSlot);
			//			Debug( "Last source updated by LastSource automatic to %s", sLastSource );
			Debug("Was Last Source Slot - Not used");
		}
		return FALSE;
		break;
		
	default:
		Debug("Slot change function from device %d - slot %d has changed to '%s'",iDevice,iSlot,szSlot);
		return FALSE;
		//return true;
	}
	
	return TRUE;
}

//
//  FUNCTION: CSIClientNotify()
//
//  PURPOSE: Callback function for incoming CSI messages for client class
//
//  COMMENTS: the message is supplied in szMsg
LRESULT CSIClientNotify(extclient* pec,LPCSTR szMsg)
{
	//UINT i;
	//int iTemp=0;
	char sTemp[BUFFER_LENGTH];
	char szDebug[BUFFER_LENGTH];
	bncs_string strCmd;
	UpdateCounters();
	switch (pec->getstate())
	{
	case REVTYPE_R:
		{
			bncs_stringlist slSearchSources ="";
			int	iRevDevice=atoi(pec->getparam(1));
			int iRevDest =atoi(pec->getparam(2)); 
			int iRevSource = atoi(pec->getparam(3));
			//find range
			int intRange = 80;
			
			ei.getslot(RANGE_SLOT,sTemp);
			intRange=atoi(sTemp);
			
			
			
			Debug("Revertive from router %d, dest %d, source is %d", iRevDevice, iRevDest, iRevSource);
			if(iRevDevice == atoi(sRouter) )
			{				
				//Debug("router revertive Source is %d ", iRevSource);
				//Get all the equivalent sources from the HDSD routerShim if we're in the vision router
				if(atoi(sRouter) == iVisionRouter)
				{	
					if(rsh)
					{
						bncs_string sSourceInfo = rsh->getSourceInfo(iRevSource);
						if(sSourceInfo.length()>0 && sSourceInfo.contains(','))
						{
							bncs_string s1,s2,s3,sTemp;
							sSourceInfo.split(',',s1,sTemp);
							sTemp.split(',',s2,s3);
							//Debug("Revertive - Source Info is %d, %d, %d",s1.toInt(),s2.toInt(),s3.toInt());
							if(s1.toInt()>0)
							{
								slSearchSources.append(s1);
							}
							if(s2.toInt()>0)
							{
								slSearchSources.append(s2);
							}
							if(s3.toInt()>0)
							{
								slSearchSources.append(s3);
							}
						}
					}
					
					
				}
				//search for sources in the array and light the correct button!!
				if(fQuartz3201 || fQuartz_Label)
				{
					
					Debug("Router Revertive - Searching Source Array..for source(s) - Quartz");
					
					int i=0;
					int iFoundButton =0;
					bool bFound = false;
					if(slSearchSources.count()>0)
					{
						for( bncs_stringlist::iterator it = slSearchSources.begin() ; it != slSearchSources.end() ; ++it )
						{
							for(i=1; i < MAX_NUMBER_OF_SOURCES +1; i++)
							{
								bncs_string s = *it;
								if(iSourceArray[i] == atoi(s))
								{
									//Debug("SString Search = FFFound %d at button %d",atoi(s) ,i);
									bFound = true;
									iFoundButton = i;
									break;
								}
								
							}
						}
						//Debug("String Search - found - button is %d", i);
					}
					else//just use revertive source
					{
						for(i = 1; i < MAX_NUMBER_OF_SOURCES +1; i++)
						{
							if(iSourceArray[i] == iRevSource)
							{
								//Debug("FFFFFFFFFFFFound %d",iRevSource );
								bFound = true;
								iFoundButton = i;
								break;
							}
						}
					}
					
					
					Debug("Revertive Search result is %d, button is %d",bFound,iFoundButton);
					
					if(fQuartz3201 == 1)
					{//moved to here to capture routes to this destination not requested by this automatic
						
						if(bFound == true && iFoundButton)
						{//go through all the buttons, make them unlit except for the found one
							
							
							if(bFound == true)
							{
								Debug("fQuartz 3201 - Colour button Light %d", iFoundButton);
								//wsprintf(sTemp, "IW %d '1' %d", iTriggerDevice, iFoundButton + Q3201_COLOUR_SLOT_OFFSET);	//turn on corresponding lamp
								//ec.txinfocmd(sTemp);
								strCmd = bncs_string("IW %1 '%2' %3").arg(iTriggerDevice).arg(iQuartzLightColourState).arg(iFoundButton + Q3201_COLOUR_SLOT_OFFSET);
								ec.txinfocmd(strCmd);
								
								//moved to here to capture routes to this destination not requested by this automatic
								if(iFoundButton != iLastTriggerUsed)
								{
									Debug("fQuartz 3201 -  Colour button Dark %d", i);
									strCmd = bncs_string("IW %1 '%2' %3").arg(iTriggerDevice).arg(iQuartzDarkColourState).arg(iLastTriggerUsed + Q3201_COLOUR_SLOT_OFFSET);
									ec.txinfocmd(strCmd);
									iLastTriggerUsed = iFoundButton;
								}
								
							}
							else
								
							{
								Debug("fQuartz 3201- Router revertive not in source list so colour turning off last lamp %d",i);
								strCmd = bncs_string("IW %1 '%2' %3").arg(iTriggerDevice).arg(iQuartzDarkColourState).arg(iLastTriggerUsed + Q3201_COLOUR_SLOT_OFFSET);
								ec.txinfocmd(strCmd);	
								iLastTriggerUsed = 0;
							}
							
							
						}
						//added this condition which was missing - if the source routed is not on one of the buttons....
						else
								
						{
							Debug("fQuartz 3201- Router revertive not in source list so colour turning off last lamp %d",i);
							strCmd = bncs_string("IW %1 '%2' %3").arg(iTriggerDevice).arg(iQuartzDarkColourState).arg(iLastTriggerUsed + Q3201_COLOUR_SLOT_OFFSET);
							ec.txinfocmd(strCmd);	
							iLastTriggerUsed = 0;
						}
						
					}
					else if(fQuartz_Label == 1)
					{	
						if(bFound == true && iFoundButton)	
						{
							
							for(i=1 ; i<= intRange; i++)
							{
								if(i== iFoundButton)
								{
									//wsprintf(sTemp, "IW %d '' %d", iTriggerDevice, iFoundButton + CP1000_COLOUR_SLOT_OFFSET);
									strCmd = bncs_string("IW %1 '%2' %3").arg(iTriggerDevice).arg(iQuartzLightColourState).arg(i + CP1000_COLOUR_SLOT_OFFSET);
									ec.txinfocmd(strCmd);
									Debug("Quartz Cp1000 _ Colouring Button Light %d", i);
								}
								else
								{
									//wsprintf(sTemp, "IW %d '3' %d",iTriggerDevice, (i + CP1000_COLOUR_SLOT_OFFSET));
									strCmd = bncs_string("IW %1 '%2' %3").arg(iTriggerDevice).arg(iQuartzDarkColourState).arg(i + CP1000_COLOUR_SLOT_OFFSET);
									ec.txinfocmd(strCmd);
									Debug("Quartz Cp1000 - Colouring Button Dark %d",i );
									
								}
								
							}
							iLastTriggerUsed = iFoundButton;
						}
						else
						{
							for(i = 1; i<= intRange; i++)
							{
							Debug("Quartz Cp1000 -Router revertive not in source list so turning off last lamp");
						//	wsprintf(sTemp, "IW %d '3' %d", iTriggerDevice, i + CP1000_COLOUR_SLOT_OFFSET);
							Debug("Quartz Cp1000 - Colouring Button Dark %d", i);
						
							bncs_string strCmd = bncs_string("IW %1 '%2' %3").arg(iTriggerDevice).arg(iQuartzDarkColourState).arg(i + CP1000_COLOUR_SLOT_OFFSET);
							ec.txinfocmd(strCmd);
							}
						}	
					}
				}
				if(iFirstGPIO > 1)	//light GPI buttons
				{
					Debug("Searching Source Array....First GPO.");
					int i=0;
					int iFoundButton =0;
					bool bFound = false;
					if(slSearchSources.count()>0)
					{
						for( bncs_stringlist::iterator it = slSearchSources.begin() ; it != slSearchSources.end() ; ++it )
						{
							for(i=1; i < (iFirstGPIO - 1); i++)
							{
								bncs_string s = *it;
								if(iSourceArray[i] == atoi(s))
								{
									//Debug("FFFFFFFFFFFFound %d at button %d",atoi(s) ,i);
									bFound = true;
									iFoundButton = i;
									break;
								}
							}
						}
						//Debug("FFFFFFFFFFFFound - button is %d", i);
					}
					else//just use revertive source
					{
						for(i = 1; i < (iFirstGPIO - 1); i++)
						{
							if(iSourceArray[i] == iRevSource)
							{
								//Debug("FFFFFFFFFFFFound %d",iRevSource );
								bFound = true;
								iFoundButton = i;
								break;
							}
						}
					}
					//iTemp=atoi(pec->getparam(3));
					
					Debug("Search result is %d, button is %d",bFound,iFoundButton);
					//	for(i = 1; i < (iFirstGPIO - 1); i++)
					//{
					if(bFound == true)
					{
						Debug("Lighting button %d", i);
						wsprintf(sTemp, "GS %d %d 1", iTriggerDevice, iFoundButton + (iFirstGPIO - 1));	//turn on corresponding lamp
						ec.txgpicmd(sTemp);
						
						//moved to here to capture routes to this destination not requested by this automatic
						if( iLastTriggerUsed > 0 )
						{
							wsprintf(sTemp, "GS %d %d 0",iTriggerDevice, (iLastTriggerUsed + (iFirstGPIO - 1)));	//turn off last lit lamp
							ec.txgpicmd(sTemp);
						}
						
						iLastTriggerUsed = iFoundButton;
						
						break;
					}
					//	}
					if(i == (iFirstGPIO - 1))	//if source not in list routed by external app turn off last lamp
						//first GPIO should be one more than number of GPI inputs
					{
						Debug("Router revertive not in source list so turning off last lamp");
						wsprintf(sTemp, "GS %d %d 0",iTriggerDevice, (iLastTriggerUsed + (iFirstGPIO - 1)));
						ec.txgpicmd(sTemp);
						iLastTriggerUsed = 0;
					}
				}
			}
			
			
			else	// to try to locate some spurious revertives (possibly from the Studer, device 131)
			{
				Debug("REVERTIVE FROM WRONG ROUTER!!   Router %d rather than %d", iRevDevice, atoi(sRouter) );
			}
			
			break;
		}
		break;
	case REVTYPE_I:
		{
			bncs_string sInfodriver = pec->getparam(1);
			bncs_string sSlotNum = pec->getparam(2);
			int iSlotNum = atoi(sSlotNum);
			bncs_string sSlotContent = pec->getparam(4);
			//remove quotes!!!!!!!!!
			sSlotContent.remove(0,1);
			sSlotContent.remove(sSlotContent.length() -1,1);
			char szContent[256] ;
			strcpy(szContent,sSlotContent);
			int iContent = atoi(sSlotContent);
			
			//iTemp=atoi(pec->getparam(1));
			Debug("Revertive from infodriver %d index %d, contents %s, %d", atoi(sInfodriver), iSlotNum, szContent,iContent);
			
			if(atoi(sInfodriver) == iTriggerDevice)
			{
				Debug("TRIGGER Info Revertive");
				if (iReRoute_LastSource == 1)
				{
					//	fLastSourceTimeOut = 1;
					//SetTimer(ghWnd, LASTSOURCETIMER, LASTSOURCEDELAY, NULL);
				}
				
				//Process revertives from Trigger Infodriver
				if(iDTMFSlot > 0)
				{
					//get rid of the "''" surrounding the slot content
					bncs_string strIndexQuoted = pec->getparam(4);
					int iLength = strIndexQuoted.length();
					bncs_string strIndex = strIndexQuoted.remove((iLength-1), 1);
					strIndex.remove(0, 1);
					//then change it to numeric
					int iIndex = strIndex.toInt();
					Debug("TRIGGER - - index=%d",iIndex);
					char sSceFromSlot[256];
					ei.getslot(iIndex, sSceFromSlot);
					
					SendRouterCrosspoint(pec,atoi(sSceFromSlot));
					wsprintf(sTemp, "IW %d %d %d",iTriggerDevice, iIndex, iDTMFRevertiveSlot);
					ec.txinfocmd(sTemp);
				}
				else
				{
					Debug("TRIGGER Slot %d",iSlotNum);
					//param 2 is slot number
					int iTrigger = (iSlotNum - iOffset);
					if(iMaskArray[iTrigger] == 1 || (iMaskInfodriver == 0))
					{
						if (strcmp("'1'", pec->getparam(4)) == 0)
							TriggerSet(pec);
						else
							TriggerRelease(pec);
					}
					else
						if (strcmp("'1'", pec->getparam(4)) == 0)
							Debug("Trigger %d masked out", iTrigger);
				}
			}
			else if(atoi(sInfodriver) == iMaskInfodriver)	//if not the trigger Infodriver assume it must be the Mask Infodriver
				//which allocates individual joysticks to LVA 1 or 2
			{
				//get rid of the "''" surrounding the slot content
				bncs_string strIndexQuoted = pec->getparam(4);
				int iLength = strIndexQuoted.length();
				bncs_string strIndex = strIndexQuoted.remove((iLength-1), 1);
				strIndex.remove(0, 1);
				
				int iIndex=(atoi(pec->getparam(2)));	//get slot number
				wsprintf(sTemp, strIndex);
				if (strcmp(sMaskString, strIndex) == 0)
				{
					iMaskArray[iIndex] = 1;	//slot content matches Mask string
					Debug("Trigger number %d ENABLED by mask text string %s", iIndex, sTemp);
				}
				else
				{
					iMaskArray[iIndex] = 0;	//slot content does not match Mask string
					Debug("Trigger number %d disabled by mask text string %s", iIndex, sTemp);
				}
			}
			else if(atoi(sInfodriver) == iTBSDriverNo && iSlotNum== iTBSSlot)
			{
				Debug("Rtr_Trig - - revertive from TBS - set Mode to %s, %d", szContent, iContent);
				
				iTBSState = iContent;
				if(rsh)
					rsh->setTBSMode(iContent);
			}
		}
		break;
		
	case REVTYPE_G:
		{
			Debug("TRIGGER GPI Revertive");
			//Process revertives from Trigger GPI driver
			/*	if (iReRoute_LastSource == 1)
			{
			//	fLastSourceTimeOut = 1;
			//SetTimer(ghWnd, LASTSOURCETIMER, LASTSOURCEDELAY, NULL);
		}*/
			//param 2 is slot number
			int iTrigger = ((atoi(pec->getparam(2))) - iOffset);
			if(iMaskArray[iTrigger] == 1 || (iMaskInfodriver == 0))
			{
				wsprintf(sTemp, pec->getparam(4));
				if (strcmp("'1'", pec->getparam(4)) == 0)
					TriggerSet(pec);
				else
					TriggerRelease(pec);
			}
			else
				if (strcmp("'1'", pec->getparam(4)) == 0)
					Debug("Trigger %d masked out", iTrigger);
		}
		break;
		
	case DATABASECHANGE:
		{
			
			Debug ("Database change message - %s",szMsg);
			//	for (i=0;i<pec->getparamcount();Debug("Param %d is %s",++i,pec->getparam(i)));
			
			int iDevice = atoi(pec->getparam(1));
			int iDatabase = atoi(pec->getparam(2));
			int iIndex =atoi(pec->getparam(3));
			//	Debug("Dev is %d, vis router is %d, db is %d",iDevice,iVisionRouter, iDatabase);
			//if(iDevice == iVisionRouter && iDatabase == LAST_SOURCE_DATABASE)
			if(iDevice == atoi(sRouter) && iDatabase == LAST_SOURCE_DATABASE)
			{
				strcpy(szDebug,sDest);
				//	Debug("Index is %d, our dest is %s",iIndex,szDebug);
				if(iIndex == atoi(sDest))//it's our dest
				{
					char sdbName[BUFFER_LENGTH];
					//Debug("Database Callback - It's ours!!!! ");
					pec->getdbname(iDevice,LAST_SOURCE_DATABASE,iIndex,sdbName,BUFFER_LENGTH);
					iLastSource = atoi(sdbName);
					Debug("Database Callback - It's ours!!!! - get name - its %s, %d - Storing Last Source",sdbName,iLastSource);
				}
			}
			//TODO: Add parsing function for database changes
		}
		break;
		
	case STATUS:
		Debug("Status message is %s",szMsg);
		break;
		
	case DISCONNECTED:
		Debug("CSI has closed down");
		DestroyWindow(hWndMain);
		break;
	}
	
	// always return TRUE so CSI doesn't delete your client registration */
	return TRUE;
}

void	LoadConfig(void)
{
	int iTemp=0;
	int iGPITemp=0;
	char sTemp[256];
	int iSource=0;
	int iRange=0;
	iTriggerDevice=0;
	int iRouter=0;
	int iDest=0;

	char szFileName[32];
	char szMessage[BUFFER_LENGTH];
	char szSection [MAX_LOADSTRING];

	// First perform initialization
	for(iTemp = 1; iTemp < NUMBER_OF_TRIGGERS; iTemp++)		//clear arrays
	{
		iTriggerArray[iTemp] = 0;
		iMaskArray[iTemp] = 0;
	}

	//special for Directors Quartz panel Studer tielines - get rid of
//	ec.regtallyrange( TIELINED_ROUTER, TIELINE_DEST, TIELINE_DEST);

	wsprintf(sSource,"");
	wsprintf(sRouter,"");
	wsprintf(sDest,"");

	wsprintf(szFileName,"DEV_%03d.ini",iDevice);
	LoadString(hInst, IDS_SECTION, szSection, MAX_LOADSTRING);
	iTemp=atoi(r_p(szFileName,szSection,"Trigger_Device_Number","0",TRUE));
	wsprintf(sTemp, "%d", iTemp);
	ei.setslot(TRIGGER_DEVICE_NUMBER_SLOT, sTemp);
	Debug("Trigger device number %d", iTemp);
	iTriggerDevice=iTemp;
	if(iTriggerDevice==0)
		Debug("ERROR _ NO Trigger Device SET");

	iRange=atoi(r_p(szFileName,szSection,"Range","0",TRUE));
	if ((iRange == 0) || (iRange > MAX_NUMBER_OF_SOURCES))
	{
		ei.setslot(RANGE_SLOT, "80");
		Debug("Range not set, default is 80");
		iRange=MAX_NUMBER_OF_SOURCES;
	}
	else
	{
		wsprintf(sTemp, "%d", iRange);
		ei.setslot(RANGE_SLOT, sTemp);
		Debug("Range is %s", sTemp);
	}

	iOffset=atoi(r_p(szFileName,szSection,"Offset","0",TRUE));
	wsprintf(sTemp, "%d", iOffset);
	ei.setslot(OFFSET_SLOT, sTemp);
	Debug("Offset is %s", sTemp);

	iTemp=atoi(r_p(szFileName,szSection,"DTMF_Box_Number","0",TRUE));
	iDTMFSlot = ((iTemp * 2) - 1);			//DTMF boxes send switch no. pressed to odd slot
	iDTMFRevertiveSlot = (iDTMFSlot + 1);		//and revertive returned to even slot
	Debug("DTMF Box number is %i", iTemp);

	// Register with Trigger device
	if(iDTMFSlot > 0)
	{
		ec.regtallyrange(iTriggerDevice,iDTMFSlot,iDTMFSlot);
		Debug("DTMF Trigger device %d registered from index %d to %d",iTriggerDevice,iDTMFSlot,iDTMFSlot);
	}
	else
	{
		ec.regtallyrange(iTriggerDevice,(iOffset +1),(iOffset + iRange));
		Debug("Trigger device %d registered from index %d to %d",iTriggerDevice,(iOffset +1),(iOffset + iRange));
	}

	//The Mask string is text in a 'Mask' infodriver slot that if matched
	//enables the trigger of the same number to occur

	wsprintf(sMaskString, r_p(szFileName,szSection,"Mask_String","",TRUE));

	iMaskInfodriver = atoi(r_p(szFileName,szSection,"MaskInfodriver","0",TRUE));
	if (iMaskInfodriver > 0)
	{
		ec.regtallyrange(iMaskInfodriver,1,iRange);
		Debug("Mask text string is %s", sMaskString);
		Debug("Mask Infodriver %d registered from index 1 to %d",iMaskInfodriver, iRange);
		wsprintf(sTemp, "IP %d 1 %d",iMaskInfodriver, iRange);
		ec.txinfocmd(sTemp);
	}
	
	fQuartz3201=atoi(r_p(szFileName,szSection,"Quartz3201/6401","0",TRUE));
	wsprintf(sTemp, "%d", fQuartz3201);
//	Debug("Quartz 3201/6401 flag is %s, write to dev %d from %d", sTemp,iTriggerDevice,(iTemp +100));
	if(fQuartz3201 == 1)
	{
		//set Quartz Colour states
		iQuartzLightColourState = 1;
		iQuartzDarkColourState = 0;

		for(iTemp=1; iTemp < MAX_NUMBER_OF_SOURCES +1; iTemp++)	//colour all quartz buttons to 'OFF' = 0
		{
			bncs_string strCmd = bncs_string("IW %1 '%2' %3").arg(iTriggerDevice).arg(iQuartzDarkColourState).arg(iTemp + Q3201_COLOUR_SLOT_OFFSET);
			ec.txinfocmd(strCmd);
		}
	}
	
	fQuartz_Label=atoi(r_p(szFileName,szSection,"Quartz_Label","0",TRUE));
	wsprintf(sTemp, "%d", fQuartz_Label);
	Debug("Quartz panel assignable label flag is %s", sTemp);
	if(fQuartz_Label == 1)
	{		
		//set Quartz Colour states
		iQuartzLightColourState = 6;
		iQuartzDarkColourState = 1;

		for(iTemp=1; iTemp < NUMBER_OF_TRIGGERS; iTemp++)	//colour all quartz buttons to dark GREEN = 1
		{
			bncs_string strCmd = bncs_string("IW %1 '%2' %3").arg(iTriggerDevice).arg(iQuartzDarkColourState).arg(iTemp + CP1000_COLOUR_SLOT_OFFSET);
			ec.txinfocmd(strCmd);
		}
	}

	iFirstGPIO=atoi(r_p(szFileName,szSection,"FirstGPIO","0",TRUE));
	wsprintf(sTemp, "%d", iFirstGPIO);
	Debug("First GPIO is %s  [0 = none]", sTemp);
	if( iFirstGPIO > 0 )
	{
		Debug("Re-setting GPIOs");
		for(iSource=1;iSource<(iRange + 1);iSource++)
		{
			wsprintf(sTemp, "GS %d %d 0",iTriggerDevice, (iSource + (iFirstGPIO - 1)));	//turn off lamp
			ec.txgpicmd(sTemp);
		}
	}
		//Router Config
		iRouter=atoi(r_p(szFileName,szSection,"Default_Router_Device_Number","0",TRUE));
		wsprintf(sRouter, "%d", iRouter);
		ei.setslot(ROUTER_SLOT, sRouter);
		Debug("Default router device number is %s", sRouter);
		//Dest
		iDest=atoi(r_p(szFileName,szSection,"Default_Destination_Number","0",TRUE));
		wsprintf(sDest, "%d", iDest);
		ei.setslot(DESTINATION_SLOT, sDest);
		Debug("Default destination number is %s", sDest);
		
		//Last Source settings
		iReRoute_LastSource=atoi(r_p(szFileName,szSection,"ReRoute_LastSource","0",TRUE));
		wsprintf(sTemp, "%d", iReRoute_LastSource);
		ei.setslot(REROUTE_SLOT, sTemp);
		Debug("Re Route Last Source flag is %s", sTemp);
		iSave_LastSource = atoi(r_p(szFileName,szSection,"Save_LastSource", "1", TRUE));
		wsprintf(sTemp,"%d", iSave_LastSource);
		Debug("Save_LastSource flag is %s",sTemp); 

		if(iRouter>0 && iDest>0)
		{
			
			ec.regtallyrange(iRouter,iDest,iDest);
			ReturnDatabaseSizes( atoi(sRouter), &iRouterSize, &x );
			Debug("router db size is %d", iRouterSize);
			//polling
			wsprintf(szMessage,"RP %d %d %d",iRouter, iDest, iDest);
			ec.txrtrcmd(szMessage);
			//wsprintf(sLASTSOURCEPOLL, "RP %d %d %d",iRouter,iDest,iDest);
			//	ec.txrtrcmd(sLASTSOURCEPOLL);
			Debug("Registered with router device number %d, destination number %d", iRouter, iDest);
			//next line added to provide default lastsource, because if router is running up when this
			//program starts no router poll is returned, so no lastsource, and joysticks
			//appear to 'latch'
			//SetTimer(ghWnd, LASTSOURCEPOLLTIMER, LASTSOURCEPOLLDELAY, NULL);	//ghWnd not available yet! this is now in InitInstance
			
			if(iReRoute_LastSource && iRouter && iDest)
			{
				
				//read in Last Source from Database 3 - if it doesn't exist make it Mixer Out
				char sdbName[BUFFER_LENGTH];
				ec.getdbname(iRouter,LAST_SOURCE_DATABASE,iDest,sdbName,BUFFER_LENGTH);
				iLastSource = atoi(sdbName);
				
				if(iLastSource==0)
				{
					iLastSource = 341;	//341 is TC4  Virtual 'Mixer Clean'
				}
				Debug("Storing Last Source %d",iLastSource);
				
				
				
			}
			
		}
	fLoad_Defaults=atoi(r_p(szFileName,szSection,"Load_Defaults","1",TRUE));
	wsprintf(sTemp, "%d", fLoad_Defaults);
	Debug("Load_Defaults flag is %s", sTemp);

	if(fLoad_Defaults == 1)
	{
		Debug("");
		Debug("Default source numbers are:");
		for(iSource=1;iSource<(iRange + 1);iSource++)
		{
			wsprintf(sTemp,"Source_%02d",iSource);
			//iTemp=atoi(r_p(szFileName,szSection,sTemp,"0",TRUE));
			//wsprintf(sSource, "%d", iTemp);
			wsprintf(sSource, "%s", (r_p(szFileName,szSection,sTemp,"0",TRUE)));
			ei.setslot(iSource, sSource);
			iSourceArray[iSource] = atoi(sSource);
			Debug("Default source %s is %s", sTemp, sSource);
			if(fQuartz_Label == 1)	//label assignable buttons
			{
				char sTemp[BUFFER_LENGTH];
				char sdbName[BUFFER_LENGTH];
				//ec.getdbname(atoi(sRouter), 0, iTemp, sdbName, 256);
				ec.getdbname(atoi(sRouter), 0, iSourceArray[iSource], sdbName, 256);
				Debug("Writing to Quartz Label %d, name is %s",iSource, sdbName);
				wsprintf(sTemp, "IW %d '%s' %d", iTriggerDevice, sdbName, iSource + 20);
				ec.txinfocmd(sTemp);
			}
		}
	}
	else
	{
		Debug("");
		Debug("Current source numbers are:");
		for(iSource=1;iSource<(iRange + 1);iSource++)
		{
			ei.getslot(iSource, sSource);
			//TODO This isn't used in TC8
			if(!strncmp(sSource, "Tieline", 7))
			{
				bncs_string p1;
				bncs_string p2;
				bncs_string s = sSource;
				s.split( '|', p1, p2 );
				//bncs_string cmd = bncs_string("RC %1 %2 %3 1").arg(TIELINED_ROUTER).arg(sRemoteSource).arg(TIELINE_DEST);
				iTielineSourceArray[iSource] = atoi(p2);
				iSourceArray[iSource] = 0;
			}
			else
			{
				iSourceArray[iSource] = atoi(sSource);
				iTielineSourceArray[iSource] = 0;
			}

			Debug("Current source %d is %s", iSource, sSource);
		}
	}
	//get TheBigSwitch device and slot and register for it
	char type;
	getDevSlot("TheBigSwitch", "standard", &iTBSDriverNo, & iTBSSlot, & type);
	//Debug("DDDDDDDDDDDDRIver is %d, slot is %d, type is %d", iTBSDriverNo,iTBSSlot,type);
	if(iTBSDriverNo>0 && iTBSSlot >0 && type == 'I')
	{
		ec.regtallyrange(iTBSDriverNo,iTBSSlot,iTBSSlot);
		Debug("TBS Infodriver %d registered slot %d",iTBSDriverNo, iTBSSlot);
		wsprintf(sTemp, "IP %d 1 %d",iTBSDriverNo, iTBSSlot);
		ec.txinfocmd(sTemp);
	}
	//get Vision Router Device and store
	iVisionRouter = getInstanceDevice("sdi_router");
	Debug("Rtr_Trig - the dual Standard Vision router is %d", iVisionRouter);
	SetDlgItemText(hWndDlg,IDC_AUTO_STATUS,"Running...");
}

void SendRouterCrosspoint(extclient* pec, int iSceFromSlot)
{
	char szDebug[BUFFER_LENGTH];
	if( iSceFromSlot > 0 )
	{
		int intRouterDevice = atoi(sRouter);
	//	int intSourceIndex = atoi(sSource);
		int intSourceIndex= iSceFromSlot;
		int intDestIndex = atoi(sDest);
		//Debug("SendRouterCrosspoint - Dev is %d, Source is %d, dest is %d",intRouterDevice,intSourceIndex,intDestIndex);
		if(intRouterDevice == iVisionRouter)
		{
			//Debug("Router is Vision Router - get special source");
			intSourceIndex = rsh->getSpecialSource(intSourceIndex, intDestIndex, ROUTE_FOLLOW);
		//need to check SaveLastSource flag too----------		
			if(iSave_LastSource && LastSce)
			{
			//	Debug("Save Last Source,?????");
				bool b = LastSce->CheckLastSce(intRouterDevice,intDestIndex);
				if(b==true)
				{
					Debug("Saving last source........RM");
					char szSource[BUFFER_LENGTH];
					sprintf(szSource,"%d", intSourceIndex);
					pec->setdbname(intRouterDevice,LAST_SOURCE_DATABASE,intDestIndex,szSource,false);
				}
			}
		}
		if(intSourceIndex){
			bncs_string strCommand = bncs_string("RC %1 %2 %3")
				.arg(intRouterDevice).arg(intSourceIndex).arg(intDestIndex);
			pec->txrtrcmd(strCommand,NOW);
			strcpy(szDebug,strCommand);
			Debug("Send Router Crosspoint %s",szDebug);
		}

	}
	else
	{
		Debug("No source so router crosspoint command inhibited");
	}
}

void	TriggerSet(extclient* pec)
{
	int i=0;
	int iTrigger=0;
	char sTemp[BUFFER_LENGTH];
	iTrigger=((atoi(pec->getparam(2))) - iOffset);
	Debug("Trigger number %d set", iTrigger);
	if(fQuartz3201 == 1)
	{
		
		//moved to router revertive code
		//wsprintf(sTemp, "IW %d '0' %d",iTriggerDevice, (iLastTriggerUsed + 100));
		//ec.txinfocmd(sTemp);
		//iLastTriggerUsed = iTrigger;
		
		//wsprintf(sTemp, "IW %d '1' %d",iTriggerDevice, (iTrigger + 100));
		//ec.txinfocmd(sTemp);
	}
	else
		if(fQuartz_Label == 1)
		{
//			wsprintf(sTemp, "IW %d '3' %d",iTriggerDevice, (iLastTriggerUsed + 40));
//			ec.txinfocmd(sTemp);
//			Debug("RTR_Trigger - Trigger Set Quartz Labels...- %s",sTemp);
//			iLastTriggerUsed = iTrigger;
			//indicate button has been pressed prior to router revertive
			wsprintf(sTemp, "IW %d '1' %d",iTriggerDevice, (iTrigger + 40));
			ec.txinfocmd(sTemp);
		}
		else
		{
			if(iTrigger < NUMBER_OF_TRIGGERS)
				iTriggerArray[iTrigger] = 1;
			for(i = 1; i < (iTrigger); i++)	//check there isn't a lower trigger already - joystick feature
			{
				if(iTriggerArray[i] == 1)
					return;
			}
		}
		
		//addition.  check slot content to see if it holds a router + dest, or just a source number
		ei.getslot(iTrigger, sTemp);	//get content from host sources slot
		if(!strncmp(sTemp, "Router=", 7))
		{
			bncs_string s = sTemp;	//**********************************************************************
			bncs_string p1;
			bncs_string p2;
			bncs_string p3;
			bncs_string p4;
			bncs_string p5;
			bncs_string p6;
			s.split( '|', p1, p2 );
			p1.split( '=', p3, p4 );
			p2.split( '=', p5, p6 );
			
			int iRouter = atoi(p4);
			int iDest = atoi(p6);
			
			char szTempRtr[256];
			char szTempDest[256];
			strcpy(szTempRtr,p4);
			strcpy(szTempDest,p6);
			RouterReRegister(szTempRtr,szTempDest);
			/*if(atoi(sRouter))
			ec.unregtallyrange(atoi(sRouter));
			ec.regtallyrange(iRouter,iDest,iDest);
			ReturnDatabaseSizes( atoi(sRouter), &iRouterSize, &x );
			Debug("router db size is %d", iRouterSize);
			wsprintf(sTemp, "RP %d %d %d",iRouter,iDest,iDest);
			ec.txrtrcmd(sTemp);*/
			//Debug("Router changed to %d and destination changed to %d", iRouter, iDest );
			//Debug(bncs_string("Trigger Set () - Router changed to %1 and destination changed to %2").arg(p1).arg(p2) );
			//Debug("Router changed to %s and destination changed to %s", p1, p2 );
			
			ei.setslot(ROUTER_SLOT, p4);	//101 is router slot
			ei.setslot(DESTINATION_SLOT, p6);	//102 is destination slot
			
			if(fQuartz3201 == 1)
				if(iTrigger != iLastDestButton)	//check not the same to avoid writing 0 then 1 to same slot in case messages arrive in reverse order
				{
					wsprintf(sTemp, "IW %d '0' %d",iTriggerDevice, (iLastDestButton + 100));	//turn off last lit dest lamp
					ec.txinfocmd(sTemp);
					Debug("Trigger Set - Qtz3201 - turning off lamp %d",iLastDestButton);
					wsprintf(sTemp, "IW %d '1' %d",iTriggerDevice, (iTrigger + 100));	//turn on new dest lamp
					ec.txinfocmd(sTemp);
					Debug("Trigger Set - Qtz3201 - turning ON lamp %d",iTrigger);
					iLastDestButton = iTrigger;
				}
		}
		else
		{
			//Make Crosspoint
			char sSceFromSlot[256];
			ei.getslot(iTrigger, sSceFromSlot);
		//	ei.getslot(iTrigger, sSource);	//get current source from host sources slot
			SendRouterCrosspoint(pec,atoi(sSceFromSlot));
		
		}
}

void	TriggerRelease(extclient* pec)
{
	int i;
	int iTrigger;
	iTrigger=((atoi(pec->getparam(2))) - iOffset);
	Debug("Trigger number %d released", iTrigger);
	if(iTrigger < NUMBER_OF_TRIGGERS)
	{
		iTriggerArray[iTrigger] = 0;
		for(i = 1; i < NUMBER_OF_TRIGGERS; i++)
		{
			if(iTriggerArray[i] == 1)
			{
				Debug("Trigger %d is now lowest so has priority", i);
				char sSceFromSlot[256];
				ei.getslot(i, sSceFromSlot);
			//	ei.getslot(i, sSource);
				SendRouterCrosspoint(pec,atoi(sSceFromSlot));
				return;
			}
		}
	}
	if(iReRoute_LastSource == 1)
	{
		//Debug("ReRouting 'last source' set in slot 99");
		//ei.getslot(99, sSource);				//TEMPORARILY GET 'last source' FROM SLOT 99
		Debug("ReRouting 'last source'");
		wsprintf(sSource, "%d",iLastSource);		//no triggers set so reroute 'last source'
		//just make the cross point cleanly
	bncs_string strCommand = bncs_string("RC %1 %2 %3")
				.arg(atoi(sRouter)).arg(iLastSource).arg(atoi(sDest));
			pec->txrtrcmd(strCommand,NOW);
	//	SendRouterCrosspoint(pec,atoi(sSource));
	}
}

void ReturnDatabaseSizes( int iDevice, int *db0, int *db1 )
{
        // get filename
        char szFileName[32]= "";
		wsprintf(szFileName,"DEV_%03d.ini",iDevice);		
		// extract from lcf db0 database size
        char szStr0[BUFFER_LENGTH]= "", szStr1[BUFFER_LENGTH]= "";
		strcpy( szStr0, r_p( szFileName,"Database","DatabaseSize_0","0",FALSE) );      // get db size 0
		strcpy( szStr1, r_p( szFileName,"Database","DatabaseSize_1","0",FALSE) );      // get db size 1
		
		// then turn strings into integers if required....
                *db0 = atoi( szStr0 );
                *db1 = atoi( szStr1 );
}
/////////////////////////////////////////////////
//
//void RouterReRegister(char* szRouter, char * szDest)
//
//PURPOSE: If the Router or destination change, we need to unregister with old and re register with the new
//also we may need to destroy or create an instance or the router Shimm class, depending on whether the old or new router corresponds to the vision router
//
//
////////////////////////////////////////
void RouterReRegister(const char* szRouter,const  char * szDest)
{
	//locals
	int iNewRouter = atoi(szRouter);
	int iNewDest = atoi(szDest);
	int iOldRouter = atoi(sRouter);
	int iOldDest = atoi(sDest);
	char szMessage[BUFFER_LENGTH];
	//store globals
	wsprintf(sRouter, "%s", szRouter);
	wsprintf(sDest,"%s", szDest);

	Debug("RtrTrig - RouterReRegister() - new router is %d new dest is %d, old rtr is %d, old dest is %d",iNewRouter,iNewDest, iOldRouter, iOldDest);

	
	if(iNewRouter != iOldRouter)
	{
		if(iOldRouter && iOldRouter == iVisionRouter)
		{
			//delete shimm
			if(rsh)
			
				delete rsh;
				rsh=0;
		}
		if(iNewRouter && iNewRouter== iVisionRouter)
		{
			//create new shimm
				rsh = new routerShim(iVisionRouter);
				rsh->setTBSMode(iTBSState);
		}

//		Clear_Source_Configuration();//we are changing router so existing source labels and indices mean nothing
//will leave this function call out for now cos a bit drastic		
	}
	else
	{
		//don't need to do anything with shimm - just reregister with new dest
	}
	//unregister
	if(iOldRouter)
		ec.unregtallyrange(iOldRouter);
	//register with new
	if(iNewRouter && iNewDest)
	{
		ec.regtallyrange(iNewRouter,iNewDest,iNewDest);
		ReturnDatabaseSizes(iNewRouter, &iRouterSize, &x);
		Debug("RTR-Trig - RouterReRegister Register with router %d dest %d - db size is %d", iNewRouter, iNewDest,iRouterSize);
		//poll
		wsprintf(szMessage,"RP %s %s %s",sRouter, sDest, sDest);
		ec.txrtrcmd(szMessage);

	}
}
// this function is called if the user switches to another router instance in which case the existing source slot arrangement is useless and
// the labels on the Quartz buttons (if used) mean nothing so we wipe the slate clean of them too.

void Clear_Source_Configuration(){
	int iSource;
	int iRange;
	char sTemp[256];
	char sEmptySource[1]="";
	


		ei.getslot(RANGE_SLOT,sTemp);
		iRange=atoi(sTemp);
		Debug("Default source numbers are:");
		for(iSource=1;iSource<(iRange + 1);iSource++)
		{
			wsprintf(sTemp,"Source_%02d",iSource);
			//iTemp=atoi(r_p(szFileName,szSection,sTemp,"0",TRUE));
			//wsprintf(sSource, "%d", iTemp);
			
			ei.setslot(iSource, sEmptySource);
			iSourceArray[iSource] = 0;
			Debug("source %s is %s", sTemp, sEmptySource);
			if(fQuartz_Label == 1)	//label assignable buttons
			{
				char sTemp[BUFFER_LENGTH];
				char sdbName[BUFFER_LENGTH] = "";
				//ec.getdbname(atoi(sRouter), 0, iTemp, sdbName, 256);
			//	ec.getdbname(atoi(sRouter), 0, iSourceArray[iSource], sdbName, 256);
				Debug("Writing to Quartz Label %d, name is %s",iSource, sdbName);
				wsprintf(sTemp, "IW %d '%s' %d", iTriggerDevice, sdbName, iSource + 20);
				ec.txinfocmd(sTemp);
			}
		}

}