// This script allows the specification of a group/set of pageset and generates
// two kinds of navigation widgets for that set:
// 
// 1) writeTitleIndex() writes a list of the titles of the pageset in the form:
//		1. Title 1
//		2. Title 2
//		3. Title 3
//		...etc.
// 2) writeNumberIndex() writes a single strip of navigation buttons in the form:
//		<< [ 1 | 2 | 3 | 4 | etc. ] >>
//
// Both base their outputs on the pageset array defined just below this comment.
// pageset is an array of arrays; the only realistic way to generate a 2D array
// in Javascript, but a ridiculously powerful one. Each element in the array is
// an array of three elements (although Javascript isn't typed, this may help
// explain what I was thinking when I wrote this):
//
// (NUMBER position, STRING URL, STRING Title)
// 
// The variables pgPosition, pgURL and pgTitle defined below help make it easier
// for a human to decipher what's going on, rather than unexplained references to
// the 0th element or whatever.
//
// Ye recipe to make this work:
// 1) Reference this script in your web page. Hint:
//    
//    <script type="text/javascript" src="{path to this script}">
//    
//    Put it inside the <head></head> tags for correctness and to avoid unexplained
//    newlines in your pageset.
// 2) call setTitle() to specify the name of the page set. writeTitleIndex() will 
//    inject this as a H1 into the document above the title list (if it's been
//    specified, at least).
// 3) Call addpage() a few times. addPage populates the pageset array, and reorders
//    its contents where necessary when people specify duplicate positions etc.
// 4) To get a nav widget of the types listed above, call the relevant function,
//    telling it which page of the set you're on now, e.g.
//    
//    writeTitleIndex(2) 
//    
//    ...will tell it to write the list of titles assuming it's on the second 
//    item in the array. (Well, with Javascript, the second item in the array 
//    is actually item #1, as it's zero-based, but the script accounts for this 
//    - it's zero-based internally but the lists it generates and the parameters
//    it accepts are one-based.
//
//  as they say in France, et voilá!
//  
//  Created	29/03/2003, Domhnall Walsh
//  Edited	31/03/2003, Domhnall Walsh, to fix lack of support for Array::push, 
//  Array::pop and Array::splice in IE < 5.5...
//  Edited	02/04/2003, Domhnall Walsh, to add a "back to top" link at the bottom 
//  of each page beside the numbered page list.
//  Edited	07/04/2003, Domhnall Walsh:
//    1) To add a feature to the writeTitleIndex function so that it could do 
//       multiple columns if need be...
//    2) To close the <a> tag in the line {output = '<a name="top">'...} in 
//       writeTitleIndex as it was causing Mozilla/Netscape to thing the whole
//       document (up to the next <a> tag, at least) was a link to the top... :-} 
var pageset = new Array();
var title = '';
var pgPosition = 0;
var pgURL = 1;
var pgTitle = 2;

// Step 2 above explains why these are here...
function getTitle()
{
	return title;
}

function setTitle(value)
{
	title = value;
}

// As we're using a pseudo-2D array to store the page nav contents, we need a 
// custom sort function to ensure that they're sorted by the value of their 
// position value:
function customsort(a, b)
{
	if (a[pgPosition] < b[pgPosition]) return -1;
	if (a[pgPosition] > b[pgPosition]) return 1;
	return 0;
}

// This function renumbers all the "position" values of the other pageset
// so that there's a gap (if necessary) for the position of the item
// that's about to be inserted...
function addPositionAt(position)
{
	// first, find if there's already a gap...
	var currentItem;
	var gapExists = true;
	for (i=0; i < pageset.length; i++)
	{
		if (pageset[i][pgPosition] == position)
		{
			gapExists = false;
			break;
		}
	}
	
	if (!gapExists)
	{
		for (i=0; i < pageset.length; i++)
		{
			currentItem = pageset[i];
			if (currentItem[pgPosition] >= position) currentItem[pgPosition]++;
		}
	}
}

// Exact opposite - collapses holes in the ordinal positioning of the list 
// elements.
function removePositionAt(position)
{
	var currentItem;
	for (i=0; i < pageset.length; i++)
	{
		currentItem = pageset[i];
		if (currentItem[pgPosition] > position) currentItem[pgPosition]--;
	}
}

// Call this function to add a page to the list; the parameters should be
// obvious.
function addPage(URL, title, position)
{
	if (pageset.length == 0)
	{
		position = 1;
	}
	else
	{
		addPositionAt(position);
	}
	
	var newItem = new Array(position, URL, title);
	// 31/03/2003, DW: Versions of IE prior to 5.5 don't support 
	// Array::push (why?). This checks if the method exists and "works around" 
	// the problem if it doesn't (although Array::concat() required JavaScript 
	// 1.2, but I've not got a lot of options...)
	if (!pageset.push)
	{
		pageset = pageset.concat(new Array(newItem));
		// Another potential method, if IE < 5.5 supported Array::splice :-(
		// pageset.splice(pageset.length - 1,0,newItem);
	}
	else
	{
		pageset.push(newItem);
	}
	
	pageset.sort(customsort);
	return pageset.length;
}

