<?xml version="1.0" encoding="utf-8"?>
<print-template>
	<options>
		<option name="Columns" type="int" default="3" min="1" max="10">Number of columns you'd like to print</option>
		<option name="Draw lines between programmes" type="bool" default="1">draw horizontal lines separating each programme</option>
		<option name="Draw Icons" type="bool" default="1">display icons for special programmes</option>
		<option name="New page per day" type="bool" default="0">Create a new page when a change in day occurs</option>
		<option name="New column per day" type="bool" default="0">Create a new column when a change in day occurs (mutually exclusive with "New page per day")</option>
		<option name="New column per channel" type="bool" default="1">Create a new column when a change in channel occurs</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>
		<option name="Colour: Category" type="color" default="#5a5a5a">Colour used for printing the programme category.</option>
		<option name="Colour: Description" type="color" default="#5a5a5a">Colour used for printing the programme description.</option>
		<option name="Colour: Channel Name" type="color" default="maroon">Colour used for printing the channel name.</option>
	</options>

<main-code><![CDATA[

// Version 1.1 19-Nov-2005 Paul Webster

#include "utility-functions.print-include"

/*
	Basic logic for Whats On View printing (also works the same as Show Me, Finder and Daily View)

	Measure the header and footer for the page.
	Place the header and footer - this gives the amount of vertical space to use
	Determine column widths used
	for each programme
		Measure to see if it fits
			If it does then place it
			If it doesn't then move on to the next column
			If no more columns then throw a page and start again

	Note: When writing out HTML within a string always use ' to indicate a quote and use %% for a percentage
*/


//	#######################################################
//	BEGIN EDITABLE SECTION
//	Fiddle variables to play with (they begin with f_...)

var f_nColumnGap = 100;						// gap between columns
var f_nProgrammeGap = 50;					// gap between programme blocks
var f_nBoxPadding = 20;						// padding between box border and programme information

// Page layout options
var f_bNewPageOnDay = GetOptionValue( "New page per day" );
var f_bNewColumnOnDay = GetOptionValue( "New column per day" );
var f_bNewColumnPerChannel = GetOptionValue( "New column per channel" );


//	f_nColumnsToPrint is the number of columns to use, can't be zero.
//	Setting it too high will produce a large number of pages so beware!
var f_nColumnsToPrint = GetOptionValue( "Columns" );


// Set some default fonts, colours 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( 13 ) + " face='Verdana, Arial' color='#5a5a5a'>"
var f_strFooterEndHTMLTemplate = "</font></p>"

var f_strTitleStartHTMLTemplate = "<font size=" + GetFontSizePoints( 9 ) + " face='Verdana, Arial' color='Black'><b>"
var f_strTitleEndHTMLTemplate = "</b></font>"
var f_strCatStartHTMLTemplate = "<font size=" + GetFontSizePoints( 7 ) + " face='Verdana, Arial' color='" + GetOptionValue( "Colour: Category") + "'>"
var f_strCatEndHTMLTemplate = "</font>"
var f_strBodyStartHTMLTemplate = "<font size=" + GetFontSizePoints( 7 ) + " face='Verdana, Arial' color='" + GetOptionValue( "Colour: Description") + "'>"
var f_strBodyEndHTMLTemplate = "</font>"

var f_strChannelStartHTMLTemplate = "<p align='center'><font size=" + GetFontSizePoints( 13 ) + " face='Verdana, Arial' color='" + GetOptionValue( "Colour: Channel Name") + "'><b>"
var f_strChannelEndHTMLTemplate = "</b></font></p>"


// Display
var f_bShowIcons = GetOptionValue( "Draw Icons" );
var f_bDrawLinesBetweenProgs = GetOptionValue( "Draw lines between programmes" );


//	Header, footer and programme 'block' templates
var f_strDateBlock = "<br>$LongDate<br>";
var f_strIconsBlock = "$MarkerIcons";
var f_strVPlusBlock = "$VideoPlus<br>";
if( !f_bShowIcons ) f_strIconsBlock = "";


// Set up main string templates
var f_strHeaderTemplate = "<p><table width='100%%'><tr valign='middle'>" +
			"<td width=" + GetPageWidth() + ">" + f_strHeaderStartHTMLTemplate + 
			"Multi-List" + f_strDateBlock +
			f_strHeaderEndHTMLTemplate + "</td></tr></table></p>" + 
			"<hr noshade width='100%%'><br>";

var f_strFooterTemplate = "<br><hr noshade width='100%%'>" +
			f_strFooterStartHTMLTemplate + 
			"Printed from DigiGuide TV guide. Get it now at www.digiguide.com. Copyright GipsyMedia Limited.&nbsp;&nbsp;Page: $PageNum" + 
			f_strFooterEndHTMLTemplate;

var f_strProgrammeDetailsTemplate = "<p>" + f_strTitleStartHTMLTemplate + "$StartTime $ProgrammeName" + f_strTitleEndHTMLTemplate + 
			f_strCatStartHTMLTemplate + "&nbsp;($CategoryName)" + f_strCatEndHTMLTemplate + f_strIconsBlock + "<br>" + 
			f_strBodyStartHTMLTemplate + "$ScriptVPlus$DescriptionMarked" + f_strBodyEndHTMLTemplate + "</p>";

var f_strProgrammeDetailsTemplateWithoutDescription = "<p>" + f_strTitleStartHTMLTemplate + "$StartTime $ProgrammeName" + f_strTitleEndHTMLTemplate + 
			f_strCatStartHTMLTemplate + "&nbsp;($CategoryName)" + f_strCatEndHTMLTemplate + f_strIconsBlock + "</p>";

var f_strChannelTemplate = f_strChannelStartHTMLTemplate + "$ChannelName%ReplaceWithChannelAssignment%" + f_strChannelEndHTMLTemplate

//	END EDITABLE SECTION
//	#######################################################



//
//	Set some constants for the report
var g_nProgCount = GetProgrammeCount();
var g_nPageWidth = GetPageWidth();
var g_nPageHeight = GetPageHeight();
var g_nPageBottom = g_nPageHeight - ( MeasureText( g_nPageWidth, f_strFooterTemplate ) );

//	Note that due to a bug (yet to be found) the first thing we measure needs to be measured twice. 
g_nPageBottom = g_nPageHeight - ( MeasureText( g_nPageWidth, f_strFooterTemplate ) );


//
// Calculate width of columns taking space between (gap) into account
var g_nFullGaps = ( f_nColumnsToPrint - 1 ) * f_nColumnGap;
var g_nColumnWidth = ( g_nPageWidth - g_nFullGaps ) / f_nColumnsToPrint;
var g_nMillisecondsPerDay = 1000 * 60 * 60 * 24;

//
// Some page variables
var g_nCurrentX = 0;
var g_nCurrentY = 0;
var g_nTopY = 0;
var g_nBottomY = 0;
var g_nCurrentColumn = 1;
var g_dtDay;
var g_nFirstProg = 0;
var g_nPageNum = 1;
var g_nProgHeight = 0;
var g_nPreviousChannel = 0;

var g_dtStartTime;
var g_dtEndTime;
var g_dtCurrent = new Date( Options.StartDate );


//
//	Just set the top and the "current" day.
if( g_nProgCount )
{
	if( g_nProgCount > 1 )
	{
		g_nFirstProg = 2;
	}
	g_dtDay = new Date( GetProgrammeInfo( g_nFirstProg, "$USStartDateTime" ) );
	g_nBottomY = PlaceFooter();
	g_nTopY = PlaceHeader( g_nFirstProg );
	g_nCurrentY = g_nTopY;
}


//
//	Some functions
function ThrowNewPage( nProg )
{
		NewPage();
		g_nPageNum++;
		g_nCurrentColumn = 1;
		g_nTopY = PlaceHeader( nProg );
		g_nBottomY = PlaceFooter();
		g_nCurrentY = g_nTopY;
		g_nCurrentX = 0;
}

function NextColumn( nProg )
{
	//
	//	If we are on the last column then we should always do a page throw.
	if( g_nCurrentColumn == f_nColumnsToPrint )
	{
		ThrowNewPage( nProg );
	}
	else
	{
		g_nCurrentY = g_nTopY;
		g_nCurrentX += ( g_nColumnWidth + f_nColumnGap );
		g_nCurrentColumn++;
	}
}

function PlaceHeader( nProg )
{
	//DebugOut( "PlaceHeader:" + nProg );
	var strPrintHeader = GetProgrammeInfo( nProg, f_strHeaderTemplate );
	var nHeaderHeight = MeasureText( g_nPageWidth, strPrintHeader );

	PlaceText( 0, 0, g_nPageWidth, strPrintHeader );
	return nHeaderHeight;
}

function PlaceFooter()
{
	var strPrintFooter = GetProgrammeInfo( g_nFirstProg, f_strFooterTemplate );
	strPrintFooter = strPrintFooter.replace("$PageNum", g_nPageNum);
	var nFooterHeight = MeasureText( g_nPageWidth, strPrintFooter );
	
	PlaceText( 0, g_nPageBottom, g_nPageWidth, strPrintFooter );
	return nFooterHeight;
}


function GetProgVPlusDesc( nProg )
{
	var strPrintDesc = GetProgrammeInfo( nProg, f_strProgrammeDetailsTemplate );

	// Check if VideoPlus number exists and add it to programme description
	if( GetProgrammeInfo( nProg, "$VideoPlus" ) == "" )
		strPrintDesc = strPrintDesc.replace("$ScriptVPlus", "");
	else
		strPrintDesc = strPrintDesc.replace("$ScriptVPlus", f_strVPlusBlock);

	return strPrintDesc;
}


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 );
	}		

	//DebugOut( "From date: " + g_dtStartTime + " To date: " + g_dtEndTime );
}


