#include "routerShim.h"
#include "bncs_config.h"
#include "bncs_stringlist.h"
#include <windows.h>

//#include "databasemgr.h"

/** 
\class routerShim
\brief This shared class is used by TC8 Panels and Automatics as a helper for HD, SD and Virtual Routing features

The full requirements that this class implements are defined in SY05 here: \n
<tt>"TC8_PM\7.Project_Delivery_Result\7.3_OtherWorkProducts\SY_System\TC8_SY05 sharedclassfunctions.doc"</tt>

The class should be added to the Panel or Automatic project as follows:

\par Panel Usage

In myPanel.h
\code
private:
	routerShim* rsh;	//pointer to the router shim
\endcode

In myPanel.cpp
\code
// constructor - equivalent to ApplCore STARTUP
myPanel::myPanel( bncs_client_callback * parent, const char * path ) : 
	bncs_script_helper( parent, path )
{
	//Initialise Router Shim
	rsh = new routerShim( intRouter );
}

// destructor - equivalent to ApplCore CLOSEDOWN
myPanel::~myPanel()
{
	//Delete the routerShim when the app shuts down
	delete rsh;
}
\endcode

\par Automatic usage

In myAuto.h
\code
private:
EXT routerShim* rsh;	//pointer to the router shim
\endcode

In myAuto.cpp
\code
LRESULT InitApp(HWND hWnd)
{
	//Initialise Router Shim
	rsh = new routerShim( intRouter );
}

void CloseApp(HWND hWnd)
{
	//Delete the routerShim when the app shuts down
	delete rsh;
}
\endcode
*/

