<?xml version="1.0" encoding="utf-8"?>
<print-template>
	<options>
		<option name="Show Legend" type="bool" default="1">Show the legend for the coloured cells</option>
		<option name="Grid Lines" type="bool" default="0">Show Background grid lines</option>
		<option name="Page throw on day change" type="bool" default="0">When a new day starts we will start on a new page.</option>
		<option name="Channel Image Height" type="int" default="74">Height of the channel images in pixels</option>
		<option name="Channel Image Width" type="int" default="154">Width of the channel images in pixels</option>
		<option name="Display Marked Programme Icons" type="bool" default="1">Display marker icons for marked programmes</option>
		<option name="Display Marked Programme Blobs" type="bool" default="1">Display coloured blobs for marked programmes</option>
		<option name="Display Coloured Boxes" type="bool" default="1">Display coloured boxes for main marker types</option>
		<option name="Include Channel Numbers" type="bool" default="1">Include channel (EPG) numbers with the channel image</option>
		<option name="Include Programme Category" type="bool" default="0">Include the programme category in the grid.</option>
		<option name="Font Size Percent" type="int" default="100">Font size. 100% is the default. To make the font size twice as big use 200.</option>
	</options>


<main-code><![CDATA[

#include "utility-functions.print-include"


//	#######################################################
//	BEGIN EDITABLE SECTION
//	Fiddle variables to play with

// Layout - General
var f_nSpaceBetweenChannelAndGridLeft = 10;
var f_nChannelImageHeight = ( GetOptionValue( "Channel Image Height" )* f_nFontSizePercent ) / 100;
var f_nChannelImageWidth = ( GetOptionValue( "Channel Image Width" ) * f_nFontSizePercent ) / 100;

var g_IncludeEPG = GetOptionValue( "Include Channel Numbers" );
var g_IncludeCategory = GetOptionValue( "Include Programme Category" );

var f_strEPGFontName = "Tahoma";
var f_strEPGFontBold = f_strEPGFontItalic = f_strEPGFontUnderline = false;
var f_strEPGFontColour = "black";
var f_nEPGSizePoints = GetFontSize( 6 );

// Layout - Programme Boxes
var f_strProgrammeFontName = "Tahoma";
var f_strProgrammeFontBold = f_strProgrammeFontItalic = f_strProgrammeFontUnderline = false;
var f_strProgrammeFontColour = "black";
var f_nProgrammeSizePoints = GetFontSize( 8 );
var f_nProgrammeInnerBorder = 5;		//	Border around teh inner of a programme cell
var f_nProgrammeInnerLeftBorder = 20;	//	Left border for a programme cell
var f_nVerticalGapBetweenRows = 10;
var f_nProgrammeCellSpacing = 5;
var f_nGapBetweenDateRow = 40;

var f_strProgrammeCategoryFontColour = "black";
var f_strProgrammeCategoryFontSizePoints = GetFontSize( 6 );
var f_strProgrammeCategoryFontFontName = "Tahoma";


// Layout - Timeline
var f_strTimelineFontName = "Tahoma";
var f_strTimelineFontBold = true;
var f_strTimelineFontItalic = f_strTimelineFontUnderline = false;
var f_strTimelineFontColour = "black";
var f_nTimelineSizePoints = GetFontSize( 8 );
var f_nTimeLineTopBottomBorder = 2;
var f_nGapBetweenTimeLineAndGrid = 5;
var f_nTimeLineEveryChannel = 10;		// Print timeline every x number of channels


// Options
var f_bDayThrowsPage = GetOptionValue( "Page throw on day change");				// Throws a new page when a new day starts when TRUE
var f_bPrintGrid = GetOptionValue( "Grid Lines");						// Outputs background grid
var f_bShowBoxLegend = GetOptionValue( "Show Legend");				// this will only be used if box colours (f_bColourBoxes) has been turned on.


// Marked Programme Options
var f_bShowIcons = GetOptionValue( "Display Marked Programme Icons" );						// display icons for marked programmes
var f_bShowColourBlobs = GetOptionValue( "Display Marked Programme Blobs" );			// display blobs for marked programmes
var f_nIconSpacer = 5;							// Spacer between icons
var f_bColourBoxes = GetOptionValue( "Display coloured boxes" );					// colour box depending on marker type


// Set some box colours
var f_strGridOutlineColour = "gray";
var f_strGridFillColour = "white";

var f_strBoxOutlineColour = "black";
var f_strBoxFillColour = "white";
var f_nBoxOutlineWidth = 1;

var f_strFavBoxFillColour = "#C0FFC0";		// Colour of favourite markers if f_bColourBoxes TRUE
var f_strRemBoxFillColour = "#C0C0FF";		// Colour of reminder markers if f_bColourBoxes TRUE
var f_strWatchBoxFillColour = "#FFC0C0";	// Colour of watch markers if f_bColourBoxes TRUE
var f_strVideoBoxFillColour = "#FFFFC0";	// Colour of video markers if f_bColourBoxes TRUE
var f_strCatBoxFillColour = "#C0FFFF";		// Colour of category markers if f_bColourBoxes TRUE
var f_strManBoxFillColour = "#C0C0C0";		// Colour of manual markers if f_bColourBoxes TRUE


//
// Set some default fonts and sizes
var f_strHeaderStartHTMLTemplate = "<p align=\"center\"><font size=" + GetFontSizePoints( 15 ) + " face=\"Verdana, Arial\" color=\"Black\"><b>"
var f_strHeaderEndHTMLTemplate = "</b></font></p>"
var f_strFooterStartHTMLTemplate = "<p align=\"center\"><font size=" + GetFontSizePoints( 7 ) + " face=\"Verdana, Arial\" color=\"#5a5a5a\">"
var f_strFooterEndHTMLTemplate = "</font></p>"

var f_strLegendBlock = "<td width=250 align=\"right\"><table width=\"100%%\">" +
		"<tr>" + 
		"<td width=10 bgcolor=\"" + f_strFavBoxFillColour + "\"></td><td width=2></td><td width=100><font size=" + GetFontSizePoints( 7 ) + " face=\"Verdana, Arial\" color=\"#5a5a5a\">Favourite Marker</font></td>" +
		"<td width=26></td>" +
		"<td width=10 bgcolor=\"" + f_strVideoBoxFillColour + "\"></td><td width=2></td><td width=100><font size=" + GetFontSizePoints( 7 ) + " face=\"Verdana, Arial\" color=\"#5a5a5a\">Video Marker</font></td>" +
		"</tr>" + 
		"<tr>" + 
		"<td width=10 bgcolor=\"" + f_strRemBoxFillColour + "\"></td><td width=2></td><td width=100><font size=" + GetFontSizePoints( 7 ) + " face=\"Verdana, Arial\" color=\"#5a5a5a\">Reminder Marker</font></td>" +
		"<td width=26></td>" +
		"<td width=10 bgcolor=\"" + f_strCatBoxFillColour + "\"></td><td width=2></td><td width=100><font size=" + GetFontSizePoints( 7 ) + " face=\"Verdana, Arial\" color=\"#5a5a5a\">Category Marker</font></td>" +
		"</tr>" + 
		"<tr>" + 
		"<td width=10 bgcolor=\"" + f_strWatchBoxFillColour + "\"></td><td width=2></td><td width=100><font size=" + GetFontSizePoints( 7 ) + " face=\"Verdana, Arial\" color=\"#5a5a5a\">Watch Marker</font></td>" +
		"<td width=26></td>" +
		"<td width=10 bgcolor=\"" + f_strManBoxFillColour + "\"></td><td width=2></td><td width=100><font size=" + GetFontSizePoints( 7 ) + " face=\"Verdana, Arial\" color=\"#5a5a5a\">Manually Created</font></td>" +
		"</tr>" + 
		"</table></td>";

var g_nCellWidth = GetPageWidth();		// get width of page and later take of legend cell if used
if( f_bColourBoxes && f_bShowBoxLegend )
{
	g_nCellWidth = g_nCellWidth - 250;		// take off width of legend cell
}
else
{
	f_strLegendBlock = "";
}

//
// Set up main string templates
var f_strDateString = f_strHeaderStartHTMLTemplate + "$ScriptDate" + f_strHeaderEndHTMLTemplate;
var f_strDateRow = "<br><hr noshade width=\"100%%\">" + f_strDateString;

var f_strHeaderTemplate = f_strHeaderStartHTMLTemplate + 
						"Multi-Channel Grid" + f_strHeaderEndHTMLTemplate + f_strDateString + 
						"<font size='10pt'><hr noshade width=\"100%%\"><br></font>";

var f_strFooterTemplate = "<br><hr noshade width=\"100%%\"><table width=\"100%%\"><tr valign=\"middle\">" +
						"<td width=" + g_nCellWidth + ">" + f_strFooterStartHTMLTemplate + 
						"Printed from DigiGuide TV guide. Get it now at www.digiguide.com. Copyright GipsyMedia Limited.&nbsp;&nbsp;Page: $PageNum" + 
						f_strFooterEndHTMLTemplate +  "</td>" + f_strLegendBlock +
						"</tr></table></p>";

//	END EDITABLE SECTION
//	#######################################################


//
//	Setup global variables

//	1000 per second, 60 seconds, 60 minutes, 24 hours!
var g_nMillisecondsPerDay = 1000 * 60 * 60 * 24;
var g_nMillisecondsPer30Minutes = 1000 * 60 * 30;

var g_nProgCount = GetProgrammeCount();
var g_nPageWidth = GetPageWidth();

var g_nPageNum = 1;
var g_nLeftBorder = f_nChannelImageWidth + f_nSpaceBetweenChannelAndGridLeft;
var g_nCurrentY = 0;
var g_nTimeLineHeight;

var g_nPixelsPerMinute;
var g_dtCurrent = new Date( Options.StartDate );

//
//	The lowest point on the page (above the footer)
var g_nPageBottom;

//
//	Grid times for the left and right of the grid
var g_dtStartTime;
var g_dtEndTime;

//
//	Zero can't exist as a channel ID
var g_nCurrentChannelID = 0;

//
//	Measure the height of the text used for programmes, then use that for the 
//	height of a programme cell. Also, test to ensure the channel isn't bigger.
//	If it is then we need to adjust the cell height to match that of the programme
SelectFont( f_strProgrammeFontName, f_nProgrammeSizePoints, f_strProgrammeFontBold, f_strProgrammeFontItalic, f_strProgrammeFontUnderline );
var g_nProgrammeTextHeight = GetCurrentFontHeight();
var g_nProgrammeBlockHeight = g_nProgrammeTextHeight + (f_nProgrammeInnerBorder * 2);
if( f_nChannelImageHeight > g_nProgrammeBlockHeight )
{
	g_nProgrammeBlockHeight = f_nChannelImageHeight;
}

//
//	Measure how tall we want the timeline to be
SelectFont( f_strTimelineFontName, f_nTimelineSizePoints, f_strTimelineFontBold, f_strTimelineFontItalic, f_strTimelineFontUnderline );
g_nTimeLineHeight = GetCurrentFontHeight() + f_nTimeLineTopBottomBorder * 2;



function PageThrow()
{
	NewPage();
	g_nPageNum++;
	AddPageDecorations();
}


function AddPageDecorations()
{
	g_nCurrentY = PlaceHeader()
	g_nPageBottom = PlaceFooter();
}


function FormatDate( dThisDate )
{
	return dThisDate.toLocaleDateString();
}


function PlaceDate()
{
	var strPrintDate = f_strDateRow;
	strPrintDate = strPrintDate.replace("$ScriptDate", FormatDate(g_dtCurrent) );
	var nDateHeight = MeasureText( g_nPageWidth, strPrintDate );

	// Does date + timeline + at least one programme row fit on the bottom of page, if not throw page
	if( ( g_nCurrentY + nDateHeight + g_nTimeLineHeight + g_nProgrammeBlockHeight + f_nVerticalGapBetweenRows + f_nGapBetweenDateRow + f_nGapBetweenTimeLineAndGrid ) >= g_nPageBottom )
	{
		PageThrow();
	}
	else
	{
		g_nCurrentY += g_nProgrammeBlockHeight + f_nVerticalGapBetweenRows + f_nGapBetweenDateRow;
		PlaceText( 0, g_nCurrentY, g_nPageWidth, strPrintDate );
		g_nCurrentY += nDateHeight;
	}
}

function PlaceHeader()
{
	var strPrintHeader = f_strHeaderTemplate.replace("$ScriptDate", FormatDate(g_dtCurrent) );
	var nHeaderHeight = MeasureText( g_nPageWidth, strPrintHeader );
	nHeaderHeight = MeasureText( g_nPageWidth, strPrintHeader );

	PlaceText( 0, 0, g_nPageWidth, strPrintHeader );
	return nHeaderHeight;
}


function PlaceFooter()
{
	var strPrintFooter = GetProgrammeInfo( 0, f_strFooterTemplate );
	strPrintFooter = strPrintFooter.replace("$PageNum", g_nPageNum);
	var nFooterHeight = MeasureText( g_nPageWidth, strPrintFooter );
	
	PlaceText( 0, GetPageHeight() - nFooterHeight, g_nPageWidth, strPrintFooter );
	return GetPageHeight() - nFooterHeight;
}


//
//	Function to get the number of minutes difference between two dates.
//	Corrects for possibility of the dates being the worng way round
function MinutesDifference( dtOne, dtTwo )
{
	var nMinutes = ( dtOne.getTime() - dtTwo.getTime() ) / 60 / 1000;
	if( nMinutes < 0 )
		nMinutes = -nMinutes;
	return nMinutes;
}


function SetDates()
{
	var dtStart;
	var dtEnd;
	if( g_dtCurrent.getDay() == 0 || g_dtCurrent.getDay() == 6 )
	{
		dtStart = new Date( Options.WeekEndStartTime );
		dtEnd = new Date( Options.WeekEndEndTime );
	}
	else
	{
		dtStart = new Date( Options.WeekDayStartTime );
		dtEnd = new Date( Options.WeekDayEndTime );
	}

	g_dtStartTime = new Date( g_dtCurrent );
	g_dtStartTime.setHours( dtStart.getHours() );
	g_dtStartTime.setMinutes( dtStart.getMinutes() );

	g_dtEndTime = new Date( g_dtCurrent );
	g_dtEndTime.setHours( dtEnd.getHours() );
	g_dtEndTime.setMinutes( dtEnd.getMinutes() );

	//
	//	if the end time is before the start time then we need to add a day on.
	//	This accounts for 09:00 ->00:00 situations
	if( g_dtEndTime < g_dtStartTime )
	{
		var nTime = g_dtEndTime.getTime();
		nTime += g_nMillisecondsPerDay;
		g_dtEndTime.setTime( nTime );
	}		

	g_nMinutes = MinutesDifference( g_dtEndTime, g_dtStartTime );
	//
	//	If we have zero minutes then probably we have 24hr
	if( g_nMinutes == 0 )
	{
		g_nMinutes = 24 * 60;
	}
	
	
	//
	//	We would modify this to take into account of left and right borders as well as channel images
	g_nPixelsPerMinute = ( g_nPageWidth - g_nLeftBorder ) / g_nMinutes;
}


function AddDay()
{
	var nTime = g_dtCurrent.getTime();
	nTime += g_nMillisecondsPerDay;
	g_dtCurrent.setTime( nTime );
	g_dtCurrent.setHours( 12 );

	// Throw a new page or just put in a date banner strip
	if( f_bDayThrowsPage )
		PageThrow();
	else
		PlaceDate();
}


function DrawGridRow( nProgrammeChannelID )
{
	DrawImage( 0, g_nCurrentY, f_nChannelImageWidth, f_nChannelImageHeight, "Channel:" + nProgrammeChannelID );
	var dtTime = new Date( g_dtStartTime );

	if( g_IncludeEPG )
	{
		SelectFont( f_strEPGFontName, f_nEPGSizePoints, f_strEPGFontBold, f_strEPGFontItalic, f_strEPGFontUnderline )
		var strEPG = GetProgrammeInfo( nProg, "$ChannelAssignment")
		var nWidth = GetTextWidth( strEPG );
		var nHeight = GetCurrentFontHeight();
		var nLeft = f_nChannelImageWidth - nWidth;
		var nTop = g_nCurrentY + f_nChannelImageHeight - nHeight;
		DrawBox( nLeft, nTop, nWidth, nHeight, "black", "white" );
		DrawEllipsisText( nLeft, nTop, f_nChannelImageWidth, GetProgrammeInfo( nProg, "$ChannelAssignment"), f_strProgrammeFontColour )
	}

	//
	//	Round it down to multiple of 30 minutes
	dtTime.setMinutes( 30 * ( dtTime.getMinutes() / 30 ) );

	var nY = g_nCurrentY - f_nVerticalGapBetweenRows / 2;

	while( dtTime < g_dtEndTime )
	{
		var nXPos = g_nLeftBorder + ( MinutesDifference( g_dtStartTime, dtTime ) * g_nPixelsPerMinute );
		
		//
		// Only draw grid if asked
		if( f_bPrintGrid ) DrawBox( nXPos, nY, nXPos + 30 * g_nPixelsPerMinute, g_nProgrammeBlockHeight + f_nVerticalGapBetweenRows * 2, f_strGridOutlineColour, f_strGridFillColour );
		
		dtTime.setTime( dtTime.getTime() + g_nMillisecondsPer30Minutes );
	}
}


function NextChannel( nProgrammeChannelID )
{
	if( g_nCurrentChannelID )
	{
		//
		//	Move Y positions accordingly
		g_nCurrentY += ( g_nProgrammeBlockHeight + f_nVerticalGapBetweenRows / 2 );

		//
		//	If we fall off the bottom of a page then we need to create a new one, add the timeline and do the normal stuff
		if( g_nCurrentY + ( g_nProgrammeBlockHeight + f_nVerticalGapBetweenRows / 2 ) > g_nPageBottom )
		{
			PageThrow();
			DrawTimeline();
		}
	}

	DrawGridRow( nProgrammeChannelID );
}


function ShowProgramme( nProg, dtProgrammeStartDate, dtProgrammeEndDate )
{
	//
	//	Check to see if this programme is the same channel as the previous programme
	//	If not then throw a grid row
	var nProgrammeChannelID = GetProgrammeInfo( nProg, "$ChannelID" );
	if( g_nCurrentChannelID != nProgrammeChannelID )
	{
		NextChannel( nProgrammeChannelID );
		g_nCurrentChannelID = nProgrammeChannelID;
	}


	//
	//	If the programme starts before our grid then we can safely assume it's an overlapping
	//	programme. Mark it as such and then adjust the start date to keep it within our grid.
	var bDrawBox = bOverlapProg = false;
	if( dtProgrammeStartDate < g_dtStartTime )
	{
		dtProgrammeStartDate = new Date( g_dtStartTime );
		bOverlapProg = true;
	}

	var nProgrammeWidth = MinutesDifference( dtProgrammeStartDate, dtProgrammeEndDate ) * g_nPixelsPerMinute - f_nProgrammeCellSpacing;
	var nProgrammeX = g_nLeftBorder + MinutesDifference( g_dtStartTime, dtProgrammeStartDate ) * g_nPixelsPerMinute;
	if( !bOverlapProg )
	{
		// Programme starts at same time as grid starts so indent with cellspacing on the left
		nProgrammeX += f_nProgrammeCellSpacing;
	}

	var nBoxHeight = g_nProgrammeBlockHeight - ( f_nVerticalGapBetweenRows / 2 );

	// Draw boxes with appropriate fill colours
	var bWasMarker = false;
	if( f_bColourBoxes )
	{
		var arrMarkers = GetMarkersForProgramme( nProg );
		for( var n = 0; n < arrMarkers.length; n++ )
		{
			var nMarker = arrMarkers[ n ];
			
			if( !IsProgrammeExcludedFromMarker( nProg, nMarker ) )
			{

				var nType = Math.abs( GetMarkerInfo( nMarker, "$MarkerTypeID" ) );
				// Add your own marker colours here
				switch( nType )
				{
					case 1:	// Favourite marker
						DrawBox( nProgrammeX, g_nCurrentY, nProgrammeWidth, nBoxHeight, f_strBoxOutlineColour, f_strFavBoxFillColour, f_nBoxOutlineWidth );
						bWasMarker = true;
						break;

					case 2:	// Reminder marker
						DrawBox( nProgrammeX, g_nCurrentY, nProgrammeWidth, nBoxHeight, f_strBoxOutlineColour, f_strRemBoxFillColour, f_nBoxOutlineWidth );
						bWasMarker = true;
						break;

					case 4:	// Video marker
						DrawBox( nProgrammeX, g_nCurrentY, nProgrammeWidth, nBoxHeight, f_strBoxOutlineColour, f_strVideoBoxFillColour, f_nBoxOutlineWidth );
						bWasMarker = true;
						break;

					case 5:	// Watch marker
						DrawBox( nProgrammeX, g_nCurrentY, nProgrammeWidth, nBoxHeight, f_strBoxOutlineColour, f_strWatchBoxFillColour, f_nBoxOutlineWidth );
						bWasMarker = true;
						break;

					case 6:	// Category marker
						DrawBox( nProgrammeX, g_nCurrentY, nProgrammeWidth, nBoxHeight, f_strBoxOutlineColour, f_strCatBoxFillColour, f_nBoxOutlineWidth );
						bWasMarker = true;
						break;

					case 2147483646:	// Manual marker
						DrawBox( nProgrammeX, g_nCurrentY, nProgrammeWidth, nBoxHeight, f_strBoxOutlineColour, f_strManBoxFillColour, f_nBoxOutlineWidth );
						bWasMarker = true;
						break;

					default:	// All others
						DrawBox( nProgrammeX, g_nCurrentY, nProgrammeWidth, nBoxHeight, f_strBoxOutlineColour, f_strBoxFillColour, f_nBoxOutlineWidth );
						bWasMarker = true;
						break;
				}
			}
		}
	}

	// Hasnt already been coloured
	if( !bWasMarker )
	{
		DrawBox( nProgrammeX, g_nCurrentY, nProgrammeWidth, nBoxHeight, f_strBoxOutlineColour, f_strBoxFillColour, f_nBoxOutlineWidth );
	}

	SelectFont( f_strProgrammeFontName, f_nProgrammeSizePoints, f_strProgrammeFontBold, f_strProgrammeFontItalic, f_strProgrammeFontUnderline )

	var nProgRight = nProgrammeX + nProgrammeWidth - f_nProgrammeInnerBorder * 2;
	if( nProgRight > g_nPageWidth - 1 )
		nProgRight = g_nPageWidth - 1;

	nProgrammeX += f_nProgrammeInnerLeftBorder;
	var nY = g_nCurrentY + ( nBoxHeight - g_nProgrammeTextHeight ) / 2;

	// Draw Icons and Blobs
	if( f_bShowIcons || f_bShowColourBlobs )
	{
		var nIconSize = (f_nProgrammeSizePoints * 2) * 2;					// We want to base our icons on font size but have to double it
		var nBlobSize = (f_nProgrammeSizePoints * 2 - 4) * 2;			// Draw blob slightly smaller as it tends to overpower things
		var nIconYPos = nY + ( (nBoxHeight - nIconSize) / 2);
		var nBlobYPos = nY + ( (nBoxHeight - nBlobSize) / 2);

		var arrMarkers = GetMarkersForProgramme( nProg );
		for( var n = 0; n < arrMarkers.length; n++ )
		{
			var nMarker = arrMarkers[ n ];

			if( !IsProgrammeExcludedFromMarker( nProg, nMarker ) )
			{

				var strIcon = GetMarkerInfo( nMarker, "$MarkerIcon" );
				if( strIcon && f_bShowIcons )
				{
					// Draw icon if room
					if( (nProgrammeX + nIconSize) < nProgRight )
						DrawImage( nProgrammeX, nIconYPos, nIconSize, nIconSize, "Marker-ICON:" + strIcon );
		
					// Draw spacer if room
					if( (nProgrammeX + f_nIconSpacer) < nProgRight )
						nProgrammeX += nIconSize + f_nIconSpacer;
				}

				var strBlob = GetMarkerInfo( nMarker, "$MarkerBlob" );
				if( strBlob && f_bShowColourBlobs )
				{
					// Draw blob if room
					if( (nProgrammeX + nBlobSize) < nProgRight )
						DrawImage( nProgrammeX, nBlobYPos, nBlobSize, nBlobSize, "Marker-BLOB:" + strBlob );

					// Draw spacer if room
					if( (nProgrammeX + f_nIconSpacer) < nProgRight )
						nProgrammeX += nBlobSize + f_nIconSpacer;
				}
			}
		}
	}

	// Draw text if room
	var strProgrammeName = GetProgrammeInfo( nProg, "$ProgrammeName");
	if( !DrawEllipsisText( nProgrammeX, nY, nProgRight, strProgrammeName, f_strProgrammeFontColour ) )
	{
		//
		//	All of the programme name didn't fit. Should we do something with it?
		//DebugOut( "Programme too wide ", GetProgrammeInfo( nProg, "$ProgrammeName" ) );
	}
	else
	{
		if( g_IncludeCategory )
		{
			var nProgrammeLength = GetTextWidth( strProgrammeName );
			SelectFont( f_strProgrammeCategoryFontFontName, f_strProgrammeCategoryFontSizePoints, 0, 0, 0 );
			var strCategory = GetProgrammeInfo( nProg, "($CategoryName)")
			DrawEllipsisText( nProgrammeX + nProgrammeLength + 10, nY, nProgRight, strCategory, f_strProgrammeCategoryFontColour )
		}
	}
}

function DrawTimeline()
{
	var dtTime = new Date( g_dtStartTime );

	//
	//	Round it down to multiple of 30 minutes
	dtTime.setMinutes( 30 * ( dtTime.getMinutes() / 30 ) );

	while( dtTime < g_dtEndTime )
	{
		var nXPos = g_nLeftBorder + ( MinutesDifference( g_dtStartTime, dtTime ) * g_nPixelsPerMinute );
		var strTime = FormatTime( dtTime );

		SelectFont( f_strTimelineFontName, f_nTimelineSizePoints, f_strTimelineFontBold, f_strTimelineFontItalic, f_strTimelineFontUnderline )
		DrawEllipsisText( nXPos, g_nCurrentY, nXPos + 30 * g_nPixelsPerMinute, strTime, f_strTimelineFontColour )
		dtTime.setTime( dtTime.getTime() + g_nMillisecondsPer30Minutes );
	}
	g_nCurrentY += g_nTimeLineHeight + f_nGapBetweenTimeLineAndGrid;
}



//
//	Kickstart our first page...
AddPageDecorations();


//
//	For each day iterate over the programmes
var nProgressMax = Options.DaysToPrint * ( g_nProgCount - 1 );
for( nDayCount = 0; nDayCount < Options.DaysToPrint && !HasAborted(); nDayCount++ )
{
	SetDates();
	DrawTimeline();

	//
	//	Zero can't exist as a channel ID
	g_nCurrentChannelID = 0;

	//
	//	Loop over the programmes, if a programme falls within our times then show it.
	for( var nProg = 0; nProg < g_nProgCount && !HasAborted(); nProg++ )
	{
		SetProgress( nDayCount * g_nProgCount + nProg, nProgressMax );

		var dtProgrammeStartDate = new Date( GetProgrammeInfo( nProg, "$USStartDateTime" ) );
		var dtProgrammeEndDate = new Date( GetProgrammeInfo( nProg, "$USEndDateTime" ) );

		if( dtProgrammeEndDate >= g_dtStartTime && dtProgrammeStartDate < g_dtEndTime )
		{
			ShowProgramme( nProg, dtProgrammeStartDate, dtProgrammeEndDate );
		}
	}

	if( nDayCount != Options.DaysToPrint - 1 )
		AddDay();
}
]]></main-code>
</print-template>