// I doubt this will ever be used, but it removes a page, if you so wish,
// and fixes the gap this would otherwise leave in the position list.
// Included for completeness more than any realistic expectation of use.
// 31/03/2003, DW: Added alternative to using Array::splice for when 
// the browser doesn't support it.
function removePage(position)
{
	for (i=0;i < pageset.length;i++)
	{
		if (pageset[i][pgPosition] == position)
		{
			// This is the accepted way to check if a property or method 
			// is supported (note no '()' after the call!)
			if (!pageset.splice)
			{
				// For when Array::splice isn't supported, we have to do something
				// like this:
				switch (i)
				{
					case 0:
					{
						pageset = pageset.slice(1,pageset.length);
						break;
					}
					case pageset.length:
					{
						pageset = pageset.slice(0,(pageset.length - 1));
						break;
					}
					default:
					{
						var before = pageset.slice(0,i);
						var after = pageset.slice(i+1,pageset.length);
						pageset = (new Array).concat(before, after);
					}
				}
			}
			else
			{
				// Otherwise, it's as easy as...
				pageset.splice(i,1);
			}
			removePositionAt(position);
			break;
		}
	}
	return pageset.length;
}

// This function writes a list of page titles to the screen, in the form:
// <h1>{Page Set Title}</h1>
//		1. Title 1
//		2. Title 2
//		3. Title 3
//		...etc.
// <h2>{Current Page Title}</h2>
function writeTitleIndex(currentpage)
{
	var output;
	var pagedata;
	var columns = 1;
	var splitevery = pageset.length + 1;
	
	// This does the page-by-page listing.
	output = '<a name="top">' + ((title != '')?'<h1>' + title + '</h1>':'') + '</a>';//<p class="smalltext"><b>Pages:</b></p>';
	
	// Decide how many columns we want. 1-5 items: 1 column. 6-8 items: 2 columns, 9+ items: 3 columns.
	var approxColumns = Math.floor(pageset.length / 3);
	switch (approxColumns)
	{
		case 0:
			break;
		case 1:
			break;
		case 2: 
			columns = 2;
			break;
		default:
			columns = 3;
	}
	
	// If we're using multiple columns, we'll need a table. We'll also have to figure out how
	// often we split the list up into columns...
	if (columns > 1)
	{
		splitevery = Math.floor(pageset.length / columns) + (((pageset.length % columns)==0)?0:1);
		output = output + '<table border="0" width="100%"><tr><td width="' + Math.floor(100/columns) + '%" valign="top">';
	}
	
	output = output + '<ol class="smalltext">';
	
	for (pageIndex = 1; pageIndex <= pageset.length; pageIndex++)
	{
		pagedata = pageset[pageIndex - 1];
		output = output + '<li>';
		if (currentpage == pageIndex)
		{
			output = output + '<span class="currentpage">' + pagedata[pgTitle] + '</span>';
		}
		else
		{
			output = output + '<a href="' + pagedata[pgURL] + '">' + pagedata[pgTitle] + '</a>';
		}
		output = output + '</li>';
		if ((pageIndex % splitevery == 0) && (pageIndex < pageset.length))
		{
			output = output + '</ol></td><td width="' + Math.floor(100/columns) + '%" valign="top">';
			output = output + '<ol class="smalltext" start="' + (pageIndex + 1) + '">';
		}
	}
	
	// This will close the cell, row and table if required
	output = output + '</ol>' + ((columns > 1)?'</td></tr></table>':'');
	// write the page header.
	output = output + '<hr><h2>'+ pageset[currentpage - 1][pgTitle] + '</h2>';
	return output;
}


// This function writes a single strip of clickable page numbers to the screen,
// in the form:
//		<< [ 1 | 2 | 3 | 4 | etc. ] >>
function writeNumberIndex(currentpage)
{
	var output;
	var pagedata;
	
	output = '<hr><p class="smalltext"><a href="#top">[Top]</a> <b>Page: </b>';
	output = output + ((currentpage > 1)?'<a href="' + pageset[currentpage - 2][pgURL] + '">&#xab;</a>':'&nbsp;&nbsp;') + ' [ ';
	for (pageIndex = 1; pageIndex <= pageset.length; pageIndex++)
	{
		pagedata = pageset[pageIndex - 1];
		if (currentpage == pageIndex)
		{
			output = output + '<span class="currentpage">' + currentpage + '</span> ';
		}
		else
		{
			output = output + '<a href="' + pagedata[pgURL] + '">' + pageIndex + '</a> ';
		}
		if (pageIndex < pageset.length) output = output + " | ";
	}
	output = output + '] ' + ((currentpage < pageset.length)?'<a href="' + pageset[currentpage][pgURL] + '">&#xbb;</a>':'&nbsp;&nbsp;');
	output = output + '</p>'; 
	return output;
}