/** 
\param device the router device ID the class should use

\note Database usage for this device id is expected to be as defined in Fig 3 of\n
<tt>"TC8_PM\\7.Project_Delivery_Result\\7.3_OtherWorkProducts\\SY_System\\ \n
   TC8_SY02_Dual_Presented_Sources_Vision system architecture thoughts.doc"</tt>\n
i.e. a db9 entry should contain one of the following values:\n
HD\n
SD\n
PAL\n
VIRTUAL\n
*/
routerShim::routerShim( int device )
{
	
	bncs_string strFile = bncs_string( "%1\\%2\\config\\system\\dev_%3.ini").arg( getenv("CC_ROOT")).arg( getenv( "CC_SYSTEM")).arg( device,'0', 3);

	OutputDebugString( bncs_string("routerShim: filename=%1").arg(strFile) );

	//Set TBS mode to SD initially - the host application will update this via setTBSMode()
	intTBS_mode = TBS_SD;
	
	//Get router dimensions
	maxSources = GetPrivateProfileInt( "Database", "DatabaseSize_0", 0, strFile );
	maxDests = GetPrivateProfileInt( "Database", "DatabaseSize_1", 0, strFile );
	firstVirtual = GetPrivateProfileInt( "GRD", "FirstVirtual", 0, strFile );
	//realSources = firstVirtual - 1;
	//realDests = firstVirtual - 1;

	//OutputDebugString( bncs_string("routerShim: maxSources=%1 maxDests=%2 realSources=%3 realDests=%4")
	//	.arg(maxSources).arg(maxDests).arg(realSources).arg(realDests));

	//Get all source types
	bncs_stringlist sltSourceTypeNames( DEST_TYPE_NAMES );	
	bncs_string strKey;
	char szResult[256];
	strFile = bncs_string( "%1\\%2\\config\\system\\dev_%3.db6").arg( getenv("CC_ROOT")).arg( getenv( "CC_SYSTEM")).arg( device,'0', 3);
	OutputDebugString( bncs_string("routerShim: db9 strFile=%1").arg(strFile));
//	OutputDebugString( bncs_string("routerShim: maxSources=%1 firstVirtual=%2").arg(maxSources).arg(firstVirtual));

	for(int intSource = 1; intSource <= maxSources; intSource++)
	{
		if(intSource >= firstVirtual)
		{
			strcpy(szResult, "VIRTUAL");
			sourceType[ intSource ] = SRCE_VIRTUAL;
		}
		else
		{
			strKey = bncs_string( "%1").arg( intSource,'0', 4);
			GetPrivateProfileString("Database_6", strKey, "-1", szResult, 256, strFile);
			sourceType[ intSource ] = sltSourceTypeNames.find( szResult );
		}

		//OutputDebugString(bncs_string("Source%1=%2 - type=%3").arg(intSource).arg(szResult).arg(sourceType[ intSource ]));
	}

	//Initialise Dest Types
	//DB9 contains Destination type
	//0001=HD
	//0002=SD
	//0003=PAL
	bncs_stringlist sltDestTypeNames( DEST_TYPE_NAMES );	
	strFile = bncs_string( "%1\\%2\\config\\system\\dev_%3.db9").arg( getenv("CC_ROOT")).arg( getenv( "CC_SYSTEM")).arg( device,'0', 3);
	//OutputDebugString( bncs_string("routerShim: db9 strFile=%1").arg(strFile) );
	
	for(int intDest = 1; intDest < firstVirtual; intDest++)
	{
		strKey = bncs_string( "%1").arg( intDest,'0', 4);
		GetPrivateProfileString("Database_9", strKey, "-1", szResult, 256, strFile);
		destType[ intDest ] = sltDestTypeNames.find( szResult );
	//	OutputDebugString(bncs_string("%1=%2 - type=%3").arg(strKey).arg(szResult).arg(destType[ intDest ]));
	}


	//Load source association table
	bncs_config c( "object_settings.Virtual_Router_Associations" );
	if( c.isValid())
	{
		while( c.isChildValid())
		{
			int intSettingID = c.childAttr( "id" );
			bncs_stringlist sl( c.childAttr( "value" ));
			//expecting value to contain "virtual,hd,sd"  e.g. "257,161,33"
	
			if( sl.count() == 3 )
			{
				int intVirtualSource = sl[ VRA_VIRTUAL ];
				virtualToHD[ intVirtualSource ] = sl[ VRA_HD ].toInt();
				virtualToSD[ intVirtualSource ] = sl[ VRA_SD ].toInt();
				HDToVirtual[ sl[ VRA_HD ].toInt() ] = intVirtualSource;
				SDToVirtual[ sl[ VRA_SD ].toInt() ] = intVirtualSource;
				
				//Save the source types for this item
				sourceType[ sl[VRA_VIRTUAL] ] = SRCE_VIRTUAL;
				sourceType[ sl[VRA_HD] ] = SRCE_HD;
				sourceType[ sl[VRA_SD] ] = SRCE_SD;
			}
			c.nextChild();
		}
	}

	
}

routerShim::~routerShim()
{
}

/** Get the associated Virtual, HD and SD indices for a source
\param intSource The source index for which the associated indices are required
\return string containing "<Virtual Source>,<HD Source>,<SD Source>"

Examples:

\code
routerShim* rsh;
rsh = new routerShim(101);
Debug( bncs_string("getSourceInfo(257) returned '%1'")
	.arg(rsh->getSourceInfo(257)) ); //returns "257,161,33"
Debug( bncs_string("getSourceInfo(161) returned '%1'")
	.arg(rsh->getSourceInfo(161)) ); //returns "257,161,33"
Debug( bncs_string("getSourceInfo(33) returned '%1'")
	.arg(rsh->getSourceInfo(33)) ); //returns "257,161,33"
Debug( bncs_string("getSourceInfo(91) returned '%1'")
	.arg(rsh->getSourceInfo(91)) ); //returns "0,0,0"
\endcode

\note When requesting information on a source that is not described in the 
"Virtual_Router_Associations" table the function will return "0,0,0"
 */