function ShowProgramme( nProgramme )
{
	var nChannelID = GetProgrammeInfo( nProgramme, "$ChannelID" );
	if( g_nPreviousChannel != nChannelID )
	{
		if( f_bNewColumnPerChannel && g_nPreviousChannel != 0 )
		{
			NextColumn( nProgramme );
		}

		g_nPreviousChannel = nChannelID;
		var strChannelHeading = GetProgrammeInfo( nProgramme, f_strChannelTemplate );

		// Do our channel assignment if there is one
		var strEPG = new String( GetProgrammeInfo( nProgramme, "$ChannelAssignment" ) );
		if( strEPG.length )
		{
			strEPG = " (" + strEPG + ")";
		}
		strChannelHeading = strChannelHeading.replace( "%ReplaceWithChannelAssignment%", strEPG );

		var nChannelHeight = MeasureText( g_nColumnWidth - (f_nBoxPadding * 2), strChannelHeading );

		PlaceText( g_nCurrentX + f_nBoxPadding, g_nCurrentY, g_nColumnWidth - (f_nBoxPadding * 2), strChannelHeading );
		g_nCurrentY += nChannelHeight;
	}

	//
	//	Decide whether to show the descriptions for shows based on how they have been highlighted
	//		and the options the user has selected.
	var strProgrammeDetails = "";
	var	bProgrammeDescriptionIncluded = false;

	//
	// Get descriptions
	if( ShouldIncludeProgrammeDescription( nProgramme ) )
	{
		strProgrammeDetails = GetProgrammeInfo( nProgramme, GetProgVPlusDesc( nProgramme ) );
		bProgrammeDescriptionIncluded = true;
	}
	else
	{
		strProgrammeDetails = GetProgrammeInfo( nProgramme, f_strProgrammeDetailsTemplateWithoutDescription );
		bProgrammeDescriptionIncluded = true;
	}
	strProgrammeDetails = ConvertCRLFForHTML( strProgrammeDetails );

	//
	// Add in icons
	var strMarkers = strIcons = strBlobs = "";
	var arrMarkers = GetMarkersForProgramme( nProgramme );
	for( var n = 0; n < arrMarkers.length; n++ )
	{
		var nMarker = arrMarkers[ n ];
		if( !IsProgrammeExcludedFromMarker( nProgramme, nMarker ) )
		{
			var strIcon = GetMarkerInfo( nMarker, "$MarkerIcon" );

			if( strIcon )
			{
				strIcons += '&nbsp;<img src="Marker-ICON:' + strIcon + '">';
			}

			var strBlob = GetMarkerInfo( nMarker, "$MarkerBlob" );
			if( strBlob )
			{
				strBlobs += '&nbsp;<img src="Marker-BLOB:' + strBlob + '" width=11 height=11>';
			}
		}
	}
	strMarkers = strIcons + strBlobs;
	strProgrammeDetails = strProgrammeDetails.replace("$MarkerIcons", strMarkers );
	if( f_bDrawLinesBetweenProgs ) strProgrammeDetails += "<hr noshade size=1 width='100%%'>";


	//
	//	if the day is different then we throw a column or throw a page depending on 'fiddle' vars
	var dtCurrent = new Date( GetProgrammeInfo( nProgramme, "$USStartDateTime" ) );
	g_nProgHeight = MeasureText( g_nColumnWidth - (f_nBoxPadding * 2), strProgrammeDetails );

	if( g_dtDay.getDate() != dtCurrent.getDate() )
	{
		g_dtDay = dtCurrent;
		if( f_bNewPageOnDay )
		{
			ThrowNewPage( nProgramme );
		}
		else
		{
			if ( f_bNewColumnOnDay )
				NextColumn( nProgramme );
		}
	}

	//
	//	If the object wont fit then try another column
	if( g_nCurrentY + g_nProgHeight > g_nPageBottom )
		NextColumn( nProgramme );


	//
	// Dont pad out programme information
	PlaceText( g_nCurrentX + f_nBoxPadding, g_nCurrentY, g_nColumnWidth - (f_nBoxPadding * 2), strProgrammeDetails );
	g_nCurrentY += g_nProgHeight;
	

	// Dont pad out programme information if no description
	if( bProgrammeDescriptionIncluded )
		g_nCurrentY += f_nProgrammeGap;
}


var arrChannels = GetChannelListFromProgrammes();
var nPrintedProgrammes = 0;
//
// Main programme writing loop
for( var nDayCount = 0; nDayCount < Options.DaysToPrint && !HasAborted(); nDayCount++ )
{
	SetDates();

	for( var nChannel = 0; nChannel < arrChannels.length && !HasAborted(); nChannel++ )
	{
		//DebugOut( "CHANNEL: " + arrChannels[ nChannel ] );
		var arrProgrammes = GetProgrammeListForChannelDateRange( arrChannels[ nChannel ], g_dtStartTime, g_dtEndTime );

		for( var nProgramme = 0; nProgramme < arrProgrammes.length && !HasAborted(); nProgramme++ )
		{
			ShowProgramme( arrProgrammes[ nProgramme ] );
			nPrintedProgrammes++;
			SetProgress( nPrintedProgrammes, g_nProgCount - 1 );
		}
	}

	var nTime = g_dtCurrent.getTime();
	nTime += g_nMillisecondsPerDay;
	g_dtCurrent.setTime( nTime );
	g_dtCurrent.setHours( 12 );

}
]]></main-code>
</print-template>