bncs_string routerShim::getSourceInfo(int intSource)
{
	int intSourceVirtual = 0;
	int intSourceHD = 0;
	int intSourceSD = 0;

	switch(sourceType[ intSource ])
	{
		case SRCE_VIRTUAL:
			//Check if the source is in the Virtual_Router_Associations table
			if( virtualToSD[ intSource ] && virtualToHD[ intSource] )
			{
				intSourceVirtual = intSource;
				intSourceHD = virtualToHD[ intSource ];
				intSourceSD = virtualToSD[ intSource ];
			}
			break;

		case SRCE_HD:
			//Check if the source is in the Virtual_Router_Associations table
			if( HDToVirtual[ intSource ] )
			{
				intSourceVirtual = HDToVirtual[ intSource ];
				intSourceHD = intSource;
				intSourceSD = virtualToSD[ intSourceVirtual ];
			}
			break;

		case SRCE_SD:
			//Check if the source is in the Virtual_Router_Associations table
			if( SDToVirtual[ intSource ] )
			{
				intSourceVirtual = SDToVirtual[ intSource ];
				intSourceHD = virtualToHD[ intSourceVirtual ];
				intSourceSD = intSource;
			}
			break;
	}

	bncs_string strReturn = bncs_string("%1,%2,%3").arg(intSourceVirtual).arg(intSourceHD).arg(intSourceSD);
	return strReturn;

}

/** Get the associated Virtual index for a source and infer the mode of routing that was used
\param intSource The source index for which the associated virtual index is required
\param intDest The dest index from which the revertive has originated
\return string containing "<Virtual Source>,<Route Mode>"

The Route Mode is defined as follows:\n
\code
enum Route_Mode {
	ROUTE_FOLLOW,	//0 - a real source with no dual presentation
	ROUTE_HD,	//1 - a revertive from an HD source
	ROUTE_SD,	//2 - a revertive from an SD source
	ROUTE_VIRTUAL	//3 - a revertive from a Virtual source
};
\endcode

Examples:

1. Automatic Example
\code
routerShim* rsh;
rsh = new routerShim(intRouter);
Debug( bncs_string("getSpecialRevertive(91,1) returned '%1'")
	.arg(rsh->getSpecialRevertive(91,1)) ); //returns "91,0"
Debug( bncs_string("getSpecialRevertive(161,1) returned '%1'")
	.arg(rsh->getSpecialRevertive(161,1)) ); //returns "257,1"
Debug( bncs_string("getSpecialRevertive(33,1) returned '%1'")
	.arg(rsh->getSpecialRevertive(33,1)) ); //returns "257,2"
Debug( bncs_string("getSpecialRevertive(257,1) returned '%1'")
	.arg(rsh->getSpecialRevertive(257,1)) ); //returns "257,3"
\endcode

2. Panel Example
\code
TODO
\endcode

\note When requesting information on a source that is not described in the 
"Virtual_Router_Associations" table the function will return "<source>,0"
 */
bncs_string routerShim::getSpecialRevertive(int intSource, int intDest)
{
	bncs_string strReturn;
	int intSourceVirtual = intSource;
	int intRouteMode = ROUTE_FOLLOW;

	switch(sourceType[ intSource ])
	{
		case SRCE_VIRTUAL:
			intSourceVirtual = intSource;
			intRouteMode = ROUTE_VIRTUAL;
			break;

		case SRCE_HD:
			intSourceVirtual = HDToVirtual[ intSource ];
			intRouteMode = ROUTE_HD;
			break;

		case SRCE_SD:
		case SRCE_PAL:
			intSourceVirtual = SDToVirtual[ intSource ];
			intRouteMode = ROUTE_SD;
			break;

	}

	strReturn = bncs_string("%1,%2").arg(intSourceVirtual).arg(intRouteMode);
	return strReturn;
}

/** Get the appropriate source to route for the mode of routing that was requested
\param intSource The source index for which the correct index is required
\param intDest The dest index to which the source is to be routed
\param mode The Route Mode to be used - see \ref RouteMode
\return int containing the appropriate source with which to make the route

\section RouteMode
The Route Mode is defined as follows:\n
\code
enum Route_Mode {
	ROUTE_FOLLOW,	//0 - follow the source requested
	ROUTE_HD,	//1 - as HD
	ROUTE_SD,	//2 - as SD
	ROUTE_VIRTUAL	//3 - as Virtual
};
\endcode

\par Examples:

\code
routerShim* rsh;
rsh = new routerShim(intRouter);

//Real Source to SD/PAL Dest
Debug( bncs_string("getSpecialSource(91,1,0) returned '%1'")
	.arg(rsh->getSpecialSource(91,1,0)) ); //returns "91"
Debug( bncs_string("getSpecialSource(91,1,1) returned '%1'")
	.arg(rsh->getSpecialSource(91,1,1)) ); //returns "91"
Debug( bncs_string("getSpecialSource(91,1,2) returned '%1'")
	.arg(rsh->getSpecialSource(91,1,2)) ); //returns "91"
Debug( bncs_string("getSpecialSource(91,1,3) returned '%1'")
	.arg(rsh->getSpecialSource(91,1,3)) ); //returns "91"

//Dual Presented HD Source to HD Dest
Debug( bncs_string("getSpecialSource(161,161,0) returned '%1'")
	.arg(rsh->getSpecialSource(161,161,0)) ); //returns "161"
Debug( bncs_string("getSpecialSource(161,161,1) returned '%1'")
	.arg(rsh->getSpecialSource(161,161,1)) ); //returns "161"
Debug( bncs_string("getSpecialSource(161,161,2) returned '%1'")
	.arg(rsh->getSpecialSource(161,161,2)) ); //returns "33"
Debug( bncs_string("getSpecialSource(161,161,3) returned '%1'")
	.arg(rsh->getSpecialSource(161,161,3)) ); //returns "257"

//Dual Presented HD Source to SD/PAL Dest
Debug( bncs_string("getSpecialSource(161,1,0) returned '%1'")
	.arg(rsh->getSpecialSource(161,1,0)) ); //returns "33"
Debug( bncs_string("getSpecialSource(161,1,1) returned '%1'")
	.arg(rsh->getSpecialSource(161,1,1)) ); //returns "33"
Debug( bncs_string("getSpecialSource(161,1,2) returned '%1'")
	.arg(rsh->getSpecialSource(161,1,2)) ); //returns "33"
Debug( bncs_string("getSpecialSource(161,1,3) returned '%1'")
	.arg(rsh->getSpecialSource(161,1,3)) ); //returns "257" 
					// or "33" if TBS=HD

//Dual Presented SD Source to HD Dest
Debug( bncs_string("getSpecialSource(33,161,0) returned '%1'")
	.arg(rsh->getSpecialSource(33,161,0)) ); //returns "33"
Debug( bncs_string("getSpecialSource(33,161,1) returned '%1'")
	.arg(rsh->getSpecialSource(33,161,1)) ); //returns "161"
Debug( bncs_string("getSpecialSource(33,161,2) returned '%1'")
	.arg(rsh->getSpecialSource(33,161,2)) ); //returns "33"
Debug( bncs_string("getSpecialSource(33,161,3) returned '%1'")
	.arg(rsh->getSpecialSource(33,161,3)) ); //returns "257"

//Dual Presented SD Source to SD/PAL Dest
Debug( bncs_string("getSpecialSource(33,1,0) returned '%1'")
	.arg(rsh->getSpecialSource(33,1,0)) ); //returns "33"
Debug( bncs_string("getSpecialSource(33,1,1) returned '%1'")
	.arg(rsh->getSpecialSource(33,1,1)) ); //returns "33"
Debug( bncs_string("getSpecialSource(33,1,2) returned '%1'")
	.arg(rsh->getSpecialSource(33,1,2)) ); //returns "33"
Debug( bncs_string("getSpecialSource(33,1,3) returned '%1'")
	.arg(rsh->getSpecialSource(33,1,3)) ); //returns "257"
					// or "33" if TBS=HD

//Virtual Source to HD Dest
Debug( bncs_string("getSpecialSource(257,161,0) returned '%1'")
	.arg(rsh->getSpecialSource(257,161,0)) ); //returns "257"
Debug( bncs_string("getSpecialSource(257,161,1) returned '%1'")
	.arg(rsh->getSpecialSource(257,161,1)) ); //returns "161"
Debug( bncs_string("getSpecialSource(257,161,2) returned '%1'")
	.arg(rsh->getSpecialSource(257,161,2)) ); //returns "33"
Debug( bncs_string("getSpecialSource(257,161,3) returned '%1'")
	.arg(rsh->getSpecialSource(257,161,3)) ); //returns "257"

//Virtual Source to SD/PAL Dest
Debug( bncs_string("getSpecialSource(257,1,0) returned '%1'")
	.arg(rsh->getSpecialSource(257,1,0)) ); //returns "257"
					// or "33" if TBS=HD
Debug( bncs_string("getSpecialSource(257,1,1) returned '%1'")
	.arg(rsh->getSpecialSource(257,1,1)) ); //returns "33"
Debug( bncs_string("getSpecialSource(257,1,2) returned '%1'")
	.arg(rsh->getSpecialSource(257,1,2)) ); //returns "33"
Debug( bncs_string("getSpecialSource(257,1,3) returned '%1'")
	.arg(rsh->getSpecialSource(257,1,3)) ); //returns "257"
					// or "33" if TBS=HD
\endcode
 */
int routerShim::getSpecialSource(int intSource, int intDest, Route_Mode mode)
{
	int intSpecialSource = -1;
	int intVirtualSource = -1;

	//Get facts
	//What format was this source described as in object_settings.Virtual_Router_Associations
	//sourceType[intSource];

	//What format was this dest described as in DB9
	//destType[intDest];

	//Assume the source supplied is correct
	intSpecialSource = intSource;

	

	//Check if the source is Real
	if( (HDToVirtual[intSource] == 0) && (SDToVirtual[intSource] == 0)
		&& (sourceType[ intSource ] != SRCE_VIRTUAL) )
	{
		//The source does not appear in the virtual association table
		//The requested source should always be routed to the dest
	}
	else
	{
		switch(mode)
		{
			case ROUTE_FOLLOW:
				//Handle special case where the Dest is not HD capable 
				if( (destType[ intDest ] != DEST_HD) ){
					//The dest needs an SD source
					//Find the appropriate SD source
					switch(sourceType[ intSource ])
					{
						case SRCE_VIRTUAL:
							//Check if TBS is HD
						//	if (intTBS_mode == TBS_HD)
						//	{
								intSpecialSource = virtualToSD[ intSource ];
						//	}
							break;

						case SRCE_HD:
							intVirtualSource = HDToVirtual[ intSource ];
							intSpecialSource = virtualToSD[ intVirtualSource ];
							break;

						case SRCE_SD:
							//The source is already SD as needed by the dest
							//intSpecialSource = intSource;
							break;
					}

				}
				break;
									
			case ROUTE_HD:
				//Is the Dest HD Capable
				if(destType[ intDest ] == DEST_HD)
				{
					//Find the appropriate HD Source
					switch(sourceType[ intSource ])
					{
						case SRCE_VIRTUAL:
							intSpecialSource = virtualToHD[ intSource ];
							break;

						case SRCE_HD:
							//The source is already HD as requested
							//intSpecialSource = intSource;
							break;

						case SRCE_SD:
							intVirtualSource = SDToVirtual[ intSource ];
							intSpecialSource = virtualToHD[ intVirtualSource ];
							break;
					}
				}
				else
				{
					//Find the appropriate SD source
					switch(sourceType[ intSource ])
					{
						case SRCE_VIRTUAL:
							intSpecialSource = virtualToSD[ intSource ];
							break;

						case SRCE_HD:
							intVirtualSource = HDToVirtual[ intSource ];
							intSpecialSource = virtualToSD[ intVirtualSource ];
							break;

						case SRCE_SD:
							//The source is already SD as needed by the dest
							//intSpecialSource = intSource;
							break;
					}
				}
				
				break;

			case ROUTE_SD:
				//Find the appropriate SD source
				switch(sourceType[ intSource ])
				{
					case SRCE_VIRTUAL:
						intSpecialSource = virtualToSD[ intSource ];
						break;

					case SRCE_HD:
						intVirtualSource = HDToVirtual[ intSource ];
						intSpecialSource = virtualToSD[ intVirtualSource ];
						break;

					case SRCE_SD:
						//The source is already SD as requested
						//intSpecialSource = intSource;
						break;
				}
				break;

			case ROUTE_VIRTUAL:
				//Assume Dest is HD Capable and should take the appropriate Virtual Source
				//Find the appropriate Virtual Source
				switch(sourceType[ intSource ])
				{
					case SRCE_VIRTUAL:
						//The source is already Virtual as requested
						//intSpecialSource = virtualToHD[ intSource ];
						intSpecialSource=intSource;//the source is virtual and the command is to route the virtual
						break;

					case SRCE_HD:
						intSpecialSource = HDToVirtual[ intSource ];
						break;

					case SRCE_SD:
						intSpecialSource = SDToVirtual[ intSource ];
						break;
				}

				//Handle special case where the Dest is not HD capable and TBS is HD
				if( (destType[ intDest ] != DEST_HD) && (intTBS_mode == TBS_HD) ){
					//The dest needs an SD source
					//Find the appropriate SD source
					switch(sourceType[ intSource ])
					{
						case SRCE_VIRTUAL:
							intSpecialSource = virtualToSD[ intSource ];
							break;

						case SRCE_HD:
							intVirtualSource = HDToVirtual[ intSource ];
							intSpecialSource = virtualToSD[ intVirtualSource ];
							break;

						case SRCE_SD:
							//The source is already SD as needed by the dest
							//intSpecialSource = intSource;
							break;
					}
				}
				break;

		}
	}

	//OutputDebugString(bncs_string("routerShim: getSpecialSource(%1,%2,%3) sourceType=%4 - returning '%5'")
	//	.arg(intSource).arg(intDest).arg(mode).arg(sourceType[ intSource ]).arg(intSpecialSource));

	return intSpecialSource;

}

/*
\brief This functions should be called by the host application whenever TheBigSwitch mode changes

*/
void routerShim::setTBSMode(int mode)
{
	if( mode == TBS_HD || mode == TBS_SD)
	{
		intTBS_mode = mode;		
	}
}


bncs_stringlist routerShim::getSourceListSinglePresentedSD()
{

	bncs_stringlist	strlReturnlist;

	for (int intSource = 1; intSource < firstVirtual; intSource++)
	{
		//Is the source format SD?
		if(sourceType[ intSource ] == SRCE_SD || sourceType[ intSource ] == SRCE_PAL )
		{
			//Is the source NOT defined in the Virtual_Router_Associations table?
			if( SDToVirtual[ intSource ] == 0)
			{
		
			strlReturnlist.append(bncs_string("%1").arg(intSource));
			}
		}
	}


	return strlReturnlist;
}

bncs_stringlist routerShim::getSourceListSinglePresentedHD()
{
	bncs_stringlist	strlReturnlist;
	

	for (int intSource = 1; intSource < firstVirtual; intSource++)
	{
		//Is the source format SD?
		if(sourceType[ intSource ] == SRCE_HD)
		{
			//Is the source NOT defined in the Virtual_Router_Associations table?
			if( HDToVirtual[ intSource ] == 0)
			{
				strlReturnlist.append(bncs_string("%1").arg(intSource));
		
			}
		}
	}

	return strlReturnlist;
}

bncs_stringlist routerShim::getSourceListVirtuals()
{
	
	bncs_stringlist	strlReturnlist;
	
	for (int intSource = firstVirtual; intSource <= maxSources; intSource++)
	{

		strlReturnlist.append(bncs_string("%1").arg(intSource)); 
	}


	return strlReturnlist;

}

Dest_Types routerShim::getDestType(int dest)
{
	return (Dest_Types)destType[ dest ];
}

