// Main javascript file for brianmacmillan.com
// Copyright 2008 by Brian MacMillan
// Notes on variable prefixes:
// gai - global array integer
// gi - global integer
// gf - global float 
// pi - parameter integer eg function myfunct(piWhichValue){}
//  i - locally scoped integer, eg var iAmount = 1;
//  f - locally scoped float, eg var fAmount = 1.9;
//  e - element, eg e = document.getElementById("toc1");

/*
Also, if you edit this file, please respect my preference for positive logic. 
I find that it results in fewer errors (I have bad eye site and its easy to miss
the negation operator !)
For example:

if (validatePassword())
{
	// Do nothing. login worked.
} else
{
	return 0;
}
*/

// Note that some variables have an integer and string version.
// This is to insulate the code from casting problems, where, for example, a font size
// is expressed as 18px but my calculations depend on the integer 18.
// Also note that some locals have been caste as globals to simplify function calls.


//NB Brian flip this flag to false before deployment.
var LOCALHOST = true;
var SUCCESS = 0;  // queries return 0 on success, non zero on failiure.

// giDebug - non zero values displays error messages.
var giDebug = 0;

giCurrentUserKey=0;

//Note bene: the two variables below are an exception to the rule that ALL styling occurs in the CSS
//The issue here is that toc events trigger style changes on multiple objects
var gsTOCColor = "#666"; //"#04e";
var gsTOCHoverColor = "#404"; //"#04e";

// giPageLoaded == 1 when html doc loaded. 
var giPageLoaded = 0;

var gbLoggedIn=false; //equals true when logged in 

//adding and deleting stories impacts the following:
/* 
giStoryLoaded[]

*/
/* Tabs */
/* the order is help, login, preferences, comments, ratings */
// giTabList is used to handle tab z-order
var giTabList = new Array();
giTabList[0]="";
giTabList[1]="";
giTabList[2]="";
giTabList[3]="";
giTabList[4]="";

var gbLoginInProcess = 0;
var LOGIN_URL = "php/login.php";
var LOGEVENT_URL = "php/logEvent.php";
var COMMENTS_INSERT_URL = "php/commentsInsert.php";
var COMMENTS_GET_URL = "php/commentsGet.php";
var PREFERENCES_UPDATE_URL = "php/preferencesUpdate.php";
var USERS_UPDATE_URL = "php/usersUpdate.php";
var CHANGE_PASSWORD_URL = "php/changePassword.php";

// There is a need to synchronize these values with the login.php script.
var LOGIN_SUCCESS = 0;
var LOGIN_ERROR_MISSING_ARGUMENTS = 1;
var LOGIN_ERROR_NO_DATABASE_CONNECTION = 2;
var LOGIN_ERROR_INVALID_USERNAME_PASSWORD = 3;
var LOGIN_ERROR_USER_NAME_ALREADY_EXISTS = 4;

var COMMENTS_ADD_BUTTON = "Add Comment";
var COMMENTS_SUBMIT_BUTTON = "Submit Comment";
var MINIMUM_COMMENT_LENGTH = 5;

var ARROW_NEXT ="pictures/arrow-next-light-orange.png";
var ARROW_PREVIOUS="pictures/arrow-previous-light-orange.png";
var ARROW_NEXT_MOUSE_OVER ="pictures/arrow-next-orange.png";
var ARROW_PREVIOUS_MOUSE_OVER="pictures/arrow-previous-orange.png";

var TAB_COUNT = 5;
var TAB_GUTTER = 15; //gutter between toc-navbar images, as percent

var TAB_HELP=300; //zIndex and unique identifier 
var TAB_LOGIN=301; 
var TAB_PREFERENCES=302;
var TAB_COMMENTS=303;
var TAB_RATING=304;

var CONTENT_HEIGHT_WITH_FOOTER = "84%"; /* */
var CONTENT_HEIGHT_NO_FOOTER = "88%"; /* */



// vars which index into the option menu
var OPT_HELP="opt6";
var OPT_PREF="opt0";
var OPT_FOOTER="opt4";
var OPT_LOGIN="opt1";
var OPT_COMMENT="opt3";
var OPT_RATING="opt8";
var OPT_REDRAW="opt10";
var OPT_LOGOUT="opt11";

var TAB_ZINDEX_SHOW = "401";
var NAV_ZINDEX_SHOW = 400; // default zIndex in a "bring to top" event for navbar used by bigicon.
//var FOOTER_RIGHT_ZINDEX_SHOW = 400;
//var TAB_MASK_ZINDEX = 399;  // 

var NAVBAR_COUNT = 11;
var NAVBAR_GUTTER = 10; //space in percent, between navbar images

var NAVBAR_HOME = 0; // - img0 displays the home icon on the navbar

//Two different ways of viewing chapters
var DEFAULT_TOC_MENU = 0;
var DEFAULT_TOC_TOOLBAR = 1;
	
var EDITING_NOTHING = 0;
var EDITING_USERNAME = 1;
var EDITING_PASSWORD = 2;
var EDITING_EMAIL = 3;
var EDITING_CITY = 4;
var EDITING_COMMENTS = 5;
var EDITING_EXISTING_PASSWORD = 6;
var EDITING_NEW_PASSWORD = 7;
var EDITING_CONFIRM_NEW_PASSWORD = 8;
var EDITING_FIRST_NAME = 9;
var EDITING_LAST_NAME = 10;
var EDITING_PREFERENCES_UPDATE_PASSWORD_BUTTON = 11;

// Used mostly by window.keyUp to handle keyboard input.
var KEY_TAB = 9;
var KEY_ENTER = 13;
var KEY_UP_ARROW = 38;
var KEY_DOWN_ARROW = 40;
var KEY_LEFT_ARROW = 37;
var KEY_RIGHT_ARROW = 39;
		
//var KEY_RIGHT_ARROW = 39;

var giCurrentEditMode = EDITING_NOTHING;

var DEFAULT_SHOW_ERRORS = 1;

var DEFAULT_USERNAME = "enter your username or email";
var DEFAULT_PASSWORD = "enter your password";
var DEFAULT_EMAIL = "enter your email";
var DEFAULT_CITY = "enter your city";

// Used to handle the display of subsections on the preferences and help tabs.
var HELP_OVERVIEW = 1;
var HELP_NAVIGATION = 2;
var HELP_SHORTCUTS = 3;
var PREFERENCES_PERSONAL=1;
var PREFERENCES_INTERFACE=2;
var PREFERENCES_UPDATE_PASSWORD=3;

var VALIDATE_LOGIN = "login"; // used by funciton validate() to centralize all edit checks 
var VALIDATE_USERNAME = "username"; // used by funciton validate() to centralize all edit checks 
var VALIDATE_PASSWORD = "password"; // used by funciton validate() to centralize all edit checks 

// Flags for switching column width. Hardwired to two sizes
var WIDTH_WIDE = 1;
var WIDTH_NARROW = 2;
var giCurrentColWidth = WIDTH_NARROW;

var TOC_NAVBAR_COUNT = 6;
var TOC_NAVBAR_GUTTER = 0; //space in percent, between navbar images
var HIGHLIGHT_COLOR_CURRENT_CHAPTER = "green";

var giDefaultTOC = DEFAULT_TOC_TOOLBAR; // 0 is menu, 1 is buttons

var gsPreviousCursorStyle; // used by content-inner on mouse out event to reset cursor
var giPreviousZIndex = 1; // used by navClose and bigIcon to reset zIndex after a mouse over event

/* end tabs */

// To do - make the following variables arrays to handle stories/chapters of currently displayed book
// giStoryLoaded == 1 when individual story is loaded.
var giStoryLoaded = new Array();
giStoryLoaded[0]=0;
giStoryLoaded[1]=0;
giStoryLoaded[2]=0;
giStoryLoaded[3]=0;
giStoryLoaded[4]=0;
giStoryLoaded[5]=0;
giStoryLoaded[6]=0;

// page counter - zero based. 
// when display shows 1, currentpage == 0 
var giCurrentPage = new Array();
 	giCurrentPage[0] = 0;
	giCurrentPage[1] = 0;

// giParaLimit - number of paragraphs in current story
var giParaLimit = new Array();
	giParaLimit[0] = 0;
	giParaLimit[1] = 0;

// giPageLimit - number of pages in current story. 
// giPageLimit can be calculated dynamically so it is just a convenience.

var giPageLimit = new Array();
	giPageLimit[0] = 0;
	giPageLimit[1] = 0;
	giPageLimit[2] = 0;
	giPageLimit[3] = 0;
	giPageLimit[4] = 0;
	giPageLimit[5] = 0;

// g(s)(i)BaseFontSize - dynamically determined; initially from style sheet in setGlobals
var gsBaseFontSize = "12px"; //px 
// giFontSize is integer version of gsBaseFontSize. For convenience only.
var giFontSize = 12;

var giLineHeight = 12; // integer version derived from style sheet in setGlobals

// giFirstParagraph - which paragraph starts the current page
// it is used by redraw function to move the current page to a sensible location
// after a redraw event. the idea is that after a redraw, the current page includes the first paragraph 
// from the page as it was before the resize event. 
var giFirstParagraph = 0;

// Synchronize with CSS. To do: make dynamic. Query DOM object after base load.
var giContentInnerMargin = 5; //px change if content inner margin changes in css!

var gsColumnHeight = "auto";
var gsColumnWidth = "48%";
var gsColumnTextHeight = "12px";
var gsOffsetHeight; //size of textResizeControl
var gfColumnHeight = 500;

// To do: remove.
var giIndexIntoLineHeightArray = 3;
		
// These variables could be private to a function. Made global because function calls got too long.
// gasParaHeight is key to this program - it contains the height in pixels of every paragraph in a story.
var gasParaHeight = new Array();
gasParaHeight[0] =  new Array();
gasParaHeight[1] =  new Array();

// float version of gasParaheight. (gas means global array string)
var gafParaHeight = new Array();
gafParaHeight[0] = new Array();
gafParaHeight[1] = new Array();

var giParaSpacing = 6; // To do: read from css - same as lineheight property of current style.

// size of the content html element in pixels and floats.
// to do - remove gsContentHeight and only use the float
var gsContentHeight = "800";
var gsContentWidth = "400";
var gfContentHeight = 800;
var gfContentWidth = 400;

// the bottom of each column has a mask that covers the one or two lines that separate
// the bottom of the text and the bottom of the column (which clips overflow)
// dynamically recalculated.
var gaiColMaskHeight = new Array();
	gaiColMaskHeight[0]=0;
	gaiColMaskHeight[1]=0;
var gaiColMaskTop = new Array();
	gaiColMaskTop[0]=0;
	gaiColMaskTop[1]=0;

// gaiOverlapParaLines - the total number of lines of the paragraph which overlaps between each page.
// one array element per page.
var gaiOverlapParaLines = new Array();
	gaiOverlapParaLines[0] = 0;	
// gaiOverlapLines contains a snapshot of the overlap lines between every page in a story/chapter.
//    it is recalculated on page resize and on page load.
var gaiOverlapLines = new Array();
	gaiOverlapLines[0] = 0;
// pixel version of gaiOverlapLines. used to exactly calculate colMaskTop - the mask at the bottom of each page.
var gaiOverlapHeight = new Array();
	gaiOverlapHeight[0]="0";
	gaiOverlapHeight[1]="0";
var gaiNonOverlapLines = new Array();
	gaiNonOverlapLines[0] = 0;
var gaiNonOverlapHeight = new Array();
	gaiNonOverlapHeight[0]="0";
	gaiNonOverlapHeight[1]="0";

// To do: remove / legacy adjustment for top of column padding.
var gaiTopMarginAdjustment = 0;
	
var	gaiTopMargin = new Array();
	gaiTopMargin[0] = 0;
	gaiTopMargin[1] = 0;

var gasTopMargin = new Array();
	gasTopMargin[0] = "0px";
	gasTopMargin[1] = "0px";

//running total of paragraph heights (aggregate). used to calculate the number of lines per page.
var gafAggrParaHeight = new Array(); 
	gafAggrParaHeight[0]=0;
	gafAggrParaHeight[1]=0;

//which paragraph does each page break on.
//page index is zero based	
var gaiParaBreak = new Array();
	gaiParaBreak[0]= new Array();
	gaiParaBreak[1]= new Array();
	
/* mouse stuff */
/* used for interpage scrolling */
var giOffsetX = -0;          // X offset from mouse position
var giOffsetY = -0;          // Y offset from mouse position
var gbDown = 0;
var giMouseX = 0;
var giMouseY = 0;

var giFirstLineAdjustmentIE = 27; // exception for IE. First para client height is off by 27 px.

/********** end of global variable definitions ***********/
// NB These element names must be coordinated with the 
// element names in the div. They are used to dynamically calculate
// the node count for each story (see getNodeCount)
// by querying the number of nodes belonging to the body-text class
// that are children of the element id.
var gasChapterElement = new Array()
gasChapterElement[0]="eternal-suffering";
gasChapterElement[1]="when-we-all-have-brains";
gasChapterElement[2]="skin-deep";
gasChapterElement[3]="food";
gasChapterElement[4]="swimming-with-the-invertebrates";
gasChapterElement[5]="dream-of-a-perfect-world";
gasChapterElement[6]="shopaholic-goes-to-calcutta";

var gasChapterTitle = new Array()
gasChapterTitle[0]="Eternal Suffering";
gasChapterTitle[1]="When We All Have Brains";
gasChapterTitle[2]="Skin Deep";
gasChapterTitle[3]="Food";
gasChapterTitle[4]="Swimming with the Invertebrates";
gasChapterTitle[5]="Dream of a Perfect World";
gasChapterTitle[6]="Shopaholic Goes to Calcutta";

var giCurrentChapter = 0;  // NB Brian ZERO not one based!!
var giCurrentStory = 0;   // NB Brian ZERO not one based!!
//Not universally used, should be for clarity
var httpRequest;
if (window.getComputedStyle)
{
	gbIE = false;
} else 
{
	gbIE = true;
}
//NB Use this only for IE6 and below. Does this code work?
if (window.XMLHttpRequest)
{
	httpRequest = new XMLHttpRequest();
} else
{
	httpRequest =  new ActiveXObject("Microsoft.XMLHTTP");
}
/*********** KEY UP ************************/
function windowKeyUp(evt)
{
	var iKey = getKeystroke(evt);
	var bShiftPressed = getShiftPressed(evt);
	var bAltPressed = getAltPressed(evt);
	var bCtrlPressed = getCtrlPressed(evt);

	//alert("the number of the key you hit is "+iKey);
	if (iKey == KEY_TAB)
	{
		if (giCurrentEditMode == EDITING_CONFIRM_NEW_PASSWORD)
		{
			//alert("editing confirm new password");
		}
	}
	if (giCurrentEditMode == EDITING_NOTHING)  // if something is beinig edited ... 
	{
		// Do nothing - fall through to bottom of function.
		//alert("editing nothing");
	}
	else
	{
		// The enter key triggers a login event when the password or username fields are being edited.
		if (iKey==KEY_ENTER)
		{
			if (giCurrentEditMode == EDITING_FIRST_NAME)
			{
				document.getElementById("last-name").focus();
				return;
			}
			if (giCurrentEditMode == EDITING_LAST_NAME)
			{
				document.getElementById("city").focus();
				return;
			}

			if (giCurrentEditMode == EDITING_CITY)
			{
				document.getElementById("email").focus();
				return;
			}
			if (giCurrentEditMode == EDITING_EMAIL)
			{
				document.getElementById("preferences-save-button").focus();
				return;
			}
			if (giCurrentEditMode == EDITING_USERNAME)
			{
				document.getElementById("password").focus();
				return;
			}
			if (giCurrentEditMode == EDITING_PASSWORD)
			{
				//alert("here");
				login();
				return;
			}
			if (giCurrentEditMode == EDITING_EXISTING_PASSWORD)
			{
				document.getElementById("new-password").focus();
				return;
			}
			if (giCurrentEditMode == EDITING_NEW_PASSWORD)
			{
				document.getElementById("confirm-new-password").focus();
				return;
			}
			if (giCurrentEditMode == EDITING_CONFIRM_NEW_PASSWORD)
			{
				preferencesUpdate();  //Should create a separate change password
				return;
			}
			if (giCurrentEditMode == EDITING_PREFERENCES_UPDATE_PASSWORD_BUTTON)
			{
				preferencesUpdatePassword();  //Should create a separate change password
				return;
			}			

		}
		// tab. mostly rely on tabiindex ... 
		/*
		if (iKey==KEY_TAB) 
		{
			alert("tab pressed");
			if (giCurrentEditMode == EDITING_CONFIRM_NEW_PASSWORD)
			{
				alert("there");
				document.getElementById("preferences-save-button").focus(); 
				return;
			}			
		}
		*/
		// disable alpha shortcuts (A=65), like p for preferences. Alternatively add an extra key, like Ctrl p for previous.

		if (iKey>64 || iKey==KEY_LEFT_ARROW || iKey == KEY_RIGHT_ARROW)
		{
			if (bCtrlPressed)
			{ 
				// do nothing
				// Ctrl + keystroke yields results which happen regardless of edit state.
				//alert("here");
			} else
			{
				//alert("here");
				return;
			}
		}
	}
	/*
	if( window.getComputedStyle) 
	{
		// not IE
		key = evt.which;
		//alert("debugging window keyup. You just pressed key "+key);	
	} else
	{
		key = event.keyCode;	
		//alert("debugging Internet Explorer keypress event. You just pressed key "+key);	
	}
	*/
	//ctrl left arrow - previous page
	if ((iKey==KEY_LEFT_ARROW && bCtrlPressed)) {previousPage()}
	//right arrow - next page
	if ((iKey==KEY_RIGHT_ARROW && bCtrlPressed)) {nextPage()}

	//down arrow  40 - go to end of story
	if ((iKey==KEY_DOWN_ARROW && bCtrlPressed)) {
		//giCurrentPage[giCurrentChapter] = giPageLimit[giCurrentChapter]-1;
		//nextPage();
	}

	//up arrow 38 - go to end of story
	if ((iKey==KEY_UP_ARROW && bCtrlPressed)) {
		//giCurrentPage[giCurrentChapter] = giPageLimit[giCurrentChapter]-1;
		//previousPage();
	}

	//page down
	if (iKey==36) {nextPage()}


	//p - preferences
	if (iKey==80) 
	{
		if (gbLoggedIn)
		{
			preferencesHideShow();
		}
	}
	//w - wide / narrow toggle
	if ((bCtrlPressed && iKey==87)) {
		//	alert("toggle");
		var sNewWidth;
		if (giCurrentColWidth == WIDTH_NARROW)
		{
			sNewWidth = WIDTH_WIDE;
		} 
		if (giCurrentColWidth = WIDTH_WIDE)
		{
			sNewWidth = WIDTH_NARROW;
		}
		setColumnWidth(sNewWidth);
	}


	//r - resize
	if (iKey==82) {drawPage("resize")}

	//l - login
	if (iKey==76) 
	{
		if (!gbLoggedIn)
		{
			loginShow();
		}
	}


	// Using keys like this is a stupid idea unless control over editing is tightly controlled.
	
	if (iKey==67) {commentsHideShow()}

	if (iKey==72) {helpHideShow()}

	if (iKey==78) {nextPage()}

	//page up
	if (iKey==33) {previousPage()}
	//page down
	if (iKey==34) {nextPage()}

	
}

// Test to see if javascript is enabled 
function noJavascriptEventHandler() 
{
	//note that the element needs to exist for this to work
	var element = document.getElementById('no-javascript');
	element.style.display="none";
}
/********* INITIALIZATION FUNCTIONS **************/
function setDefaults()
{
	try
	{
		navbarInit();
		tocNavbarInit();
		colWidthInit();
		helpShowSection(HELP_NAVIGATION);
		preferencesShowSection(PREFERENCES_PERSONAL);
		usernamePasswordEmailInit();
		commentsInit();
		tocNavMouseOut("toc-img",giCurrentChapter);  
		footerRightHideShow("none");  // NB Brian need to trigger off of table settings
		if (LOCALHOST)  // helps my testing
		{
			document.getElementById("username").value = "bmacmill";
			document.getElementById("password").value = "nevsky";			
		} else
		{
			document.getElementById("username").value = "<username>";
			document.getElementById("login-submit-button").disabled = false;			
		}
		document.getElementById("username").focus();
	} catch(err)
	{
		errorHandler("setDefaults",err);
	}
}

function navbarInit()
{
	try
	{
		var e;
		var iLeftPercent = 0;
		var sLeftPercent = "";
		for (var i=0;i<NAVBAR_COUNT;i++)
		{
			ileftPercent = NAVBAR_GUTTER*i;
			sLeftPercent = ileftPercent.toString()+"%";
			e = document.getElementById("nav"+i); 
			e.style.left = sLeftPercent;
		}
	} catch(err)
	{
		errorHandler("Error in navbarInit ",err);
	}
}
function colWidthInit()
{
	//read key css values into variables which are used to resize (or unddo a resize)
	//slower than hardwiring the values as constants but more reliable. 
	//implement in final drafts for speed.
	setColumnWidth(giCurrentColWidth);
}
function tocNavbarInit()
{
	try
	{
		var e;
		var iLeftPercent = 0;
		var sLeftPercent = "";
		for (var i=0;i<TOC_NAVBAR_COUNT;i++)
		{
			ileftPercent = TOC_NAVBAR_GUTTER*i;
			sLeftPercent = ileftPercent.toString()+"%";
			if (i<3)
			{
				//alert("sLeftPercent "+sLeftPercent+" "+ileftPercent);
			}
			e = document.getElementById("toc-nav"+i); 
			e.style.left = sLeftPercent;
		}
	} catch(err)
	{
		alert("Error in tocNavbarInit "+err.message);
	}
}
function commentsInit()
{
	document.getElementById("your-comments").style.display="none";
	document.getElementById("comments-add-button").value = COMMENTS_ADD_BUTTON; // make constant for programming purposes
}
function setPreferences(piPreferenceArray)
{
	try
	{
		// NB Brian This needs to by synced with login.php database->getPreferences
		// To start change value to checked.
		giCurrentUserKey=piPreferenceArray[2];
		//alert("current user key "+giCurrentUserKey);
		
		document.getElementById("show-navigation-arrows").checked = integerToBoolean(piPreferenceArray[3]);
		document.getElementById("wide-text-columns").checked = integerToBoolean(piPreferenceArray[4]);
		document.getElementById("show-footer").checked =integerToBoolean(piPreferenceArray[5]);
		document.getElementById("show-help").checked = integerToBoolean(piPreferenceArray[6]);
		document.getElementById("show-comments").checked = integerToBoolean(piPreferenceArray[7]);
		document.getElementById("show-preferences").checked = integerToBoolean(piPreferenceArray[8]);
		document.getElementById("show-ratings").checked = integerToBoolean(piPreferenceArray[9]);
		document.getElementById("show-editor").checked = integerToBoolean(piPreferenceArray[10]);
		document.getElementById("city").value = piPreferenceArray[11];
		document.getElementById("email").value = piPreferenceArray[12];
		document.getElementById("first-name").value = piPreferenceArray[13];
		document.getElementById("last-name").value = piPreferenceArray[14];

	} catch(err)
	{
		errorHandler("setPreferences",err);
	}
}
/********* END OF INITIALIZATION FUNCTIONS **************/
/********* EVENT HANDLERS ***********/
function navbarHideShowButtonEventHandler()
{
	var e = document.getElementById('navbar-hide-show-img');
	e.style.display = "block";
	e.onmouseup = function() {hideShowNavbar()};
	e.onmouseover = function() {navbarHideShowButtonMouseOver()};
	e.onmouseout = function() {navbarHideShowButtonMouseOut()};
}
function hideShowNavbar()
{
	//NB Brian should create a separate function for the navbar independent of the footer
	footerHideShow();
}
function navbarHideShowButtonMouseOver()
{
	try
	{
		gsPreviousCursorStyle = document.body.style.cursor;
		document.body.style.cursor = "pointer";
	} catch(err)
	{
		errorHandler("navbarHideShowButtonMouseOver",err);
	}
}
function navbarHideShowButtonMouseOut()
{
	try
	{		
		document.body.style.cursor = gsPreviousCursorStyle;
	} catch(err)
	{
		errorHandler("navbarHideShowButtonMouseOut",err);
	}
}
function tabWideNarrowEventHandler()
{
	var e = document.getElementById('tab-wide-narrow-img');
	e.style.display = "block";
	e.onmouseup = function() {setColumnWidthEvent()};
	e.onmouseover = function() {tabWideNarrowMouseOver()};
	e.onmouseout = function() {tabWideNarrowMouseOut()};
}
function tabWideNarrowMouseOver()
{
	try
	{
		gsPreviousCursorStyle = document.body.style.cursor;
		document.body.style.cursor = "pointer";
	} catch(err)
	{
		errorHandler("tabWideNarrowMouseOver",err);
	}
}
function tabWideNarrowMouseOut()
{
	try
	{		
		document.body.style.cursor = gsPreviousCursorStyle;
	} catch(err)
	{
		errorHandler("tabWideNarrowMouseOut",err);
	}
}
function loginEventHandler()
{
	//note that the element needs to exist for this to work
	var e = document.getElementById('login-submit-button');
	e.onclick = function() {login();}	
	e = document.getElementById('password');
	e.onfocus = function() {passwordOnFocus();}
	e.onblur = function() {passwordOnBlur();}
	var e = document.getElementById('username');
	e.onfocus = function() {usernameOnFocus();}
	e.onblur = function() {usernameOnBlur();}
	e.onkeypress = function() {userNameKeyPress;}
}
function userNameKeyPress()
{
	var key = getKeyPress();
}
function headertoggleEventHandler() 
{
	//note that the element needs to exist for this to work
	var e = document.getElementById('header-toggle');
	e.onmouseup = function() {headerHideShow();}	
}
// trap for mouse up events on the next and previous elements.
function navigationEventHandler() {
	//note that the element needs to exist for this to work
	//alert("in navigationEventHandler");
	try
	{
		/* HEADER NAVIGATION */
		var sCurrentElementName;
		var e;
		sCurrentElementName="content-header-left-next";
		e = document.getElementById('content-header-left-next');
		e.style.display = "block";
		e.onmouseup = function() {nextPage();}
		//e = document.getElementById('content-header-left-next-img');
		e.onmouseover = function() {navArrowOnMouseOver("content-header-left-next");}
		e.onmouseout = function() {navArrowOnMouseOut("content-header-left-next");}
		sCurrentElementName="content-header-right-next";
		e = document.getElementById('content-header-right-next');
		e.style.display = "block";
		e.onmouseup = function() {nextPage();}
		//e = document.getElementById('content-header-right-next-img');
		e.onmouseover = function() {navArrowOnMouseOver("content-header-right-next");}		
		e.onmouseout = function() {navArrowOnMouseOut("content-header-right-next");}	
		sCurrentElementName="content-header-left-previous";
		e = document.getElementById('content-header-left-previous');
		e.style.display = "block";
		e.onmouseup = function() {previousPage();} 
		e.onmouseover = function() {navArrowOnMouseOver("content-header-left-previous");}		
		e.onmouseout = function() {navArrowOnMouseOut("content-header-left-previous");}	
		sCurrentElementName="content-header-right-previous";		
		e = document.getElementById('content-header-right-previous');
		e.style.display = "block";
		e.onmouseup = function() {previousPage();} 
		e.onmousover = function() {navArrowOnMouseOver("content-header-right-previous");}
		e.onmouseout = function() {navArrowOnMouseOut("content-header-right-previous");}
				
		/* FOOTER NAVIGATION */
		// NB  Brian
		/*
		sCurrentElementName="content-navigation-left-next";
		e = document.getElementById('content-navigation-left-next');
		e.style.display = "block";
		e.onmouseup = function() {nextPage();}

		e = document.getElementById('content-navigation-right-next');
		e.style.display = "block";
		e.onmouseup = function() {nextPage();}

		e = document.getElementById('content-navigation-left-previous');
		e.style.display = "block";
		e.onmouseup = function() {previousPage();} 

		e = document.getElementById('content-navigation-right-previous');
		e.style.display = "block";
		e.onmouseup = function() {previousPage();}
		*/
		e = document.getElementById('gutter');
		e.onmouseup = function(event) {gutterOnMouseUp(event);}

	} catch(err)
	{
		errorHandler("NavigationEventHandler element "+sCurrentElementName,err);
	}
}
function navArrowOnMouseOver(psElementName)
{
	try
	{
		// NB Brian - cursor style is not changing.
		gsPreviousCursorStyle = document.body.style.cursor;
		document.body.style.cursor = "pointer";
		if (document.getElementById(psElementName).src == ARROW_NEXT)
		{
			document.getElementById(psElementName).src == ARROW_NEXT_MOUSE_OVER;
		};
		if (document.getElementById(psElementName).src == ARROW_PREVIOUS)
		{
			document.getElementById(psElementName).src == ARROW_PREVIOUS_MOUSE_OVER;
		};
	} catch(err)
	{
		errorHandler("navArrowOnMouseOver",err);
	}
}
function navArrowOnMouseOut(psElementName)
{
	try
	{
		document.body.style.cursor = gsPreviousCursorStyle;
		if (document.getElementById(psElementName).src == ARROW_NEXT_MOUSE_OVER)
		{
			document.getElementById(psElementName).src == ARROW_NEXT;
		};
		if (document.getElementById(psElementName).src == ARROW_PREVIOUS_MOUSE_OVER)
		{
			document.getElementById(psElementName).src == ARROW_PREVIOUS;
		};
	} catch(err)
	{
		errorHandler("navArrowOnMouseOver",err);
	}
}
function commentsEventHandler()
{
	var e = document.getElementById('comments-add-button');
	e.onmouseup = function() 
	{
		commentsAdd();
	}
	e = document.getElementById('your-comments');
	e.onfocus = function() {commentsOnFocus();}
	e.onblur = function() {commentsOnBlur();}
}
function contentHeaderLeftEventHandler() {
	try
	{
		//note that the element needs to exist for this to work
		var e = document.getElementById('content-header-left-right');
		e.onclick = function() {contentHeaderLeftOnClick();}
	} catch(err)
	{
		errorHandler("contentHeaderLeftEventHandler ",err);
	}
}
function contentHeaderRightEventHandler() {
	try
	{
		//note that the element needs to exist for this to work
		var e = document.getElementById('content-header-right-left');
		e.onclick = function() {contentHeaderRightOnClick();}
	} catch(err)
	{
		errorHandler("HeaderRightEventHandler ",err);
	}
}
function titleEventHandler()
{
	try
	{
		var e = document.getElementById('help-title');
		e.onclick = function() {helpShow();}

		e = document.getElementById('login-title');
		e.onclick = function() {loginShow();}
	
		e = document.getElementById('comments-title');
		e.onclick = function() {commentsShow();}

		e = document.getElementById('rating-title');
		e.onclick = function() {showRatings();}
	
		e = document.getElementById('preference-title');
		e.onclick = function() {preferencesShow();}
	} catch(err)
	{
		errorHandler("titleEventHandler ",err);
	}
}
function tocEventHandler() 
{
	try
	{
		// table of contents events. mouse over, out and click.
		// note that the toc contains a number of nested elements
		// see comments in brianmacmillan.css for details.		
		var e = document.getElementById('table-of-contents');
		e.style.display="block"; //defaults to none for sake of users who do not have javascript running
		e.onclick = function() {tocOnClick();}

		var e = document.getElementById('table-of-contents-title');
 		e.onmouseover = function() {tocOnMouseOver();}
		e.onmouseout = function() {tocOnMouseOut();}
	} catch(err)
	{
		errorHandler("tocEventHandler ",err);
	}
}
function tocInnerEventHandler()
{
	try
	{
		var e = document.getElementById('table-of-contents-inner');
		/* 
  		 Note that the onMouseOut event is not used.
		 The inner element exists only to trap for the mouseover event
		 in the space between the header and the ul.
		*/
		e.onmouseover = function() {tocOnMouseOver();}
		e.onclick = function() {tocOnClick();}	
	} catch(err)
	{
		errorHandler("tocInnerEventHandler",err);
	}
}
function tocInnerUlEventHandler()
{
	var e = document.getElementById('table-of-contents-inner-ul');
	e.onmouseover = function() {tocOnMouseOver();}
	e.onmouseout = function() {tocOnMouseOut();}	
}

//These two functions could be replaced if loaded_three could be made to work with two parameters
function tocSubEventHandler(piIndex)
{
	tocSubEventHandler_Two("toc",piIndex);
}
function tocNavSubEventHandler(piIndex)
{
	tocSubEventHandler_Two("toc-nav",piIndex);
}
function tocSubEventHandler_Two(psPrefix,piIndex)
{
	try
	{
		//alert("In toc subevent handler" + piIndex);
		var elementName = psPrefix+piIndex;
		var e = document.getElementById(elementName);
		if (psPrefix=="toc-nav")
		{
				e.onmouseup = function() {showStory(piIndex)};
				e.onmouseover = function() {tocNavMouseOver("toc-img",piIndex)};		
				e.onmouseout = function() {tocNavMouseOut("toc-img",piIndex)};		
			} else
			{
				e.onmouseover = function() {showStory(piIndex)};
		}
		e.onclick = function() {tocClose()};
	} catch(err)
	{
		errorHandler("tocSubEventHandler_Two ",err);
	}
}
function tocNavMouseOver(psPrefix,piIndex)
{
	try
	{
		setBorder(psPrefix+piIndex,"solid","black","1px");		
				
	} catch(err)
	{
		errorHandler("Error in tocNavMouseOver",err);
	}
}
function tocNavMouseOut(psPrefix,piIndex)
{
	try
	{
		if (piIndex != giCurrentChapter)
		{
			setBorder(psPrefix+piIndex,"solid","#aaa","1px");
		} else
		{
			setBorder(psPrefix+piIndex,"solid",HIGHLIGHT_COLOR_CURRENT_CHAPTER,"1px");
		}			
	} catch(err)
	{
		errorHandler("Error in tocNavMouseout",err);
	}
}

// option events. mouse over, out and click.
// note that the options contains a number of nested elements
// see comments in brianmacmillan.css for details.
function optEventHandler() {
	try
	{
		//note that the element needs to exist for this to work
		var e = document.getElementById('options');
		e.style.display="none"; //defaults to none for sake of users who do not have javascript running
 		e.onmouseover = function() {optOnMouseOver();}
		e.onmouseout = function() {optOnMouseOut();}
		e.onclick = function() {optOnClick();}
		//e.innerHTML = "Table of Contents";
	} catch(err)
	{
		errorHandler("error in optEventHandler ",err);
	}
}
function optInnerEventHandler()
{
	try
	{
		var e = document.getElementById('options-inner');
		/* 
  		 Note that the onMouseOut event is not used.
		 The inner element exists only to trap for the mouseover event
		 in the space between the header and the ul.
		*/
		e.onmouseover = function() {optOnMouseOver();}
		e.onclick = function() {optOnClick();}	
	} catch(e)
	{
		alert(e.message);
	}
}
function optInnerUlEventHandler()
{
	var e = document.getElementById('options-inner-ul');
	e.onmouseover = function() {optOnMouseOver();}
	e.onmouseclick = function() {optOnMouseClick();}
	e.onmouseout = function() {optOnMouseOut();}	
}
function optSubEventHandler(piIndex)
{
	//alert(piIndex);
	var elementName = "opt"+piIndex;
	var e = document.getElementById(elementName);
	//e.onmouseclick = function() {showOption(piIndex)};
	//e.onclick = function() {optClose()};
	e.onclick = function() {executeOption(piIndex)};
}
function executeOption(piIndex)
{
	/* need to initialize opt element with command like: loaded_two('opt9',optSubEventHandler,0); */
	
 	if (piIndex==0)
	{
		preferencesHideShow();
	}
 	if (piIndex==1)
	{
		logout();
	}
 	if (piIndex==2)
	{
		alert("The copyright to this application and all content displayed therein is owned by Brian MacMillan. All rights reserved.");
	}
 	if (piIndex==3)
	{
		commentsHideShow();
	} 	
	if (piIndex==4)
	{
		footerHideShow();
	}
	if (piIndex==5)
	{
		// note that setColumnWidth changes the value of giCurrentColumnWidth
		if (giCurrentColWidth == WIDTH_NARROW)
		{
			setColumnWidth(WIDTH_WIDE);
		} else
		{
			setColumnWidth(WIDTH_NARROW);
		}

	}
	if (piIndex==6)
	{
		helpHideShow();
	}
	if (piIndex==7)
	{
		alert(piIndex);
	}
	if (piIndex==8)
	{
		alert(piIndex);
	}
	if (piIndex==9)
	{
		alert(piIndex);
	}
	if (piIndex==10)
	{
		drawPage("resize");
	}
	//close menu
	optClose();
}
function navSubEventHandler(piIndex)
{
	var elementName = "img"+piIndex;
	var e = document.getElementById(elementName);
	e.onclick = function() {execNav(piIndex)};
	e.onmouseover = function() {bigIcon(piIndex)};
	e.onmouseout = function() {navClose(piIndex)};
	
}
function navOnMouseOut(piIndex)
{
	try
	{
		navClose(piIndex);
	} catch(e)
	{
		alert(e.message);
	}
}
function navClose(piIndex)
{
	var e = document.getElementById("img"+piIndex);	
	e.style.height = "55%";
	e.style.width = "55%";
	e.style.marginTop = "0%";
	e.style.marginLeft = "0%";
	elementName = "nav"+piIndex;
	e = document.getElementById(elementName);	
	e.style.zIndex = giPreviousZIndex;
}
function bigIcon(piIndex)
{
	var e;
	try 
	{
			var e = document.getElementById("img"+piIndex);
			giPreviousZIndex = e.style.zIndex;
			e.style.width = "100%";
			e.style.height = "100%";
			e.style.marginTop = "-20%";
			e.style.marginLeft = "-25%";
			e = document.getElementById("nav"+piIndex);
			e.style.zIndex = NAV_ZINDEX_SHOW;
	}
	catch(err)
	{
		alert("",err);
	}
}
function execNav(piIndex)
{
	try
	{
		if (piIndex==0)
		{
			var sNewWidth;
			if (giCurrentColWidth == WIDTH_NARROW)
			{
				sNewWidth = WIDTH_WIDE;
			} 
			if (giCurrentColWidth == WIDTH_WIDE)
			{
				sNewWidth = WIDTH_NARROW;
			}
			setColumnWidth(sNewWidth);
		}
 		if (piIndex==1)
		{
			setColumnWidth();
		}
 		if (piIndex==2)
		{
			drawPage("resize");
		}
 		if (piIndex==3)
		{
			//alert("3");
			//alert("0 "+ eval(giTabList[0]) +" 1" + eval(giTabList[1]) + " 2" + eval(giTabList[2]) + " 3" + eval(giTabList[3]) +" 4" eval(giTabList[4]));
			alert(giTabList[0]);
			alert(giTabList[1]);
			alert(giTabList[2]);
			alert(giTabList[3]);
			alert(giTabList[4]);
		} 	
		if (piIndex==4)
		{
			alert("4");
		}
		if (piIndex==5)
		{
			alert("5");
		}
 		if (piIndex==6)
		{
			alert("6");
		}
 		if (piIndex==7)
		{
			alert("7");
		}
 		if (piIndex==8)
		{
			alert("8");
		} 		
		if (piIndex==9)
		{
			alert("9");
		}
	} catch (err)
	{
		errorHandler("execNav",err);
	}
}
function sidebarEventHandler() 
{
	//note that the element needs to exist for this to work
	var e = document.getElementById('sidebar-left');
	e.onmousedown = function(event) {mousedown();}
	e.onmouseup = function() {showColumnFormatingVars();}
}
function helpEventHandler()
{
	var e; 
	try
	{
		// moved to tabEventHandler;
		//e = document.getElementById('help');
		//e.onmouseover = function(event) {helpOnMouseOver("help");}
		//e.onmouseout = function(event) {helpOnMouseOut("help");}
		e = document.getElementById('help-next');
		e.onmouseover = function(event) {highlight("help-next","content-header-right-next");}
		e.onmouseout = function(event) {unhighlight("help-next","content-header-right-next");}
		e = document.getElementById('help-previous');
		e.onmouseover = function(event) {highlight("help-previous","content-header-right-previous");}
		e.onmouseout = function(event) {unhighlight("help-previous","content-header-right-previous");}
		
		e = document.getElementById('help-header');
		e.onmouseover = function(event) {highlight("help-header","content-header");}
		e.onmouseout = function(event) {unhighlight("help-header","content-header");}
		e = document.getElementById('help-content');
		e.onmouseover = function(event) {highlight("help-content","content-inner");}
		e.onmouseout = function(event) {unhighlight("help-content","content-inner",1);}

		//e = document.getElementById('help-gutter');
		//e.onmouseover = function(event) {highlight("help-gutter","gutter");}
		//e.onmouseout = function(event) {unhighlight("help-gutter","gutter",100);}
		
		e = document.getElementById('help-gutter-2');
		e.onmouseover = function(event) {highlight("help-gutter-2","gutter");}
		e.onmouseout = function(event) {unhighlight("help-gutter-2","gutter",100);}

		e = document.getElementById('help-gutter-3');
		e.onmouseover = function(event) {highlight("help-gutter-3","gutter");}
		e.onmouseout = function(event) {unhighlight("help-gutter-3","gutter",100);}

		//NB  bug that i've commented out for now bm.
		e = document.getElementById('help-tab');
		e.onmouseover = function(event) {highlight("help-tab","help");}
		e.onmouseout = function(event) {unhighlightHelp("help-tab","help");}
	
		e = document.getElementById('help-options');
		e.onmouseover = function(event) {highlight("help-options","options");}
		e.onmouseout = function(event) {unhighlight("help-options","options");}

		e = document.getElementById('help-header-2');
		e.onmouseover = function(event) {highlight("help-header-2","content-header");}
		e.onmouseout = function(event) {unhighlight("help-header-2","content-header",1);}
	
		//NB Needs to be turned into a function that can be called from Preferences
		if (giDefaultTOC == DEFAULT_TOC_MENU)
		{
			e = document.getElementById('help-table-of-contents');
			e.onmouseover = function(event) {highlight("help-table-of-contents","table-of-contents");}
			e.onmouseout = function(event) {unhighlight("help-table-of-contents","table-of-contents",100);}
			e = document.getElementById('help-table-of-contents-2');
			e.onmouseover = function(event) {highlight("help-table-of-contents-2","table-of-contents",300);}
			e.onmouseout = function(event) {unhighlight("help-table-of-contents-2","table-of-contents",300);}
		} 
		if (giDefaultTOC == DEFAULT_TOC_TOOLBAR)
		{
			e = document.getElementById('help-table-of-contents');
			e.onmouseover = function(event) {highlight("help-table-of-contents","table-of-contents-navbar");300}
			e.onmouseout = function(event) {unhighlight("help-table-of-contents","table-of-contents-navbar",101);}			
			e = document.getElementById('help-table-of-contents-2');
			e.onmouseover = function(event) {highlight("help-table-of-contents-2","table-of-contents-navbar",300);}
			e.onmouseout = function(event) {unhighlight("help-table-of-contents-2","table-of-contents-navbar",101);}
		}
	
		e = document.getElementById('help-navbar');
		e.onmouseover = function(event) {highlightNavbar("help-navbar",0,NAVBAR_COUNT,300);}
		e.onmouseout = function(event) {unhighlightNavbar("help-navbar",0,NAVBAR_COUNT,300);}
	
		e = document.getElementById('help-navbar2');
		e.onmouseover = function(event) {highlightNavbar("help-navbar2",0,NAVBAR_COUNT,300);}
		e.onmouseout = function(event) {unhighlightNavbar("help-navbar2",0,NAVBAR_COUNT,300);}
	
		e = document.getElementById('help-home');
		e.onmouseover = function(event) {highlightNavbar("help-home",NAVBAR_HOME,NAVBAR_HOME+1);}
		e.onmouseout = function(event) {unhighlightNavbar("help-home",NAVBAR_HOME,NAVBAR_HOME+1);}

		e = document.getElementById('help-writing');
		e.onmouseover = function(event) {highlightNavbar('help-writing',1,6);}
		e.onmouseout = function(event) {unhighlightNavbar('help-writing',1,6);}

		e = document.getElementById('help-photographs');
		e.onmouseover = function(event) {highlightNavbar('help-photographs',7,11);}
		e.onmouseout = function(event) {unhighlightNavbar('help-photographs',7,11);}
	
		document.getElementById('help-navigation-button').onmouseup = function(event) {helpShowSection(HELP_NAVIGATION);}	
		document.getElementById('help-overview-button').onmouseup = function(event) {helpShowSection(HELP_OVERVIEW);}
		document.getElementById('help-shortcuts-button').onmouseup = function(event) {helpShowSection(HELP_SHORTCUTS);}
	} catch(err)
	{
		errorHandler("Error in help event handler ",err);
	}
}
function preferencesShowSection(piSectionToDisplay)
{
	try
	{
		if (piSectionToDisplay == PREFERENCES_PERSONAL)
		{
			document.getElementById("preferences-personal-button").style.display="none";
			document.getElementById("preferences-interface-button").style.top = "70%";
			document.getElementById("preferences-interface-button").style.display="inline";
			document.getElementById("preferences-interface-button").style.left="55%";
			
			document.getElementById("preferences-change-password-button").style.top = "70%";
			document.getElementById("preferences-change-password-button").style.display="inline";
			document.getElementById("preferences-change-password-button").style.left="10%";

			document.getElementById("preferences-personal-section").style.display="block";
			document.getElementById("preferences-interface-section").style.display="none";
			document.getElementById("preferences-change-password-section").style.display="none";

		} 
		if (piSectionToDisplay == PREFERENCES_INTERFACE)
		{
			document.getElementById("preferences-interface-button").style.display="none";
			
			document.getElementById("preferences-personal-button").style.display="inline";
			document.getElementById("preferences-personal-button").style.top = "70%";
			document.getElementById("preferences-change-password-button").style.display="inline";
			document.getElementById("preferences-change-password-button").style.top = "70%";
			document.getElementById("preferences-change-password-button").style.left="55%";
						
			document.getElementById("preferences-interface-section").style.display="block";
			document.getElementById("preferences-personal-section").style.display="none";
			document.getElementById("preferences-change-password-section").style.display="none";
		}		
		if (piSectionToDisplay == PREFERENCES_UPDATE_PASSWORD)
		{
			document.getElementById("preferences-change-password-button").style.display="none";

			document.getElementById("preferences-personal-button").style.display="inline";
			document.getElementById("preferences-personal-button").style.top = "70%";
			document.getElementById("preferences-interface-button").style.display="inline";
			document.getElementById("preferences-interface-button").style.top = "70%";
			document.getElementById("preferences-interface-button").style.left="55%";			

			document.getElementById("preferences-interface-section").style.display="none";
			document.getElementById("preferences-personal-section").style.display="none";
			document.getElementById("preferences-change-password-section").style.display="block";
		}		
	} catch(err)
	{
		errorHandler("Error in preferencesShowSection",err);
	}
}
function helpShowSection(piSectionToDisplay)
{
	try
	{
		if (piSectionToDisplay == HELP_OVERVIEW)
		{
			document.getElementById("help-overview-button").style.display="none";
			document.getElementById("help-navigation-button").style.display="inline";
			document.getElementById("help-navigation-button").style.left = "10%";
			document.getElementById("help-navigation-button").style.top = "70%";
			document.getElementById("help-shortcuts-button").style.display="inline";	
			document.getElementById("help-shortcuts-button").style.left = "55%";
			document.getElementById("help-shortcuts-button").style.top = "70%";

			document.getElementById("help-overview-section").style.display="block";
			document.getElementById("help-navigation-section").style.display="none";
			document.getElementById("help-shortcuts-section").style.display="none";
		} 
		if (piSectionToDisplay == HELP_SHORTCUTS)
		{
			document.getElementById("help-overview-button").style.display="inline";
			document.getElementById("help-overview-button").style.left = "55%";
			document.getElementById("help-overview-button").style.top = "70%";
			document.getElementById("help-navigation-button").style.display="inline";
			document.getElementById("help-navigation-button").style.left="10%";
			document.getElementById("help-navigation-button").style.top="70%";
			document.getElementById("help-shortcuts-button").style.display="none";

			document.getElementById("help-overview-section").style.display="none";
			document.getElementById("help-navigation-section").style.display="none";
			document.getElementById("help-shortcuts-section").style.display="block";
		}		
		if (piSectionToDisplay == HELP_NAVIGATION)
		{
			document.getElementById("help-overview-button").style.display="inline";
			document.getElementById("help-overview-button").style.left="10%";
			document.getElementById("help-overview-button").style.top = "70%";
			document.getElementById("help-navigation-button").style.display="none";
			document.getElementById("help-shortcuts-button").style.display="inline";
			document.getElementById("help-shortcuts-button").style.left="55%";
			document.getElementById("help-shortcuts-button").style.top="70%";

			document.getElementById("help-overview-section").style.display="none";
			document.getElementById("help-navigation-section").style.display="block";
			document.getElementById("help-shortcuts-section").style.display="none";
		}		

	} catch(err)
	{
		errorHandler("Error in helpShowSection",err);
	}
}
function helpOnMouseOver()
{
	try
	{
		var e;
		e = document.getElementById("help");
		e.style.color = "black";
	} catch(err)
	{
		errorHandler("Error in helpMouseOver ",err);
	}
}
function helpOnMouseOut()
{
	var e;
	e = document.getElementById("help");
	e.style.color = "gray";	
}
function loginOnMouseOver()
{
	try
	{
		var e;
		e = document.getElementById("login");
		e.style.color = "black";
	} catch(err)
	{
		alert("Error in loginMouseOver "+err.message);
	}
}
function loginOnMouseOut()
{
	try
	{
		var e;
		e = document.getElementById("login");
		e.style.color = "gray";	
	} catch(err)
	{
		alert("Error in loginOnMouseOut "+err.message);
	}
}
function preferencesOnMouseOver()
{
	try
	{
		var e;
		e = document.getElementById("preferences");
		e.style.color = "black";
	} catch(err)
	{
		alert("Error in preferencesOnMouseOver "+err.message);
	}
}
function preferencesOnMouseOut()
{
	try
	{
		var e;
		e = document.getElementById("preferences");
		e.style.color = "gray";	
	} catch(err)
	{
		alert("Error in preferencesOnMouseOut "+err.message);
	}
}
function commentsOnMouseOver()
{
	try
	{
		var e;
		e = document.getElementById("comments");
		e.style.color = "black";
	} catch(err)
	{
		alert("Error in commentsOnMouseOver "+err.message);
	}
}
function commentsOnMouseOut()
{
	try
	{
		var e;
		e = document.getElementById("comments");
		e.style.color = "gray";	
	} catch(err)
	{
		alert("Error in commentsOnMouseOut "+err.message);
	}
}
function ratingOnMouseOver()
{
	try
	{
		var e;
		e = document.getElementById("ratings");
		e.style.color = "black";
	} catch(err)
	{
		alert("Error in ratingsOnMouseOver "+err.message);
	}
}
function ratingOnMouseOut()
{
	try
	{
		var e;
		e = document.getElementById("ratings");
		e.style.color = "gray";	
	} catch(err)
	{
		alert("Error in ratingsOnMouseOut "+err.message);
	}
}
function tabEventHandler()
{
	try
	{
		e = document.getElementById('help'); 
		e.onmouseover = function(event) {helpOnMouseOver("help");}
		e.onmouseout = function(event) {helpOnMouseOut("help");}
		e = document.getElementById('login');
		e.onmouseover = function(event) {loginOnMouseOver("login");}
		e.onmouseout = function(event) {loginOnMouseOut("login");}
		e = document.getElementById('preferences');
		e.onmouseover = function(event) {preferencesOnMouseOver("preferences");}
		e.onmouseout = function(event) {preferencesOnMouseOut("preferences");}
		e = document.getElementById('comments');
		e.onmouseover = function(event) {commentsOnMouseOver("comments");}
		e.onmouseout = function(event) {commentsOnMouseOut("comments");}
		e = document.getElementById('rating');
		e.onmouseover = function(event) {ratingOnMouseOver("rating");}
		e.onmouseout = function(event) {ratingOnMouseOut("rating");}
		e = document.getElementById('rating');
		e.onmouseover = function(event) {ratingOnMouseOver("rating");}
		e.onmouseout = function(event) {ratingOnMouseOut("rating");}		
	} catch(err)
	{
		errorHandler("tabEventHandler ",err);
	}
}
// stories are displayed within the content element
// note that content is a container for content inner, content text and column one/two
function contentEventHandler() {
	//note that the element needs to exist for this to work
	var e = document.getElementById('content');
	//e.onmouseup = function(event) {contentOnMouseUp(event);}

	e.onmouseover = function(event) {contentInnerOnMouseOver(event);}
	e.onmouseout = function(event) {contentInnerOnMouseOver(event)}
	e = document.getElementById('content-inner');
	e.onmouseover = function(event) {contentInnerOnMouseOver(event);}
	e.onmouseout = function(event) {contentInnerOnMouseOver(event)}
}
function contentInnerEventHandler() {
	//note that the element needs to exist for this to work
	var e = document.getElementById('content-inner');
	e.onmouseup = function(event) {contentInnerOnMouseUp(event);}
	e.onmousedown = function(event) {contentInnerOnMouseDown(event);} 
	e.ondrag = function(event) {contentInnerOnDrag(event);} 
}
function contentInnerOnDrag(event)
{
	//
	//alert("contentInnerOnDrag");
	//Test if current position different from previous position. if so redraw page appropriately.	
}
function contentInnerOnMouseDown(evt)
{
	try
	{
		giMouseX = getPageX(evt);
	} catch(err)
	{
		alert("Please excuse debugging message. Deployment in process.");
	}

	// trap current position for the sake of monitoring the drag direction of the mouse.
}
function contentInnerOnMouseUp(event)
{
	//alert("contentInnerOnMouseUp");
	//is current position different from previous position?
}
function getPageX(evt)
{
	if (window.getComputedStyle)
	{
		//alert("please excuse the debugging message. i am deploying now and this is a test.");
		return evt.pageX; 
	} else
	{
		evt = window.event;
		return evt.clientX + (document.documentElement.scrollLeft ?  document.documentElement.scrollLeft : document.body.scrollLeft); 
	}
}
function contentInnerOnMouseOver(event)
{
	gsPreviousCursorStyle = document.body.style.cursor;
	document.body.style.cursor = "default";	
}
function contentInnerOnMouseOut(event)
{
	document.body.style.cursor = gsPreviousCursorStyle;	
}
function gutterOnMouseUp(pEvent)
{
	//alert("gutter mouse up")

	try
	{
		// if right mouse button is depressed
		if (window.getComputedStyle)
		{
			if (pEvent.which == 3) {return}
		} else
		{
		
			if (window.event.button == 2) {return}
		}
		if (getShiftPressed(pEvent))
		{
			previousPage();
		} else
		{
			nextPage();			
		}
/*
		old way based on drag ... 
		var iPageX = getPageX(evt);
		var iResult = iPageX - giMouseX;


		if (Number(iResult)<= 0)
		{
			nextPage();
		} else if (Number(iResult)>1)
		{
			previousPage();
		}
		//alert("Content mouse up says move one page to the left " +giMouseX+" "+evt.pageX);		
		//alert("Content mouse up says move one page to the left " +iResult);
*/
	} catch(err)
	{
		//alert("Please excuse debugging message. Deployment in process.");
		errorHandler("gutterOnMouseUp",err);
	}
}

// NB Brian - to remove usernameEventHandler and passwordEventHandler

function usernameOnBlur()
{
	giCurrentEditMode = EDITING_USERNAME;
	var e;
	e = document.getElementById("username");
	if (e.value == "")
	{
		e.value = DEFAULT_USERNAME;
	}
}
function usernameOnFocus()
{
	try
	{
		giCurrentEditMode = EDITING_USERNAME;
		var e;
		e = document.getElementById("username");
		if (e.value == DEFAULT_USERNAME)
		{
			e.value = "";
		};
		e.select();
	} catch(err)
	{
		errorHandler("usernameOnFocus",err);
	}
}
function usernamePasswordEmailInit()
{
	var e;
	e = document.getElementById("username");
	e.value = DEFAULT_USERNAME; 
	e = document.getElementById("password");
	//e.value = DEFAULT_PASSWORD;
	e = document.getElementById("city");
	e.value = DEFAULT_CITY;
	e = document.getElementById("email");
	e.value = DEFAULT_EMAIL;
}
function passwordOnFocus()
{
	document.getElementById("password").select();
	giCurrentEditMode = EDITING_PASSWORD;
	var e = document.getElementById("password");
	if (e.value == DEFAULT_PASSWORD)
	{
		e.value = "";
	};
}
function passwordOnBlur()
{
	giCurrentEditMode = EDITING_NOTHING;
}
function commentsOnFocus()
{
	document.getElementById("your-comments").select();
	giCurrentEditMode = EDITING_COMMENTS;
}
function commentsOnBlur()
{
	giCurrentEditMode = EDITING_NOTHING;
}
function preferencesEventHandler()
{
	try
	{
		var sElementName="first-name";
		var e = document.getElementById('first-name');
		e.onfocus = function() {firstNameOnFocus();}
		e.onblur = function() {firstNameOnBlur();}
		e = document.getElementById('last-name');
		e.onfocus = function() {lastNameOnFocus();}
		e.onblur = function() {lastNameOnBlur();}
		e = document.getElementById('city');		
		e.onfocus = function() {cityOnFocus();}
		e.onblur = function() {cityOnBlur();}
		sElementName = "email";
		e = document.getElementById('email');
		e.onfocus = function() {emailOnFocus();}
		e.onblur = function() {emailOnBlur();}


		sElementName = "existing-password";
		e = document.getElementById('existing-password');
		e.onfocus = function() {existingPasswordOnFocus();}
		e.onblur = function() {existingPasswordOnBlur();}

		sElementName = "new-password";
		e = document.getElementById('new-password');
		e.onfocus = function() {newPasswordOnFocus();}
		e.onblur = function() {newPasswordOnBlur();}

		sElementName = "confirm-new-password";
		e = document.getElementById('confirm-new-password');
		e.onfocus = function() {confirmNewPasswordOnFocus();}
		e.onblur = function() {confirmNewPasswordOnBlur();}

		sElementName = "preferences-save-button";
		e = document.getElementById('preferences-save-button');
		e.onfocus = function() {preferencesSaveOnFocus();}
		e.onblur = function() {preferencesSaveOnBlur();}
		e.onmouseover = function() {preferencesSaveOnMouseOver();}		
		e.onmouseout = function() {preferencesSaveOnMouseOut();}
		e.mouseup = function() {preferencesUpdate();}

		sElementName = "preferences-update-password-button";
		e = document.getElementById('preferences-update-password-button');
		e.onfocus = function() {preferencesUpdatePasswordOnFocus();}
		e.onblur = function() {preferencesUpdatePasswordOnBlur();}
		e.onmouseover = function() {preferencesUpdatePasswordOnMouseOver();}		
		e.onmouseout = function() {preferencesUpdatePasswordOnMouseOut();}
		e.mouseup = function() {preferencesUpdatePassword();}


		document.getElementById('preferences-personal-button').onmouseup = function(event) {preferencesShowSection(PREFERENCES_PERSONAL);}	
		document.getElementById('preferences-interface-button').onmouseup = function(event) {preferencesShowSection(PREFERENCES_INTERFACE);}					
		document.getElementById('preferences-change-password-button').onmouseup = function(event) {preferencesShowSection(PREFERENCES_UPDATE_PASSWORD);}					

	} catch(err)
	{
		errorHandler("preferencesEventHandler "+sElementName,err);
	}
}
function usersUpdate()
{
	
}
function preferencesSaveOnFocus()
{
	var e = document.getElementById("preferences-save-button");
	e.borderColor = "red";
}
function preferencesSaveOnBlur()
{
	var e = document.getElementById("preferences-save-button");	
	e.color = "red";
}
function preferencesSaveOnMouseOut()
{
	var e = document.getElementById("preferences-save-button");
	e.color = "white";	
}
function preferencesSaveOnMouseOver()
{
	var e = document.getElementById("preferences-save-button");
	e.color = "red";	
	e.borderColor = "red";
}

function preferencesUpdatePasswordOnFocus()
{
	var e = document.getElementById("preferences-update-password-button");
	e.borderColor = "red";
	giCurrentEditMode = EDITING_PREFERENCES_UPDATE_PASSWORD_BUTTON;

}
function preferencesUpdatePasswordOnBlur()
{
	var e = document.getElementById("preferences-update-password-button");	
	e.color = "red";
	giCurrentEditMode = EDITING_NOTHING;
}
function preferencesUpdatePasswordOnMouseOut()
{
	var e = document.getElementById("preferences-update-password-button");
	e.color = "white";	
}
function preferencesUpdatePasswordOnMouseOver()
{
	var e = document.getElementById("preferences-update-password-button");
	e.color = "red";	
	e.borderColor = "red";
}
function firstNameOnBlur()
{
	giCurrentEditMode = EDITING_NOTHING;
}
function firstNameOnFocus()
{
	document.getElementById("first-name").select();
	giCurrentEditMode = EDITING_FIRST_NAME;
}	
function lastNameOnBlur()
{
	giCurrentEditMode = EDITING_NOTHING;
}
function lastNameOnFocus()
{
	document.getElementById("last-name").select();
	giCurrentEditMode = EDITING_LAST_NAME;
}
function emailOnBlur()
{
	giCurrentEditMode = EDITING_NOTHING;
}
function emailOnFocus()
{
	document.getElementById("email").select();
	giCurrentEditMode = EDITING_EMAIL;
	var e;
	e = document.getElementById("email");
	//alert("in email on Focus "+e.value);
	if (e.value == DEFAULT_EMAIL)
	{
		e.value = "";
	}
}
function cityOnBlur()
{
	giCurrentEditMode = EDITING_NOTHING;
}
function cityOnFocus()
{
	document.getElementById("city").select();
	giCurrentEditMode = EDITING_CITY;
	var e;
	e = document.getElementById("city");
	//alert("in email on Focus "+e.value);
	if (e.value == DEFAULT_CITY)
	{
		e.value = "";
	}
}
function cityOnBlur()
{
	giCurrentEditMode = EDITING_NOTHING;
}
function existingPasswordOnFocus()
{
	try
	{
		document.getElementById("existing-password").select();
		giCurrentEditMode = EDITING_EXISTING_PASSWORD;
	} catch(err)
	{
		errorHandler("existingPasswordOnFocus",err);
	}
}
function existingPasswordOnBlur()
{
	giCurrentEditMode = EDITING_NOTHING;
}
function newPasswordOnFocus()
{
	document.getElementById("new-password").select();
	giCurrentEditMode = EDITING_NEW_PASSWORD;
}
function newPasswordOnBlur()
{
	giCurrentEditMode = EDITING_NOTHING;
}
function confirmNewPasswordOnFocus()
{
	document.getElementById("confirm-new-password").select();
	giCurrentEditMode = EDITING_CONFIRM_NEW_PASSWORD;
}
function confirmNewPasswordOnBlur()
{
	// was a tab key hit?
	// if so go to save button
	giCurrentEditMode = EDITING_NOTHING;
	//if (getKeystroke(evt) == KEY_TAB)
	//{document.getElementById("preferences-save-button").focus();}

}

// Alternative code for trapping mouse events. Left as a reference
// To do: remove next two lines.
//function mouseX(evt) {if (!evt) evt = window.event; if (evt.pageX) return evt.pageX; else if (evt.clientX)return evt.clientX + (document.documentElement.scrollLeft ?  document.documentElement.scrollLeft : document.body.scrollLeft); else return 0;}
//function mouseY(evt) {if (!evt) evt = window.event; if (evt.pageY) return evt.pageY; else if (evt.clientY)return evt.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop); else return 0;}

function footerEventHandler() 
{
	var d = document.getElementById('footer');
	d.style.display="block";
	d.onmouseup = function() {show_node_info();}		
}
// set story loaded flag to true - story is now loaded
function storyEventHandler(piWhichStory) {
	giStoryLoaded[piWhichStory] = 1;
	//The idea here is to draw the first story after all six have been loaded.
	//probably not necessary, could replace with piWhichStory ==0
	if (piWhichStory == 5)
	{
		//alert("before drawpage");
		drawPage("load");
	}
}
/**********  functions triggered by element events ************/
// display full toc on mouse over.
function tocOnMouseOver()
{
	try
	{
		var element = document.getElementById('table-of-contents-inner');
		element.style.display="block";

		element = document.getElementById('table-of-contents');
		element.style.color = gsTOCHoverColor;
		element.style.backgroundColor="white";
		element.style.height= "10%";

		//var element = document.getElementById('table-of-contents-inner-ul');	
		//element.style.color="#300";	

	} catch(e)
	{
		alert(e.message);
	}
}
function tocOnMouseOut()
{
	try
	{
		tocClose();
	} catch(e)
	{
		alert(e.message);
	}
}
function tocClose()
{
	var element = document.getElementById('table-of-contents-inner');
	element.style.display="none";

	element = document.getElementById('table-of-contents');
	element.style.color=gsTOCColor;
	element.style.backgroundColor="white";
	element.style.height="3%";
}
function tocOnClick(evt)
{
	if (!window.getComputedStyle)
	{
	
		//showGlobals();
		//showColumnFormatingVars();
	}
}
/**********  functions triggered by element events ************/
// display full option menu on mouse over.
function optOnMouseOver()
{
	try
	{
		var element = document.getElementById('options-inner');
		element.style.display="block";

		element = document.getElementById('options');
		element.style.color = gsTOCHoverColor;
		element.style.backgroundColor="white";
		element.style.height= "10%";

		//var element = document.getElementById('table-of-contents-inner-ul');	
		//element.style.color="#300";	

	} catch(e)
	{
		alert(e.message);
	}
}
function optOnMouseOut()
{
	try
	{
		optClose();
	} catch(e)
	{
		alert(e.message);
	}
}
function optClose()
{
	var element = document.getElementById('options-inner');
	element.style.display="none";

	element = document.getElementById('options');
	element.style.color=gsTOCColor;
	element.style.backgroundColor="white";
	element.style.height="3%";
}
function optOnClick(evt)
{
	if (!window.getComputedStyle)
	{
	
		//showGlobals();
		//showColumnFormatingVars();
		// alert("just got clicked!");
	} else {
		// alert("else just got clicked");
	}
}
function contentHeaderLeftOnClick(evt)
{
	//showGlobals();
	showColumnFormatingVars();
}
function contentHeaderRightOnClick(evt)
{

	showGlobals();
	//showColumnFormatingVars();

}

/******************** END OF EVENT HANDLERS *****************/
/* 
 the loaded function tests to see if the element indicated by
 the first parameter has been loaded, and then attaches the event
 handling code indicated by the second argument.
*/

function loaded(i,f) 
{
	try
	{
		if (document.getElementById && document.getElementById(i) != null) f();
		else if (!giPageLoaded) setTimeout('loaded(\''+i+'\','+f+')',100);
	} catch(err)
	{
		errorHandler("loaded "+i,err);
	}
}
function loaded_two(i,f,piIndex) 
{
	try
	{
		if (document.getElementById && document.getElementById(i) != null) 
		{
			f(piIndex);
		} else if (!giPageLoaded) setTimeout('loaded_two(\''+i+'\','+f+','+piIndex+')',100);
	} catch(err)
	{
		errorHandler("loaded_two "+i,err);
	}
}
function loaded_three(e,f,piIndex,psType) 
{
	try
	{
		if (document.getElementById && document.getElementById(e) != null) 
		{
			f(psType,piIndex);
		} else if (!giPageLoaded) setTimeout('loaded_three(\''+i+'\','+f+','+piIndex+','+psType+')',100);
	} catch(err)
	{
		errorHandler("loaded_three "+e,err);
	}
}

loadEventHandlers()
function loadEventHandlers()
{
	try
	{
		// Initiate event handlers as screen elements are loaded.
		loaded('no-javascript',noJavascriptEventHandler);
		loaded('content-header-right-next',navigationEventHandler);
		loaded('table-of-contents',tocEventHandler);
		loaded('table-of-contents-inner',tocInnerEventHandler);

		loaded('table-of-contents-inner-ul',tocInnerUlEventHandler);
		
		loaded('options',optEventHandler);
		loaded('options-inner',optInnerEventHandler);
		loaded('options-inner-ul',optInnerUlEventHandler);
		
		loaded("comments",commentsEventHandler);
		
		//NB Brian Two subevent handlers are needed because i can't get loaded_three to work //
		loaded_two('toc0',tocSubEventHandler,0);
		loaded_two('toc1',tocSubEventHandler,1);
		loaded_two('toc2',tocSubEventHandler,2);
		loaded_two('toc3',tocSubEventHandler,3);
		loaded_two('toc4',tocSubEventHandler,4);
		loaded_two('toc5',tocSubEventHandler,5);
		loaded_two('toc6',tocSubEventHandler,6);
		loaded_two('toc-nav0',tocNavSubEventHandler,0);
		loaded_two('toc-nav1',tocNavSubEventHandler,1);
		loaded_two('toc-nav2',tocNavSubEventHandler,2);
		loaded_two('toc-nav3',tocNavSubEventHandler,3);
		loaded_two('toc-nav4',tocNavSubEventHandler,4);
		loaded_two('toc-nav5',tocNavSubEventHandler,5);

		loaded_two('preferences-personal-section',preferencesEventHandler,0);
		loaded_two('opt0',optSubEventHandler,0);
		loaded_two('opt1',optSubEventHandler,1);
		loaded_two('opt2',optSubEventHandler,2);
		loaded_two('opt3',optSubEventHandler,3);
		loaded_two('opt4',optSubEventHandler,4);
		loaded_two('opt5',optSubEventHandler,5);
		loaded_two('opt6',optSubEventHandler,6);
		loaded_two('opt7',optSubEventHandler,7);
		loaded_two('opt8',optSubEventHandler,8);
		loaded_two('opt9',optSubEventHandler,9);
		loaded_two('opt10',optSubEventHandler,10);
		loaded_two('opt11',optSubEventHandler,11);

		loaded('content',contentEventHandler);
		loaded('content-inner',contentInnerEventHandler);
		loaded('content-header-left-right',contentHeaderLeftEventHandler);
		loaded('content-header-right-left',contentHeaderRightEventHandler);

		loaded_two('story-loaded-c0',storyEventHandler,0);
		loaded_two('story-loaded-c1',storyEventHandler,1);
		loaded_two('story-loaded-c2',storyEventHandler,2);
		loaded_two('story-loaded-c3',storyEventHandler,3);
		loaded_two('story-loaded-c4',storyEventHandler,4);
		loaded_two('story-loaded-c5',storyEventHandler,5);
		//loaded_two('story-loaded-c6',storyEventHandler,6);

		loaded('login',loginEventHandler);
		loaded('tab-wide-narrow-img',tabWideNarrowEventHandler);
		loaded('navbar-hide-show-img',navbarHideShowButtonEventHandler);
		loaded("rating-title",titleEventHandler);

		loaded("help",helpEventHandler);
		loaded("tab",tabEventHandler);

		loaded('navbar-bottom',navigationEventHandler);
		loaded_two('nav0',navSubEventHandler,0);
		loaded_two('nav1',navSubEventHandler,1);
		loaded_two('nav2',navSubEventHandler,2);
		loaded_two('nav3',navSubEventHandler,3);
		loaded_two('nav4',navSubEventHandler,4);

		loaded_two('nav5',navSubEventHandler,5);
		loaded_two('nav6',navSubEventHandler,6);
		loaded_two('nav7',navSubEventHandler,7);
		loaded_two('nav8',navSubEventHandler,8);
		loaded_two('nav9',navSubEventHandler,9);
		loaded_two('nav10',navSubEventHandler,10);
	} catch(err)
	{
		errorHandler("LoadEventHandlers",err);
	}
}

window.onload = function() {
	try
	{
		giPageLoaded = 1;
		drawPage();
		helpShow();
		loginShow();
		setDefaults();
	} catch(err)
	{
		errorHandler("window.onload",err.message);
	}
}

window.onscroll = function(event){mouseScroll(event);}

// NodeCount equals the number of paragraphs in a story.

// To do: implement event
function contentDrag()
{
	alert("in content drag");
}

// debugging function
function showNodeInfo()
{
	try
	{
		//var element = document.getElementById("full-story");
		//alert(element.lastChild.nodeName);
		//var element = document.getElementsByClassName("quote");
		//var element = document.getElementById('full-story').getElementsByClassName('body-text');function text');(args) {
		var element = document.getElementById("eternal-suffering");
/*
		var i=0;
		for (i=0;i<iLimit;i++)
		{
			errorHandler(element.firstChild.id);
			i++;
		}
*/
	} catch(err)
	{
		errorHandler("Error in show_node_info: '",err);
	}
}
// drawPage() - (re)draw story content
// notice execution order
// 1. set globals
// 2. putTextIntoColumns
// 3. redraw
// 4. draw header
function drawPage(psEvent)
{
	try
	{		

		if (giStoryLoaded[giCurrentChapter]==0) {return}


		if ((giParaLimit[giCurrentChapter]==undefined) || (giParaLimit[giCurrentChapter]==0))
		{
			giCurrentPage[giCurrentChapter] = 0;
			giParaLimit[giCurrentChapter] = getNodeCount(gasChapterElement[giCurrentChapter],"body-text");
		}

		//To do: the code below should be unnecessary once the counting bug in getNodeCount is fixed.
		//The bug at present only occurs in firefox for Vista and IE7

		if ((giParaLimit[giCurrentChapter]==undefined) || (giParaLimit[giCurrentChapter]==0))
		{		
			//alert("IE debugging - for chapter "+giCurrentChapter);
			if (giCurrentChapter==0)
			{
				giParaLimit[giCurrentChapter]=127;
			}

			if (giCurrentChapter==1)
			{
				giParaLimit[giCurrentChapter]=43;
			}
			if (giCurrentChapter==2)
			{
				giParaLimit[giCurrentChapter]=118;
			}
		

			if (giCurrentChapter==3)
			{
				giParaLimit[giCurrentChapter]=139;
			}

			if (giCurrentChapter==4)
			{
				giParaLimit[giCurrentChapter]=67;
			}

			if (giCurrentChapter==5)
			{
				giParaLimit[giCurrentChapter]=79;
			}		
			if (giCurrentChapter==6)
			{
				giParaLimit[giCurrentChapter]=147;
			}

			if( window.getComputedStyle) 
			{
			} else 
			{
				//alert("Debugging internet explorer "+giParaLimit[giCurrentChapter]);
			}

		}

		setGlobals();



		if (giDebug == 1)
		{
			showGlobals();
		}

		if (window.getComputedStyle)
		{} else {
			//showGlobals();
		}

		putTextIntoColumns();


		// NB Brian - To do: redraw logic
		// 1. determine the first paragraph of the current page - gaiParaBreak[giCurrentPage]
		// 2. recalc all globals related to screen display by running - putTextIntoColumns and subs 
		// 3. change current page to ensure that it includes the first paragraph
		//    that was visible when the resize event occurred.  
		//giFirstParagraph = gaiParaBreak[giCurrentPage];
		giFirstParagraph[giCurrentChapter] = 0;
		if (psEvent=="resize")
		{
			giCurrentPage[giCurrentChapter] = getPageFromParagraph(giFirstParagraph[giCurrentChapter]);
		}
		// if this is a redraw event getCurrentPage from paragraph number
		// giCurrentPage = getPageFromParagraph(giFirstParagraph)
		redraw();
		drawContentHeader();
	} catch(err)
	{
		//errorHandler("Error in drawPage: '" + err.message+"'")
		errorHandler("Error in drawPage: '" ,err);
	}
}
function getPageFromParagraph(piWhichParagraph)
{
	//To do: loop through paraBreak until you find piWhichParagraph
	return giCurrentPage[giCurrentChapter];
}
function showStory(piChapter)
{
	showStoryTwo(piChapter);
	highlightCurrentChapterImage(piChapter);
}
function showStoryTwo(piChapter)
{
	try
	{
		//var element = document.getElementById(gasChapterElement[piChapter]);
		if (giCurrentChapter!=piChapter)
		{
			giCurrentChapter=piChapter;		
			var element = document.getElementById("title");
			element.text = "Brian MacMillan - " + gasChapterTitle[giCurrentChapter];

			drawPage("switch");
			commentsGet(giCurrentStory,giCurrentChapter);
		}
	} catch(err)
	{
		errorHandler("Error in showStory: '",err);
	}
}
function setGlobals()
{
	//To do: speed up by only resetting values resize events
	//To do - default view does not work in IE is there another option?
	//Also note that this code depends on the sId elements being visible!!!!

	var sPlaceholder ="";
	//var bIE = "0";

	var eColumnOne = document.getElementById("column-one");


	var eContent = document.getElementById("content-inner");

	if (!eColumnOne)
	{
		//alert("eColummOne not set in setGlobals");
	}

	var eTextResizeControl = document.getElementById("content-invisible-story");
	var styleColumn, styleCOntent, styleResize;
	if( window.getComputedStyle) 
	{
		styleColumn = document.defaultView.getComputedStyle(eColumnOne,sPlaceholder);
		styleContent =  document.defaultView.getComputedStyle(eContent,sPlaceholder);
		styleResize =  document.defaultView.getComputedStyle(eTextResizeControl,sPlaceholder);
	} else
	{
		styleContent = eContent.currentStyle;
		styleColumn = eColumnOne.currentStyle;
		styleResize =  eTextResizeControl.currentStyle;
	}
	gsBaseFontSize = styleColumn.fontSize;
	giFontSize = Number(gsBaseFontSize.substring(0,gsBaseFontSize.indexOf("px")));
	//styleResize =  
	//strip px from lineHeight property and place in giLineHeight variable
	var tempSize = styleColumn.lineHeight;
	giLineHeight = Number(tempSize.substring(0,tempSize.indexOf("px")));	
		
	var eaParagraph = new Array();
	var saParagraphStyle = new Array(); 

	try
	{
 		//gsOffsetHeight = styleResize.offsetHeight;
		if (window.getComputedStyle)
		{	
			gsColumnHeight = styleColumn.height;
			gsColumnWidth = styleColumn.width;

			gsContentHeight = styleContent.height;
			gsContentWidth = styleContent.width;

			gfContentHeight = gsContentHeight.substring(0,gsContentHeight.indexOf("px"));
			gfContentWidth = gsContentWidth.substring(0,gsContentWidth.indexOf("px"));
	
			/* if gsColumnHeight is a percentage */
			if (gsColumnHeight.indexOf("%")>0)
			{
				gfColumnHeight = (gfContentHeight * gsColumnHeight.substring(0,gsColumnHeight.indexOf("%"))/100);
			} else {
				gfColumnHeight = gsColumnHeight.substring(0,gsColumnHeight.indexOf("px"));
			}
		} else
		{
			gsColumnHeight = styleColumn.height;	
			gfColumnHeight = eColumnOne.clientHeight;
			gfContentHeight = eContent.clientHeight;
			gfContentWidth = eContent.clientWidth;
		}

		//alert("para limit"+giParaLimit[giCurrentChapter]);
		for (var i=0;i<=giParaLimit[giCurrentChapter];i++)

		{
			var sId = "c"+giCurrentChapter+"p"+i; 

			eaParagraph[i] = document.getElementById(sId);

			if (eaParagraph[i])
			{
				if( window.getComputedStyle) 
				{
					saParagraphStyle[i] = document.defaultView.getComputedStyle(eaParagraph[i],sPlaceholder);
				} else
				{
					saParagraphStyle[i] = eaParagraph[i].currentStyle;
				}
			} else
			{
				alert("Element "+sId +" not set.");
			}
			if (saParagraphStyle[i])
			{
				if (window.getComputedStyle)
				{
					gasParaHeight[i] = saParagraphStyle[i].height;
					//strip off the px
					gafParaHeight[i] = gasParaHeight[i].substring(0,gasParaHeight[i].indexOf("px"));
				} else
				{
					var iTemp = eaParagraph[i].offsetHeight; //clientHeight;
					gafParaHeight[i] = iTemp; 
					if (i==0)
					{
						//NB !! exception handling. for some reason first client height is off by 27 pixels.
						gafParaHeight[i] -= giFirstLineAdjustmentIE; 					}
				}
			} else
			{
				alert("saParagraphStyle not set");
			}
		}

		//Determine the interparagraph spacing which is the bottom margin of the paragraph element.
		var sTemp = saParagraphStyle[0].marginBottom;
		giParaSpacing = sTemp.substring(0,sTemp.indexOf("px"));	

	}
	catch(err)
	{
		errorHandler("Error in setGlobals",err);
	}
}
function putTextIntoColumns()
{
	//Step one: find out which paragraph should wrap.


	// global variables you need to understand in order to use this function:
	// giLineHeight - this is the line height for this font size in pixels for this browser.

	// gaiOverlapHeight the number of pixels overlap between col 1 and col2.

	// msg is used to aggregate system state information that i display when debug mode is on.
	var msg="Content Height "+gfContentHeight+String.fromCharCode(10); //debug messages

  try
  {
	var iCurPage = 0; //current column
	var iCurPara = 0; //current paragraph
	var iNewPage = 1; //flag to handle margins and overlaps at top of page.
	var iColumnFullIgnoreBottomParaPadding = 0;
	var bMultiPagePara = false; //exception handling for multi-page paragraphs

	if (giStoryLoaded==0) {return}

	// giLineHeight and giParaSpacing are set in setGlobals - read from css properties.
	//giLineHeight = 22;  //line height
	//giParaSpacing - bottom margin of paragraph. currently same as body font size but could be size of lineheight.

	gaiTopMargin[0] = 0;


	//alert(Number(giParaSpacing));

	// Loop through all of the nodes (p elements) in the story and display then in consecutive columns.
	for (iCurPara = 0;iCurPara<=giParaLimit[giCurrentChapter];iCurPara++)
	{
		//exception handling for first paragraph on first page 
		if (iCurPage==0 && iNewPage==1)
		{
			gafAggrParaHeight[0] = 0; //Number(gaiTopMarginAdjustment);		
			iNewPage = 0;	
		}
		//exception handling for top page margins for top of all pages except the first one
		if (iCurPage>0 && iNewPage==1)
		{
			gafAggrParaHeight[iCurPage]=0;
			
			gafAggrParaHeight[iCurPage] = Number(gaiTopMargin[iCurPage]);			
			gafAggrParaHeight[iCurPage] += Number(gafParaHeight[iCurPara-1]) + Number(giParaSpacing); //

			iNewPage = 0;	
		}

		gafAggrParaHeight[iCurPage] += Number(gafParaHeight[iCurPara]);  //height of current paragraph
		

		if (gafAggrParaHeight[iCurPage] <= gfContentHeight)  
		{
			
			if (gafAggrParaHeight[iCurPage]+Number(giParaSpacing) >= gfContentHeight)  
			{
				//exclude padding after paragraph.
				iColumnFullIgnoreBottomParaPadding=1;
			}
			else 
			{
				//padding after paragraph.
				gafAggrParaHeight[iCurPage] += Number(giParaSpacing); //aggregate plus padding after paragraph
			}
		}
		
		// Is column full of text? 
		// Note that the situation where column fits exactly requires exception handling.
		// In that situation we want to exclude the padding that follows our paragraph from our calculations.
		if ((gafAggrParaHeight[iCurPage] >= gfContentHeight) || (iColumnFullIgnoreBottomParaPadding==1))
		{
			//reset flag used above.
			iColumnFullIgnoreBottomParaPadding = 0;
			
			iCurPara = setMarginsAndBreaks(iCurPage,iCurPara);
			iCurPage++;
			//flag to handle top margin - see top of for loop
			iNewPage = 1;
			
			//Trap for situation where paragraph is more than one page long
			while (gaiOverlapHeight[iCurPage-1]>gfContentHeight)
			{
				gafAggrParaHeight[iCurPage]=gafParaHeight[iCurPara]-gaiNonOverlapHeight[iCurPage-1];
				//alert("gafAggrParaHeight[iCurPage] "+gafAggrParaHeight[iCurPage]+" page "+iCurPage+" para "+Number(iCurPara));
				iCurPara = setMarginsAndBreaks(iCurPage,iCurPara);
				iCurPage++;
			}

			
		}
	}	
	//Exception handling for partial last page. 
	if (gafAggrParaHeight[iCurPage]<gfContentHeight)
	{ 
		gaiParaBreak[iCurPage]=giParaLimit[giCurrentChapter];
	}
	
	giPageLimit[giCurrentChapter] = iCurPage;
  }
  catch(err)
  {
	errorHandler("putTextIntoColumns",err);
  }
}
function setMarginsAndBreaks(piCurPage,piCurPara)
{

	//determine the number of lines which overlap between this page and the next
	setColFormatingVars(piCurPage,piCurPara);
	
	//adjust for situation where overlap lines = 0 (paragraphs fit on current col with no overlap)
	if (gaiOverlapLines[piCurPage]==0)
	{
		piCurPara++;
	}

	
	//gaiParaBreak is the paragraph that starts the next column.
	//so if the first page ends on paragraph 3 exactly, 
	//the second page starts on paragraph 4 (gaiParaBreak[0]=4)  
	//if the first page ends part way through paragraph 4
	//the second page also starts on paragraph 4 and gaiParaBreak[0]=4
	gaiParaBreak[piCurPage]=piCurPara;
	

	//set margin of next page based on overlap from previous page.
	setTopMargin(piCurPage+1,piCurPara);

	return piCurPara;
	//msg+= "page "+Number(iCurPage-1)+" breaks on para "+ iCurPara+" height "+gafAggrParaHeight[iCurPage-1]+" "+" tm "+gaiTopMargin[iCurPage-1]+String.fromCharCode(10);

}
//redraw content based on current pagef number. Called by nextPage(), previousPage()
function redraw()
{
	try
	{
		removeAndAddNodes(giCurrentPage[giCurrentChapter],"column-one",0);
		//exception handling for situation where last page is
		//on the left hand column
		//the third argument, iRemoveFlag, is set to 1, 
		// this removes the text nodes in the second column but doesn't attempt to draw text.
		if (giCurrentPage[giCurrentChapter]+1 > giPageLimit[giCurrentChapter])
		{
			removeAndAddNodes(giCurrentPage[giCurrentChapter]+1,"column-two",1);
		}
		else
		{
			removeAndAddNodes(giCurrentPage[giCurrentChapter]+1,"column-two",0);		
		}
		setMasks(giCurrentPage[giCurrentChapter]);
		setMasks(giCurrentPage[giCurrentChapter]+1);
		drawMasks(giCurrentPage[giCurrentChapter]);
	}
	catch(err)
	{
		errorHandler("Error in setMasks: '"+err.message+"'");
	}
}

//Calculate the position of the masks which cover the partial line(s) at the bottom of 
//each column.
function setMasks(piPage)
{
	try
	{
		if ((piPage)<giPageLimit[giCurrentChapter])
		{
			if (window.getComputedStyle)
			{
				gaiColMaskTop[piPage]=(Number(gafAggrParaHeight[piPage]) - Number(gafParaHeight[gaiParaBreak[piPage]])) + Number(gaiNonOverlapHeight[piPage]);
			} else
			{
				gaiColMaskTop[piPage]=(Number(gafAggrParaHeight[piPage]) - Number(gafParaHeight[gaiParaBreak[piPage]])) + Number(gaiNonOverlapHeight[piPage]);
			}
			// NB - IE exception perhaps
			if (piPage == 0)
			{
				//gaiColMaskTop[piPage] + 16; // -= giFirstLineAdjustmentIE;
			}
		} else
		{
			gaiColMaskTop[piPage] = Number(gafAggrParaHeight[piPage])+1;
		}
		gaiColMaskHeight[piPage] = (gfContentHeight - gaiColMaskTop[piPage]);
	}
	catch(err)
	{
		errorHandler("Error in setMasks: '"+err.message+"'");
	}
}
function drawMasks(piPage)
{
	var iDebugAssist = 0;  // used to determine in which statement an IE bug occurs.
	try{
		var eColumnOneMask = document.getElementById("column-one-mask");
		var eColumnTwoMask = document.getElementById("column-two-mask");

		if (gaiOverlapLines[piPage]==0)
		{
			iDebugAssist = 1;
			eColumnOneMask.style.display="none";
		} else
		{
			eColumnOneMask.style.display="block";
			eColumnOneMask.style.top = gaiColMaskTop[piPage]+"px";
			eColumnOneMask.style.height= gaiColMaskHeight[piPage]+"px";
		}
		if (piPage<=giPageLimit[giCurrentChapter])
		{
			iDebugAssist = 10;

			if (gaiOverlapLines[piPage+1]==0)
			{
				iDebugAssist = 11;
				eColumnTwoMask.style.display="none";
			} else		
			{
				iDebugAssist = 12;
				eColumnTwoMask.style.display="block";
				//NB exception handling for IE7 bug where gaiColMaskTop/Height are evaluating to NaN
				//when there is no text on the right column of the final page.
				if (gaiColMaskTop[piPage+1]== Number.NaN)
				{
					iDebugAssist = 14;
					eColumnTwoMask.style.top = gfContentHeight;
				} else
				{
					iDebugAssist = 13;
					eColumnTwoMask.style.top = gaiColMaskTop[piPage+1]+"px";
				}
				if (gaiColMaskHeight[piPage+1]==Number.NaN)
				{
					iDebugAssist = 16;
					eColumnTwoMask.style.height = 0;
				} else
				{
					iDebugAssist = 15;
					eColumnTwoMask.style.height= gaiColMaskHeight[piPage+1]+"px";
				}
			}	
		} else
		{
			// mask = column height
			iDebugAssist = 100;
			eColumnTwoMask.style.display="block";
			eColumnTwoMask.style.top = gaiColMaskTop[piPage+1]+"px";
			eColumnTwoMask.style.height= gaiColMaskHeight[piPage+1]+"px";			
		}		
	}
	catch(err)
	{
		//errorHandler("Error in drawMasks: '"err+iDebugAssist+" "+gaiColMaskHeight[piPage+1],err);
	}
}
function drawContentHeader()
{
	// The header is divided into four containers 
	// upper left center left, upper right and center right.
	// These are referred to as left-left left-right right-left and right-right
	// To do: read header information directly from story file.	
	try
	{
		var e;
		document.getElementById("content-header-left-pagenumber").innerHTML =  Number(giCurrentPage[giCurrentChapter]+1);

		document.getElementById("content-header-left-right").innerHTML =  "   "+gasChapterTitle[giCurrentChapter]+" by Brian MacMillan";

		document.getElementById("content-header-right-left").innerHTML = "When We All Have Brains And Other Stories";		

		e = document.getElementById("content-header-right-pagenumber");
		if (giCurrentPage[giCurrentChapter]+2>giPageLimit[giCurrentChapter])
		{
			//element.innerHTML = "\u00A0"+"&nbsp;"+"&nbsp;"+" Fin";	//NB Trying to put a space in front nothing is working.	perhaps just switch the csvs at this point to text-indent: 1em.
			e.innerHTML = "Fin";	//NB Trying to put a space in front nothing is working.	perhaps just switch the csvs at this point to text-indent: 1em.
		} else
		{
			e.innerHTML = Number(giCurrentPage[giCurrentChapter]+2); //+" of "+Number(giPageLimit+1);
		}
		if (giCurrentPage < 10)
		{
			document.getElementById("content-header-left-next").style.marginRight="0px";
		}
		if (giCurrentPage >= 10 && giCurrentPage <99)
		{
			document.getElementById("content-header-left-next").style.marginRight="5px";
		}
		if (giCurrentPage > 99)
		{
			document.getElementById("content-header-left-next").style.marginRight="10px";
		}
	} catch(err)
	{
		errorHandler("drawContentHeader",err);
	}
	
}
function setTopMargin(piPage,piParagraph)
{
	// To understand this function you need to understand the architecture of this program.
	// Each content column can have overlap text at the top and the bottom that reflects the situation
	// where a paragraph breaks between columns. 
	// sTopMargin is a negative pixel value which pulls the top paragraph 
	// up to the point where only the lines spilling over from the previous page are visible.
	try
	  {
		//Set top margin for piPage - assumes this is second page or higher.
		//Note that the overlaplines from the previous column are being referenced!
		if (gaiNonOverlapLines[piPage-1] <= 0)
		{
			gaiTopMargin[piPage] = 0; //giParaSpacing+gaiTopMarginAdjustment;				

		}
		else if (gaiOverlapLines[piPage-1] == 0)
		{
			gaiTopMargin[piPage] = 0; //giParaSpacing;

		} else
		{
			gaiTopMargin[piPage] =  Number(-1 * (Number(gaiNonOverlapLines[piPage-1]) * Number(giLineHeight))); // + Number(giParaSpacing)+gaiTopMarginAdjustment;
			// To do: remove
			if(piParagraph==11)
			{
				//alert("1c "+gaiTopMargin[piPage]+" "+gaiNonOverlapLines[piPage-1]);
			}
		}
	
		//strip decimals - not necessary if gaiTopMargin has been rounded to zero decimals.
		if (gaiTopMargin[piPage].toString().indexOf(".")>0)
		{
			gasTopMargin[piPage] = gaiTopMargin[piPage].toString().substring(0,gaiTopMargin[piPage].toString().indexOf(".")) + "px"; 
		} else
		{
			gasTopMargin[piPage] = gaiTopMargin[piPage]+"px";
		}

	}
	catch(err)
	{
		errorHandler("Error in setTopMargin: '"+err.message+"'");
	}
// end of setTopMargin
}
function setColFormatingVars(piPage,piPara)
{
	// Remember that the current architecture assumes that breaking paragraphs are printed twice.
	// once at the bottom of the first column with overlap lines hidden and once at the top
	// of the second column with a negative top margin that causes the lines that have already
	// been printed to be clipped.
	// Having access to reliable font metrics will make this type of approach unnecessary.
	try
	{

		// populate second column ...
		gaiOverlapHeight[piPage] = (Number(gafAggrParaHeight[piPage])-Number(gfContentHeight));

		//number of lines in overlap paragraph ...
		gaiOverlapParaLines[piPage] = Number(gafParaHeight[piPara])/Number(giLineHeight); 	

		// ... of which iOverLapLines print on next column ...
		//there is a question as to whether to round or floor or neither. that's a margin/padding issue.
		//I have chosen to use ceil rather than Math.round()
		gaiOverlapLines[piPage] = Math.ceil(Number(gaiOverlapHeight[piPage])/giLineHeight);
		
		// and iNonOverLapLines print on current column
		gaiNonOverlapLines[piPage] = Number(gaiOverlapParaLines[piPage])-Number(gaiOverlapLines[piPage]);
	
		// need to mask partial lines. Mask starts 1 pixel below the bottom of the
		// last nonOverlapLine 

		gaiNonOverlapHeight[piPage] = gaiNonOverlapLines[piPage]*giLineHeight;


		//Handle exceptions where 
		// 1. only a partial line appears at the end of the column and is rounded to 0 lines.
		// 2. A paragraph is complete and there is less than the interparagraph space below it. 
		//    This creates the negative 1 value because of Math.ceil, above.
		if (gaiNonOverlapLines[piPage]==-1) {
			gaiOverlapLines[piPage]=0;
		}
	}
	catch(err)
	{
		errorHandler("Error in setColFormatingVars: '"+err.message+"'");
	}
}
function removeAndAddNodes(piPage,psElementId, piRemoveOnlyFlag)
{
	// removeAndAddNodes deletes the paragraphs currently being displayed and replaces them
	// with the nodes from the next or previous page. 
	// An alternate architecture involves drawing all columns up front and simply hiding and displaying.
	// This version is lighter and quite fast.	// Note: when the last page is on the left hand column
	// piRemoveOnlyFlag is set to 1 so that the right hand column is erased.
	try
	{
		//alert(psElementId);
		var eNewParagraph; 
		var eOldParagraph;
		var iFirstTime = 0;
		var eColumn = document.getElementById(psElementId);
		var iParaStart = 0;
		var iParaEnd = 0;
		var j; //counter

		//alert(psElementId);
		//remove child paragraph nodes from column, if they exist, before adding them
		/*
		if (!eColumn)
		{
			var parentElement = document.getElementById("content-text");
		    	eColumn = document.createElement("div");
			eColumn.setAttribute("id",psElementId);
			parentElement.appendChild(eColumn);

			if (!eColumn)
			{
				alert("error creating "+psElementId);
			}
		}
		*/
		if (eColumn.hasChildNodes() )
		{
		    while (eColumn.childNodes.length >= 1 )
		    {
		        eColumn.removeChild(eColumn.firstChild );       
		    } 
		}
		if (piPage>0)
		{
			iParaStart = gaiParaBreak[piPage-1];
		}
		j = iParaStart;

		if (piRemoveOnlyFlag==0)
		{
			for (j=iParaStart;j<=gaiParaBreak[piPage];j++)
			{ 	
				var tempVar = "c"+giCurrentChapter+"p"+j;
				eOldParagraph = document.getElementById(tempVar);
				eNewParagraph = document.createElement('p');
				eNewParagraph.setAttribute('class',eOldParagraph.className);

				eNewParagraph.setAttribute('className',eOldParagraph.className);

				if (iFirstTime == 0 )
				{
					eNewParagraph.style.marginTop = gasTopMargin[piPage];
					iFirstTime = 1;
				}
				eNewParagraph.innerHTML = eOldParagraph.innerHTML;
				eColumn.appendChild(eNewParagraph);
			/*
				http://support.microsoft.com/kb/948550
				treeDiv = srcDoc.createElement("DIV");
				treeDiv.id = "treeDiv";
				treeDiv.className = "treeDiv";
				treeDiv.style.pixelTop = 0;
				scrollDiv.appendChild(treeDiv);
				treeDiv.onresize = treeResize;
				treeDiv.innerHTML = loadTree(treeXML);
			*/

			}
		}
	}
	catch(err)
	{
		//NB Brian To do: there is a counter issue here related to column-two and the paragraph count.
		//The error results in a blank last page
 		if (err.message = "eOldParagraph is null")
		{
			//alert("This error is related to the unnecessarily blank last page.");
		} else
		{
			errorHandler("RemoveAndAddNodes",err);
		}
	}
}
//Debugging function typically called from a click event to an unused screen element
//In the current model, this is triggered by a click on sidebar left (when debugging is enabled)
function showColumnFormatingVars()
{
	var msg="";
	var i = giCurrentPage[giCurrentChapter]; //first column
	msg += "Current Chapter "+giCurrentChapter+ String.fromCharCode(10);
	msg += "Content height = " + gfContentHeight+ String.fromCharCode(10);

	msg +="Page count (zero based) "+Number(giPageLimit[giCurrentChapter])+ String.fromCharCode(10);
	msg +="Paragraph count (zero based) "+giParaLimit[giCurrentChapter]+ String.fromCharCode(10);
	msg +="Current page (zero based) "+giCurrentPage[giCurrentChapter]+ String.fromCharCode(10);
	
	msg += "" + String.fromCharCode(10);
	msg += "Overlap paragraph lines col 1 = " + gaiOverlapParaLines[i]  + String.fromCharCode(10);
	msg += "Overlap lines col 1 = " + gaiOverlapLines[i]  + String.fromCharCode(10);
	msg += "Non overlap lines col 1 = " + gaiNonOverlapLines[i]  + String.fromCharCode(10);
	msg += "Overlap pixels col 1 = " + gaiOverlapHeight[i]  + String.fromCharCode(10);
	msg += "Paragraph break col 1 " + gaiParaBreak[i]+ String.fromCharCode(10);
	msg += "" + String.fromCharCode(10);
	msg += "Aggregate para height col 1 " +gafAggrParaHeight[i] + String.fromCharCode(10);
	//msg += " + Top Margin col 1 " +gaiTopMargin[i] + String.fromCharCode(10);
	msg += " - Height of overlap paragraph col 1 "+ gafParaHeight[gaiParaBreak[i]]+ String.fromCharCode(10);
	msg += " + Partial height of last para col 1 " + gaiNonOverlapHeight[i] + String.fromCharCode(10);
	msg += " = Top of bottom mask col 1 " + gaiColMaskTop[i] + String.fromCharCode(10);

	//msg += "Overlap pixels col 1 = " + gaiOverlapHeight[0]  + String.fromCharCode(10);
	msg += "" + String.fromCharCode(10);

	msg += "Overlap paragraph lines col 2 = " + gaiOverlapParaLines[i+1]  + String.fromCharCode(10);
	msg += "Overlap lines col 2 = " + gaiOverlapLines[i+1]  + String.fromCharCode(10);
	msg += "Non overlap lines col 2 = " + gaiNonOverlapLines[i+1]  + String.fromCharCode(10);
	msg += "Overlap pixels col 2 = " + gaiOverlapHeight[i+1]  + String.fromCharCode(10);
	msg += "Paragraph break col 2 " + gaiParaBreak[i+1]+ String.fromCharCode(10);
	msg += "" + String.fromCharCode(10);

	msg += "Aggregate para height col 2 " +gafAggrParaHeight[i+1] + String.fromCharCode(10);
	//msg += " + Top Margin col 2 " +gaiTopMargin[i+1] + String.fromCharCode(10);
	if (i+1<giPageLimit[giCurrentChapter])
	{
		msg += " - Height of overlap paragraph col 2 "+ gafParaHeight[gaiParaBreak[i+1]]+ String.fromCharCode(10);
		msg += " + Partial height of last para col 2 " + gaiNonOverlapHeight[i+1] + String.fromCharCode(10);
	} else
	{
		msg += " - Plus one pixel "+ String.fromCharCode(10);
	}
	msg += " = Top of bottom mask col 2 " + gaiColMaskTop[i+1] + String.fromCharCode(10);
	msg += "" + String.fromCharCode(10);

	msg += "Height of mask col 1 " + gaiColMaskHeight[i]  + String.fromCharCode(10);
	msg += "Height of bottom mask col 2 " + gaiColMaskHeight[i+1]  + String.fromCharCode(10);


	msg += "" + String.fromCharCode(10);
	for (var k=128;k<=giParaLimit;k++)
	{
		msg += "Paragraph "+ k +", " +gafParaHeight[k]+"px "+(gafParaHeight[k]/giLineHeight)+" lines"+String.fromCharCode(10);				
	}
	// Uncomment to display the entire list of paragraph breaks.
/*
	for (var i=0;i<=(giPageLimit[giCurrentChapter]);i++)
	{
		msg+= "page "+Number(i)+" breaks on para "+ gaiParaBreak[i]+" "+" tm "+gaiTopMargin[i]+String.fromCharCode(10);
	}
*/
	alert(msg);
}
//second debug function
//see comments immediately above
function showGlobals()
{

	try
	{
		var iParagraphCount = 12;
	
		var msg = "\nThe base font size in pixels: " + giFontSize;
		msg +="\nThe line height is " + giLineHeight;
		msg +="\nInter-paragraph spacing is " + giParaSpacing;

		msg +="\nThe current page is " + giCurrentPage[giCurrentChapter];
		//msg += "\nThis page starts at paragraph " + giFirstParagraph +" line " + giFirstLineNextColumn;
		msg += "\nColumn Height string " + gsColumnHeight;
		msg += "\nColumn Height float " + gfColumnHeight;
		msg += "\nColumnWidth " + gsColumnWidth;

		msg += "\nContent Width " + gfContentWidth;
		msg += "\nContent Height " + gfContentHeight;

		iTemp = gaiParaBreak[giCurrentPage[giCurrentChapter]];
		for (var i=iTemp;i<(iParagraphCount+iTemp);i++)
		{
			msg += "\nParagraph Height p" + i + " " + gafParaHeight[i];
		}
		for (var i=iTemp;i<(iParagraphCount+iTemp);i++)
		{
			msg += "\nNumber of Lines  p" + i + " " + (gafParaHeight[i]/giLineHeight);		
			//msg += "\nNumber of Lines basefont p" + i + " " + (gafParaHeight[i]/giFontSize);		
		}
		alert(msg);	
	} catch(err)
	{
		errorHandler("",err);
	}
}
//Set page counter and then redraw
function nextPage()
{
	if (giCurrentPage[giCurrentChapter]<(giPageLimit[giCurrentChapter]-1))
	{
		giCurrentPage[giCurrentChapter]++;
		giCurrentPage[giCurrentChapter]++;
	} else
	{
		giCurrentPage[giCurrentChapter] = 0;
	}
	redraw();
	drawContentHeader();
}
//Set page counter and then redraw
function previousPage()
{
	var iModulus;
	if (giCurrentPage[giCurrentChapter]>1)
	{
		giCurrentPage[giCurrentChapter]--;
		giCurrentPage[giCurrentChapter]--;
	} else
	{
		iModulus = (giPageLimit[giCurrentChapter] % 2);
		if (iModulus==0) 
		{
			giCurrentPage[giCurrentChapter] = giPageLimit[giCurrentChapter];
		} else
		{
			giCurrentPage[giCurrentChapter] = giPageLimit[giCurrentChapter]-1;
		}
		
	}
	redraw();
	drawContentHeader();
}
function addElement(piParagraphId) {
	try
	{
	  var ni = document.getElementById('column-two');
	  var new_p = document.createElement('p');
	  new_p.innerHTML = "Test";
	  ni.appendChild(new_p);
	}
	catch(err)
	{
		errorHandler("",err);
	}
}
function removeElement(divNum) {
   //new_p.innerHTML = 'Element Number '+num+' has been added! <a href=\'#\' onclick=\'removeElement('+pIdName+')\'>Remove the div "'+pIdName+'"</a>';
  var d = document.getElementById('myDiv');
  var olddiv = document.getElementById(divNum);
  d.removeChild(olddiv);
}
//Trap for event where font size changes.
//Trickier function than you'd think because this event cannot be
//trapped at the DOM level because it is triggered by the browser.
//Uses textresizedetector.js which is a third party js with slightly
//different terminology than mine. 
function onFontResize(e,args) {
	//semantic difference between textresizedetector.js code and mine.
	//the resize detector refers to the css value line height as font size
	//var msg = "\nThe base font size in pixels: " + args[0].iBase;
	//msg +="\nThe current font size in pixels: " + args[0].iSize;
	//msg += "\nThe change in pixels from the last size:" + args[0].iDelta;
	try
	{
		// the key variables for resize calculations are 
		// giLineHeight and giFontSize and giParaSpacing
		// which map to the lineheight and the font size and margin of the text found in
		// the story nodes (p elements)
		// the resize detector currently just grabs changes in the lineheight
		// which it refers to as base font size (args[0].iSize)
		
		gsLineHeight = args[0].iSize;
		giLineHeight = Number(gsLineHeight);
		drawPage("resize");
	} catch(err)
	{ 
		errorHandler("onFontResize",err);
	}
}
// Initiate a complete redraw.
function windowResize()
{
	try
	{			
		setTimeout('drawPage("resize")',100);		

		//drawPage("resize");
	}
	catch(err)
	{
		errorHandler("error in windowResize ",err);
	}
}

function mouseScroll(event)
{
	//switch_page(event);
}
/* ******************************************************** */
// HIDE AND DISPLAY FOR TABS HIDE AND DISPLAY FOR TAB HIDE AND DISPLAY HIDE AND DISPLAY HIDE AND DISPLAY 
//Generic function to hide / display an element
function hide_show(elementName)
{
	e =  document.getElementById(elementName);
	try
	{
		if (e.style.display=="none")
		{
		 	e.style.display="block";
		} else 
		{
		 	e.style.display="none";	
		}
	}
	catch(err)
	{
	errorHandler("hide_show",err);
	}
}
function helpShow()
{
	try
	{
		tabsNormal();
		footerRightHideShow("none");
		var e =  document.getElementById("help");	
		e.style.zIndex = TAB_ZINDEX_SHOW;

		e.style.display = "block";
		e =  document.getElementById("help-title");	
		e.style.zIndex = TAB_ZINDEX_SHOW;
		e.style.display = "block";
		e.style.color = "black";

		addTabToList(TAB_HELP);

		//e.style.top = "8%";
		//e.style.left = "0%";

		e =  document.getElementById(OPT_HELP);
		e.innerHTML = "Hide help";
	} catch(err) 
	{
		errorHandler("helpShow",err);
	}
}
function footerRightHideShow(psValue)
{
	try
	{
		var e = document.getElementById("footer-right");
		e.style.display = psValue;
	
	} catch(err)
	{
		errorHandler("footerRightHideShow",err);
	}
}
function headerHideShow()
{
	e =  document.getElementById("header");
	if (e.style.display == null)
	{
		alert(e.style.display);
	}
	try
	{
		if (e.style.display=="none" )
		{
		 	e.style.display="block";
			e =  document.getElementById("body-main");
			e.style.top=gsBodyTopWithHeader;
			e.style.height=gsBodyHeightWithHeader;
			e =  document.getElementById("header-toggle");
			e.innerHTML="Hide header";
		} else 
		{
		 	e.style.display="none";	
			e =  document.getElementById("body-main");
			e.style.top=gsBodyTopWithoutHeader;
			e.style.height=gsBodyHeightWithoutHeader;
			e =  document.getElementById("header-toggle");
			e.innerHTML="Show header";
		}
	}
	catch(err)
	{
		errorHandler("headerHideShow",err);
	}
}
function preferencesShow()
{
	try
	{
		tabsNormal();

		var e =  document.getElementById("preferences");	
		e.style.zIndex = TAB_ZINDEX_SHOW;
		e.style.display = "block";

		e =  document.getElementById("preference-title");	
		e.style.zIndex = TAB_ZINDEX_SHOW;
		e.style.color = "black";
		e =  document.getElementById(OPT_PREF);
		e.innerHTML = "Hide preferences";
		addTabToList(TAB_PREFERENCES);
		//alert("end of show prefrences");
	} catch(err) 
	{
		errorHandler("preferencesShow ",err);
	}
}
function preferencesHide()
{
	tabsNormal();
	
	var e =  document.getElementById("preferences");
	if (e.style.display == null)
	{
		alert(e.style.display);
	}
	try
	{
	 	e.style.display="none";	
		e.style.zIndex = TAB_PREFERENCES;
		e =  document.getElementById(OPT_PREF);
		e.innerHTML = "Preferences";
		removeTabFromList(TAB_PREFERENCES);
	}
	catch(err)
	{
		errorHandler("preferencesHide",err);
	}
}
function commentsShow()
{
	try
	{
		tabsNormal();

		var e =  document.getElementById("comments");	
		e.style.zIndex = TAB_ZINDEX_SHOW;
		e.style.display = "block";

		e =  document.getElementById("comments-title");	
		e.style.zIndex = TAB_ZINDEX_SHOW;
		e.style.color = "black";
		e =  document.getElementById(OPT_COMMENT);
		e.innerHTML = "Hide comments";
		addTabToList(TAB_COMMENTS);
	} catch(err) 
	{
		errorHandler("commentsShow ",err);
	}
}
function commentsHide()
{
	var e =  document.getElementById("comments");	
	e.style.display = "none";
	e =  document.getElementById(OPT_COMMENT);
	e.innerHTML = "Comments";
	removeTabFromList(TAB_COMMENTS);
}
function commentsAdd()
{
	try
	{
		// NB Brian - this process is triggered off of the value of the add button
		if (document.getElementById("comments-add-button").value==COMMENTS_ADD_BUTTON)
		{
			commentsShowNewHideExisting();
		} else if (document.getElementById("comments-add-button").value==COMMENTS_SUBMIT_BUTTON)
		{
			var sCommentsText = document.getElementById("your-comments").value;
			if (sCommentsText.length>=MINIMUM_COMMENT_LENGTH)
			{
				commmentsInsert(sCommentsText);
			} else
			{
				alert("please enter at least "+MINIMUM_COMMENT_LENGTH+" characters.");
			}
		}		
	} catch(err)
	{
		errorHandler("comments Add",err);
	}
}
function commentsShowNewHideExisting()
{
	try
	{
		document.getElementById("your-comments").style.display="block";
		document.getElementById("comments-add-button").value=COMMENTS_SUBMIT_BUTTON;
		document.getElementById("your-comments").focus();		
	} catch(err)
	{
		errorHandler("commentsShowNewHideExisting",err);
	}
}
function commentsShowExistingHideNew()
{
	try
	{
		document.getElementById("your-comments").style.display="none";
		document.getElementById("comments-add-button").value=COMMENTS_ADD_BUTTON;
		//commentsGet(giCurrentStory,giCurrentChapter);	
		
	} catch(err)
	{ 
		errorHandler("CommentsShowExistingHideNew",err);
	}
}
function commentsRemoveAndAddNodes(pbRemoveOnlyFlag,psElementId,psCommentsArray)
{
	// commentsRemoveAndAddNodes deletes the paragraphs currently being displayed and replaces them
	// with the nodes from the next or previous page. 
	// An alternate architecture involves drawing all columns up front and simply hiding and displaying.
	// This version is lighter and quite fast.	// Note: when the last page is on the left hand column
	// piRemoveOnlyFlag is set to 1 so that the right hand column is erased.
	try
	{
		//alert(psElementId);
		//var eNewParagraph; 
		//var eOldParagraph;
		var bFirstTime=true;
		var eComment = document.getElementById(psElementId);
		var j; //counter


		if (eComment.hasChildNodes() )
		{
		    while (eComment.childNodes.length >= 1 )
		    {
		        eComment.removeChild(eComment.firstChild );       
		    } 
		}
		if (!pbRemoveOnlyFlag){return;}
		// When pbRemoveOnlyFlag is true, then the contents of the array aren't populated.
		//alert(psCommentsArray[2]+" "+psCommentsArray[3]+" "+psCommentsArray[4]+" "+psCommentsArray[5]+" "+psCommentsArray[6]+" "+psCommentsArray[7]);
		for (j=2;j<psCommentsArray.length-1;j++)
		{ 	
			//alert(psCommentsArray[j]+psCommentsArray[j+1]);
			var eNewComment = document.createElement("div");
			eNewComment.setAttribute('id',psCommentsArray[j]);//psCommentsArray[j]
			j++;
			eNewComment.setAttribute('class','comments-text');
			eNewComment.setAttribute('className','comments-text');
		
			if (bFirstTime)
			{
				//eNewParagraph.style.marginTop = gasTopMargin[piPage];
				bFirstTime = false;
			}
			j++;
			eNewComment.innerHTML = psCommentsArray[j];
			document.getElementById(psElementId).appendChild(eNewComment);
			j++;
			eNewComment = document.createElement("div");
			eNewComment.setAttribute('id','comments-user-key-'+j);//psCommentsArray[j]
			eNewComment.setAttribute('class','comments-invisible');
			eNewComment.setAttribute('class-name','comments-invisible');
			eNewComment.innerHTML = psCommentsArray[j];
			document.getElementById(psElementId).appendChild(eNewComment);			
			j++;
			eNewComment = document.createElement("div");
			eNewComment.setAttribute('id','comments-username'+j);//psCommentsArray[j]
			eNewComment.setAttribute('class','comments-username');
			eNewComment.setAttribute('class-name','comments-username');
			eNewComment.innerHTML = psCommentsArray[j];
			document.getElementById(psElementId).appendChild(eNewComment);
			j++;
			eNewComment = document.createElement("div");
			eNewComment.setAttribute('id','comments-city-'+j);//psCommentsArray[j]
			eNewComment.setAttribute('class','comments-city');
			eNewComment.setAttribute('classname','comments-city');
			eNewComment.innerHTML = psCommentsArray[j];
			document.getElementById(psElementId).appendChild(eNewComment);
			j++;
			eNewComment = document.createElement("div");
			eNewComment.setAttribute('id','comments-reply-to'+j);//psCommentsArray[j]
			eNewComment.setAttribute('class','comments-invisible');
			eNewComment.setAttribute('classname','comments-invisible');
			eNewComment.innerHTML = psCommentsArray[j];
			document.getElementById(psElementId).appendChild(eNewComment);
		/*
			http://support.microsoft.com/kb/948550
			treeDiv = srcDoc.createElement("DIV");
			treeDiv.id = "treeDiv";
			treeDiv.className = "treeDiv";
			treeDiv.style.pixelTop = 0;
			scrollDiv.appendChild(treeDiv);
			treeDiv.onresize = treeResize;
			treeDiv.innerHTML = loadTree(treeXML);
			*/
		}

	}
	catch(err)
	{
		errorHandler("commentsRemoveAndAddNodes",err);

	}
	document.getElementById("comments-title").style.display="block";
}
function footerHideShow()
{
	try
	{
		var e =  document.getElementById("footer");	
		if (e.style.display == "none")
		{
			footerShow();
		} else {
			footerHide();
		};
	} catch(err)
	{
		errorHandler("footerHideShow",err);
	}
}
function footerHide()
{
	try
	{
		var e =  document.getElementById("footer");	
		e.style.display = "none";
		e =  document.getElementById("navbar");	
		e.style.display = "none";
		e =  document.getElementById(OPT_FOOTER);
		e.innerHTML = "Show footer"

		e =  document.getElementById("content");	
		e.style.height = CONTENT_HEIGHT_NO_FOOTER; /* currently 92% */
		drawPage("resize");
	} catch(err)
	{
		errorHandler("footerHide",err);
	}
}
function footerShow()
{
	var e =  document.getElementById("footer");	
	e.style.display = "block";
	e =  document.getElementById("navbar");	
	e.style.display = "block";
	e =  document.getElementById(OPT_FOOTER);
	e.innerHTML = "Hide footer"

	e =  document.getElementById("content");	
	e.style.height = CONTENT_HEIGHT_WITH_FOOTER;  /* currently 84%, same as css */
	drawPage("resize");

}
function commentsHideShow()
{
	tabsNormal();
	//alert("in hide show comments");
	
	var e =  document.getElementById("comments");
	if (e.style.display == null)
	{
		//alert("display is null "+e.style.display);
	}
	try
	{
		if (e.style.display=="none" || e.style.display =="")
		{

		 	e.style.display="block";
			e =  document.getElementById(OPT_COMMENT);
			e.innerHTML = "Hide comments";
			e =  document.getElementById("comments");
			e.style.zIndex = TAB_ZINDEX_SHOW;

			e =  document.getElementById("comments-title");
			e.style.zIndex = TAB_ZINDEX_SHOW;
			
			addTabToList(TAB_COMMENTS);

		} else 
		{
			var f =  document.getElementById("comments-title");
			if (isThisTabVisible(TAB_COMMENTS) == 1)
			{
				commentsShow();
				return;
			}
		 	e.style.display="none";	
			e =  document.getElementById(OPT_COMMENT);
			e.innerHTML = "Comments";
			removeTabFromList(TAB_COMMENTS);
		}
	}
	catch(err)
	{
		errorHandler("",err);
	}
}
function preferencesHideShow()
{
	tabsNormal();
	
	var e =  document.getElementById("preferences");

	try
	{
		if (e.style.display=="none" || e.style.display=="" | e.style.display==null)
		{
		 	e.style.display="block";
			e.style.zIndex = TAB_ZINDEX_SHOW;

			e =  document.getElementById(OPT_PREF);
			e.innerHTML = "Hide preferences"
			e = document.getElementById("preference-title");
			e.style.zIndex = TAB_ZINDEX_SHOW;
			e.style.color = "black";
			addTabToList(TAB_PREFERENCES);

		} else 
		{
			var f =  document.getElementById("preference-title");
			if (isThisTabVisible(TAB_PREFERENCES) == 1)
			{
				preferencesShow();
				return;
			}
		 	e.style.display="none";	
			e.style.zIndex = TAB_PREFERENCES;
			e =  document.getElementById(OPT_PREF);
			e.innerHTML = "Preferences";
			removeTabFromList(TAB_PREFERENCES);
		}
	}
	catch(err)
	{
		errorHandler("preferencesHideShow",err);
	}
}
function helpHideShow()
{
	tabsNormal();
	
	var e =  document.getElementById("help");
	try
	{
		if (e.style.display=="" || e.style.display=="none")
		{
		 	e.style.display="block";
			e.style.zIndex = TAB_ZINDEX_SHOW;	

			e =  document.getElementById(OPT_HELP);
			e.innerHTML = "Hide help";
			e =  document.getElementById("help-title");	
			e.style.color = "black";
			e.style.display = "block";
			e.style.zIndex = TAB_ZINDEX_SHOW;		

			addTabToList(TAB_HELP);
			// NB Brian Not certain this is the best place for this handling of display.
			footerRightHideShow("none");
		} else 
		{
			var f =  document.getElementById("help-title");
			if (f.style.display=="block" || f.style.display=="inline")	
			{
				if (isThisTabVisible(TAB_HELP) == 1)
				{
					helpShow();
					return;
				}
			}		
		 	e.style.display="none";	
			e =  document.getElementById(OPT_HELP);
			e.innerHTML = "Help";
			removeTabFromList(TAB_HELP);
		}
	}
	catch(err)
	{
		errorHandler("Error in helpHideShow ",err);
	}	
}
function isThisTabVisible(piWhichTab)
{
	// Returns 0 if tab is not in list, 1 if it is, 2 if it is visible (defined as last item in giTabList not including nulls and blanks) 
	try
	{
		var iCount=0;
		for (var i=TAB_COUNT;i>=0;i--)
		{
			//alert("In isThisTabVisible - is this tab visible");
			if (giTabList[i]=="" || giTabList[i] == null)
			{
				//do nothing
			}
			else
			{
				//alert("in isThisTabVisible "+giTabList[i]+" "+piWhichTab);
				if (giTabList[i] == piWhichTab)
				{
					if (iCount==0)
					{
						return 2;
					}
					if (iCount>0)
					{
						return 1;
					}
					
				}
				//Test to see if its on top by using a counter
				iCount++
			}
		}
		return 0;
	} catch(err)
	{
		alert("Error in isThisVisible "+err.message);
	}
}
function loginHideShow()
{
	try
	{
		var e =  document.getElementById("login");
		if (e.style.display=="none" || e.style.display == null)
		{
			loginShow();
			/*
		 	e.style.display="block";
			e =  document.getElementById("options");
			e.style.display = "none";
			
			document.getElementById("login-submit-button").disabled = false;

			commentsHide();
			footerRightHideShow("block");
			addTabToList(TAB_LOGIN);
			*/
		} else 
		{
		 	e.style.display="none";	
			e =  document.getElementById("options");
			e.style.display = "block";
			// NB Brian to make based on user preferences
			commentsShow();
			footerRightHideShow("none");
			removeTabFromList(TAB_LOGIN);
		}
	}
	catch(err)
	{
		errorHandler("loginHideShow",err);
	}
}
function loginShow()
{
	try
	{
		// NB Brian It is not good there are two functions
		// loginHideShow and loginShow
		tabsNormal();
		//footerRightHideShow("block");
		document.getElementById("login-submit-button").disabled = false;
		var e =  document.getElementById("login");	
		e.style.zIndex = TAB_ZINDEX_SHOW;
		e.style.display = "block";

		e =  document.getElementById("login-title");	
		e.style.zIndex = TAB_ZINDEX_SHOW;
		e.style.color = "black";
		e.style.display = "block";

		e =  document.getElementById(OPT_LOGIN);
		e.innerHTML = "Logout";
		e.style.display = "none";

		addTabToList(TAB_LOGIN);

	} catch(err) 
	{
		alert("error in loginShow "+err.message);
	}
}
function loginShowError(psMessage)
{
	document.getElementById("login-error").innerHTML = psMessage;
	document.getElementById("why-login").style.display="none";
	document.getElementById("username").focus();
}
function loginHideError()
{
	try
	{
		var e;
		e = document.getElementById("login-error");
		e.innerHTML = "";
		e.style.display="none";
		e = document.getElementById("why-login");
		e.style.display="block";
		e = document.getElementById("why-login-text");
		e.style.display="block";		
	} catch(err) 
	{
		errorHandler("loginHideError",err);
	}
}
function validateUsername()
{
	var e;  // local element
	var s = ""; // local string
	var i = 0; // local integer
	try
	{
		e = document.getElementById("username");
		if (e.value == DEFAULT_USERNAME)
		{
			loginShowError("Please enter a username. It needs to be at least four characters long.");
			return false;
		}
		if (e.value.length <= 3)
		{
			loginShowError("Your username needs to be at least four characters long.");
			return false;
		} else
		{
			//alert("about to return 1 in validateUserName");
			return true;
		}
	} catch(err)
	{
		errorHandler("validateUsername",err);
	}	
}
function validatePassword()
{
	// NB Brian As of version 1.0 no password is required. This will change.
	var e;  // local element
	var s = ""; // local string
	var i = 0; // local integer
	try
	{
		e = document.getElementById("password");
		if (e.value==DEFAULT_PASSWORD)
		{
			e.value = ""; // a password should only be required if an email is recorded.
		}
		return true;
		/*
		// soon enough passwords will be required and this can get turned on
		if (e.value.length <= 3)
		{
			e = document.getElementById("login-error");
			e.value = "Your password needs to be at least four characters.";
			e = document.getElementById("why-login");
			e.style.display=="none";
			e = document.getElementById("why-login-text");
			e.style.display=="none";
			document.getElementById("password").focus();
			return 0;
		} else 
		{
			return 1;
		} 
		*/
	} catch(err)
	{
		errorHandler("validatePassword",err);
	}
}
function validateEmail()
{
	var e;  // local element
	var s = ""; // local string
	var i = 0; // local integer
	try
	{
		e = document.getElementById("email");
		s  =  e.value;
		//test for presence of @ sign and period ?@*.* 

		if (s.length > 3)
		{
			return true;
		} else
		{
			return false;
		}
	} catch(err)
	{
		errorHandler("validateEmail",err);
	}
}
/************ FUNCTIONS WHICH INVOLVE DATABASE COMMUNICATION ***************/
function login()
{
	try
	{
		if (gbLoginInProcess)
		{
			//alert("double login");  // should never happen
			//return;
		}
		document.getElementById("login-submit-button").disabled = true;
		gbLoginInProcess = true;	
		if (validateUsername() && validatePassword())
		{
			var e =  document.getElementById("login");

			var sPassword =  escape(document.getElementById("password").value);
			var sUsername =  escape(document.getElementById("username").value);

			var sParams = "?login_name="+escape(sUsername);
			sParams += "&password="+escape(sPassword);
			sParams += "&new_user="+document.getElementById("checkbox-new-user").checked;

			//alert(LOGIN_URL+sParams);
			httpRequest.open("GET", LOGIN_URL+sParams, true);
			httpRequest.onreadystatechange = loginHttpResponse;
			httpRequest.send(null)	

		} else
		{
			loginShowError("Invalid username");
			document.getElementById("login-submit-button").disabled=false;
			gbLoginInProcess = false;
			return false;
		}
	}
	catch(err)
	{
		errorHandler("login",err);
		gbLoginInProcess = false;
	}
}
function logout()
{
	//alert("in logout");
	var e =  document.getElementById("login");

	try
	{

		e.style.display = "block";
		e.style.zIndex = TAB_ZINDEX_SHOW;
		e =  document.getElementById(OPT_LOGIN);
		e.style.display = "none";
		e.style.display = "inline";
		helpShow();
		loginShow();
		commentsHide();
		preferencesHide();
		gbLoggedIn = false;
		footerRightHideShow(1);
	} catch(err) 
	{
		errorHandler("logout",err);
	}
}
function loginHttpResponse() 
{
	try
	{
		/*
		Response message:
			Error number integer
			Error message string
			User_key integer - the primary key to the user table
		*/
		var sResults = httpRequest.responseText;
		var sResultsArray;
		var e;
		if (httpRequest.readyState == 4) 
		{
			sResultsArray = sResults.split(",");
			//alert("sResults are "+sResults);
			if (sResultsArray[0] == LOGIN_SUCCESS)
			{
				gbLoggedIn = true;

				//alert("Your user key is "+giCurrentUserKey);
				setPreferences(sResultsArray);
				// if login successful then do the following.
				loginHideShow();
				giCurrentEditMode = EDITING_NOTHING;
				e =  document.getElementById("options");
				e.style.display = "block";
				e =  document.getElementById(OPT_LOGIN);
				e.style.innerHTML = "Logout";
				e.style.display = "inline";
				loginHideError();
				footerRightHideShow("none");
				preferencesShow();
				commentsShowExistingHideNew();
				commentsGet(giCurrentStory,giCurrentChapter);
				commentsShow();
				helpShow();
				removeTabFromList(TAB_LOGIN);
				gbLoginInProcess = false;
			} else
			{
				//NB Brian display error
				//loginShowError(sResultsArray[1]);
				//This substring nonsense is related to a trailing 0 which is mysteriously 
				//appearing in the error message element. I wonder if that is 
				//because I'm sending the message to innerHTML.
				if (sResults=="")
				{
					alert("Error in loginHttpResponse "+sResults);
				} else
				{
					
					loginShowError(sResultsArray[1].substr(0,(sResultsArray[1].length-1)));
				}
				gbLoggedIn = false;
				document.getElementById("login-submit-button").disabled = false;
			}
	  	} else
		{
			// NB Brian Is there a need to handle other ready states?
			//alert("ready state = "+http.readyState)
		}
	} catch(err)
	{
		errorHandler("loginHttpResponse",err);
	}
	gbLoginInProcess = false;
}
function logEvent(piWhichEvent)
{
	try
	{
		var sParams = "?event="+piWhichEvent+"&user_key="+giCurrentUserKey+"&login_name="+document.getElementById("username");
		httpRequest.open("GET", LOGEVENT_URL+sParams, true);
		httpRequest.onreadystatechange = logEventHttpResponse;
		httpRequest.send(null)	
	} catch(err)
	{
		errorHandler("logEvent",err);
		gbLoginInProcess = false;
	}
}
function logEventHttpResponse()
{
	try
	{
		var sResults = httpRequest.responseText;
		var e;
		if (httpRequest.readyState == 4) 
		{
			//alert("LOG EVENT RESULTS "+sResults);
		}
	} catch(err)
	{
		errorHandler("logEventHttpResponse",err);
	}
}
function preferencesUpdate()
{
	try
	{
		var sEmail = document.getElementById("email").value;
		if (sEmail == DEFAULT_EMAIL)
		{
			sEmail="defaultEmail@email.com";
		}
		var sCity = document.getElementById("city").value;
		var sUserName = document.getElementById("username").value;
		var sPassword = document.getElementById("new-password").value;
		var sFirstName = "";
		var sLastName = "";

		
		//alert("user key "+giCurrentUserKey);
		var sParams = "?login_name="+escape(sUserName)+"&user_key="+giCurrentUserKey+"&login_name="+sUserName;
		sParams += "&show_navigation_arrows="+booleanToInteger(document.getElementById("show-navigation-arrows").checked);
		sParams += "&wide_text_columns="+booleanToInteger(document.getElementById("wide-text-columns").checked);
		sParams += "&show_footer="+booleanToInteger(document.getElementById("show-footer").checked);
		sParams += "&show_help="+booleanToInteger(document.getElementById("show-help").checked);
		sParams += "&show_comments="+booleanToInteger(document.getElementById("show-comments").checked);
		sParams += "&show_preferences="+booleanToInteger(document.getElementById("show-preferences").checked);
		sParams += "&show_ratings="+booleanToInteger(document.getElementById("show-ratings").checked);
		sParams += "&show_editor="+booleanToInteger(document.getElementById("show-editor").checked);

		//alert(PREFERENCES_UPDATE_URL+sParams);
		httpRequest.open("GET", PREFERENCES_UPDATE_URL+sParams, true);
		httpRequest.onreadystatechange = preferencesUpdateHttpResponse;
		httpRequest.send(null);	
	} catch(err)
	{
		errorHandler("preferencesUpdate",err);
		gbLoginInProcess = false;
	}
}

function preferencesUpdatePassword()
{
	try
	{
		//alert("need to add preferences updarte code here");
		var sReturn = validateNewPassword();
		//sReturn = ""; // fakeout  NB BRIAN Begin here 
		if (sReturn=="")
		{
			sPassword=document.getElementById("confirm-new-password").value;
		} else
		{
			alert(sReturn);
			document.getElementById("new-password").focus();
			return;
		}
		//alert("here");
		var sEmail = document.getElementById("email").value;
		if (sEmail == DEFAULT_EMAIL)
		{
			sEmail="";
		}
		var sCity = document.getElementById("city").value;
		var sUserName = document.getElementById("username").value;
		var sFirstName = document.getElementById("first-name").value;
		var sLastName = document.getElementById("last-name").value;
		//alert("user key "+giCurrentUserKey);
		var sParams = "?login_name="+escape(sUserName)+"&user_key="+giCurrentUserKey+"&email="+sEmail+"&city="+escape(sCity)+"&first_name="+escape(sFirstName)+"&last_name="+escape(sLastName)+"&password="+escape(sPassword);
		//alert(USERS_UPDATE_URL+sParams);
		httpRequest.open("GET",USERS_UPDATE_URL+sParams, true);
		//httpRequest.open("GET",CHANGE_PASSWORD_URL+sParams, true);
		httpRequest.onreadystatechange = usersUpdateHttpResponse;
		httpRequest.send(null);	
	} catch(err)
	{
		errorHandler("preferencesUpdate",err);
		gbLoginInProcess = false;
	}	


}
function validatePassword()
{
	return true;
}
function validateNewPassword()
{
	var sReturn = "";
	if (document.getElementById("new-password").value==document.getElementById("confirm-new-password").value)
	{
		// do nothing
	} else
	{
		// raise error
		sReturn = "Password confirmation failure. New password is different from old password.";
	}
	return sReturn;
}
function usersUpdate()
{
	try
	{
		var sEmail = document.getElementById("email").value;
		if (sEmail == DEFAULT_EMAIL)
		{
			sEmail="";
		}
		var sCity = document.getElementById("city").value;
		var sUserName = document.getElementById("username").value;
		var sPassword = document.getElementById("password").value;
		var sFirstName = document.getElementById("first-name").value;
		var sLastName = document.getElementById("last-name").value;
		//alert("user key "+giCurrentUserKey);
		var sParams = "?login_name="+escape(sUserName)+"&user_key="+giCurrentUserKey+"&email="+sEmail+"&city="+escape(sCity)+"&first_name="+escape(sFirstName)+"&last_name="+escape(sLastName)+"&password="+escape(sPassword);
		//alert(USERS_UPDATE_URL+sParams);
		httpRequest.open("GET", USERS_UPDATE_URL+sParams, true);
		httpRequest.onreadystatechange = usersUpdateHttpResponse;
		httpRequest.send(null);	
	} catch(err)
	{
		errorHandler("preferencesUpdate",err);
		gbLoginInProcess = false;
	}	
}
function preferencesUpdateHttpResponse()
{
	try
	{
		var sResults = httpRequest.responseText;
		var sResultsArray;
		var e;
		if (httpRequest.readyState == 4) 
		{
			//alert(sResults);
			sResultsArray = sResults.split(",");
			if (sResultsArray[0] == SUCCESS)
			{
				//alert("preferences update success");
			} else
			{
				alert("preferences update failure");
			}
		}		
	} catch(err)
	{
		errorHandler("commentsInsertHttpResponse",err);
	}
}
function usersUpdateHttpResponse()
{
	try
	{
		var sResults = httpRequest.responseText;
		var sResultsArray;
		var e;
		if (httpRequest.readyState == 4) 
		{
			//alert(sResults);
			sResultsArray = sResults.split(",");
			if (sResultsArray[0] == SUCCESS)
			{
				alert("Your changes have been recorded.");
			} else
			{
				alert("users update failure");
			}
		}		
	} catch(err)
	{
		errorHandler("commentsInsertHttpResponse",err);
	}
}

function commmentsInsert(psComments)
{
	try
	{
		var sParams = "?login_name="+escape(document.getElementById("username").value)+"&user_key="+giCurrentUserKey+"&comments="+escape(psComments)+"&story_id="+giCurrentStory+"&chapter_id="+giCurrentChapter;
		httpRequest.open("GET", COMMENTS_INSERT_URL+sParams, true);
		httpRequest.onreadystatechange = commentsInsertHttpResponse;
		httpRequest.send(null);	
	} catch(err)
	{
		errorHandler("commentsInsert",err);
		gbLoginInProcess = false;
	}
}
function commentsInsertHttpResponse()
{
	try
	{
		var sResults = httpRequest.responseText;
		var sResultsArray;
		var e;
		if (httpRequest.readyState == 4) 
		{
			sResultsArray = sResults.split(",");
			if (sResultsArray[0] == SUCCESS)
			{
				commentsGet(giCurrentStory,giCurrentChapter);
				commentsShowExistingHideNew();
			} else
			{
				//alert("No comments were returned");
			}
		}		
	} catch(err)
	{
		errorHandler("commentsInsertHttpResponse",err);
	}
}
function commentsGet(piCurrentStory,piCurrentChapter)
{
	try
	{
		//alert("in comments get");
		var sParams = "?login_name="+escape(document.getElementById("username").value)+"&user_key="+giCurrentUserKey+"&story_id="+piCurrentStory+"&chapter_id="+piCurrentChapter;

		httpRequest.open("GET", COMMENTS_GET_URL+sParams, true);
		httpRequest.onreadystatechange = commentsGetHttpResponse;
		httpRequest.send(null);	
	} catch(err)
	{
		errorHandler("commentsGet",err);
	}
}
function commentsGetHttpResponse()
{
	try
	{
		var sResults = httpRequest.responseText;
		var sResultsArray;
		var e;
		if (httpRequest.readyState == 4) 
		{
			sResultsArray = sResults.split(",");
			if (sResultsArray[0] == SUCCESS)
			{
				// Return message structure
				// It'd be nice to get either an associative array, or something already structured for html.
				// I'm not certain an associative array can be passed from php to javascript
				/*
				row-id (programatically generated for purposes of formating)
				evenOdd,
				C.comments,
				A.user_key, 
				A.login_name,
				A.city,
				C.reply_to,
				*/
				//alert("commentsGetHttpResponse: The number of elements returned is "+sResultsArray.length+" -"+sResults);
				commentsRemoveAndAddNodes(true,"comments-root",sResultsArray);
				//commentsShowExistingHideNew();
			} else
			{
				commentsRemoveAndAddNodes(false,"comments-root",sResultsArray);
			}
		}
	} catch(err)
	{
		errorHandler("commentsGetHttpResponse",err);
	}
}
/********* UTILITY FUNCTIONS ****************/
function errorHandler(psFunctionName,err)
{
	if (DEFAULT_SHOW_ERRORS == 1)
	{
		alert("Error in "+psFunctionName+" "+err.message);
	} else
	{
		//NB Brian to do - log errors
	}
}
function integerToBoolean(piValue)
{
	if (piValue == 1)
	{
		return true;
	} else
	{
		return false;
	}
	
}
function booleanToInteger(pbValue)
{
	if (pbValue)
	{
		return 1;
	} else
	{
		return 0;
	}
	
}
function getKeystroke(evt)
{
	var key;
	// determine which key was just pressed
	// IE and non-ie code.
	try
	{
		key = (evt.which) ? evt.which : evt.keyCode;
	} catch(err)
	{
		// ie7 and perhaps other versions
		key = document.event.keyCode;	
	}
	return key;
}
function getShiftPressed(evt)
{
	try
	{
		return (evt.shiftKey==1);
	} catch(err)
	{
		// ie7 and perhaps other versions
		return (document.event.shiftKey==1);	
	}
}
function getCtrlPressed(evt)
{
	try
	{
		return (evt.ctrlKey==1);
	} catch(err)
	{
		// ie7 and perhaps other versions
		errorHandler("getCtrlPressed",err);
		return (document.event.ctrlKey==1);	
	}
}
function getAltPressed(evt)
{
	
}
function highlight(psElementId, psElementId2)
{
	var e; 	
	e = document.getElementById(psElementId);
	e.style.backgroundColor="yellow";
	e = document.getElementById(psElementId2);
	e.style.zIndex = "500";
	e.style.borderStyle="solid";
	e.style.borderColor="red"; // should be a preference
	e.style.borderWidth="1px";

}
function unhighlight(psElementId, psElementId2,piZindex)
{
	var e; 
	if (piZindex == "" || piZindex == null)
	{
		piZindex == "100";
	}	
	e = document.getElementById(psElementId);
	e.style.backgroundColor="white";
	e = document.getElementById(psElementId2);
	e.style.zIndex = piZindex;
	e.style.borderWidth="0px";
}
function unhighlightHelp(psElementId, psElementId2,piZindex)
{
	//NB Brian - Exception handling for the help mouseover highlight process. 
	//does almost exactly the same thing as unhighlight
	var e; 
	if (piZindex == "" || piZindex == null)
	{
		piZindex == "100";
	}	
	e = document.getElementById(psElementId);
	e.style.backgroundColor="white";
	e = document.getElementById(psElementId2);
	e.style.zIndex = piZindex;
	e.style.borderColor="gray";
	e.style.borderWidth="1px";
}
function highlightNavbar(psHelpElement,piStart,piEnd,piZindex)
{
	var e;
	var sTemp
	try
	{
		if (piZindex == null || piZindex == "")
		{
			piZindex = "100";
		}
		e = document.getElementById(psHelpElement);
		e.style.backgroundColor="yellow";
		for (i=piStart;i<piEnd;i++)
		{
			sTemp = "img"+i;
			e = document.getElementById(sTemp);
			e.style.borderStyle="solid";
			e.style.borderColor="red"; // should be a preference
			e.style.borderWidth="1px";
			e.style.zIndex = piZindex;
		}
	} catch(err)
	{
		alert("Error in highlightNavbar "+err.message+" for element name '"+psHelpElement+"' i="+i);
	}
}
function unhighlightNavbar(psHelpElement,piStart,piEnd)
{
	var e;
	var sTemp
	e = document.getElementById(psHelpElement);
	e.style.backgroundColor="white";
	for (i=piStart;i<=piEnd;i++)
	{
		sTemp = "img"+i;
		e = document.getElementById(sTemp);
		e.style.borderStyle="dotted";
		e.style.borderColor="#aaa"; // NB Brian should be a preference/constant
		e.style.borderWidth="1px";
	}
}
function highlightCurrentChapterImage(piChapter)
{
	try
	{
		// unhighlight existing borders
		// and highlight the border for piChapter
		for (var i = 0;i<TOC_NAVBAR_COUNT;i++)
		{
			if (i==piChapter)
			{
				//setBorder("toc-img"+i,"solid","red","1px");
				//set in mouse out event. awkward coding but mouse events do that to you sometimes.
			} else
			{
				setBorder("toc-img"+i,"dotted","gray","1px");
			}
		}	
	} catch(err)
	{
		errorHandler("highlightCurrentChapterImage",err);
	}
}
function isNumber(psStringToTest)
{
  	var sNumberList = "0123456789.";
	var bReturnValue = true;
	var sTemp;

	if (psStringToTest == "NaN")
	{
		return false;
	}
 
   for (i = 0; i < psStringToTest.length && bReturnValue == true; i++) 
      { 
      sTemp = psStringToTest.charAt(i); 
      if (sNumberList.indexOf(sTemp) == -1) 
         {
         bReturnValue = false;
         }
      }
   return bReturnValue;
   
}
function getNodeCount(psElementId,psClassName)
{
	var iReturn=0;
	var sClassName;
	try 
	{
		var iDebugAssist = 0;
		//-1 was added to the following expression result to make it zero-based
		iReturn = Number(document.getElementById(psElementId).getElementsByClassName(psClassName).length)-1;

		if (iReturn==0)
		{
			iDebugAssist = 1;
			iReturn = getNodeCountVerbose(psElementId,psClassName);
		}

		//alert("node count" + iReturn);
		return iReturn;
	} catch(err)
	{
		//This is a serious, unexplained error with firefox on vista and ie
		//The above statement throws an error
		if (!window.getComputedStyle)
		{
			//alert("IE Error: Your browser returned the following message for className "+psClassName+" "+err.message+". This appears to be a bug with FireFox running under the Vista operating system and with IE. "+iDebugAssist);
		}
		try
		{
			iDebugAssist = 2;
			iReturn = getNodeCountVerbose(psElementId,psClassName);
			return iReturn;
		} catch(err)
		{
			return 0;
		}
	}
}
function getNodeCountVerbose(psElementId,psClassName)
{
	try
	{
		var iDebugAssist = 0;
		//alert("Node count test "+iReturn);
		var eStory = document.getElementById(psElementId);
		var sClassName;
		var iReturn = 0;
		iDebugAssist = 1;
		for (var i = 0; i<eStory.childNodes.length;i++)
	    	{
			sClassName = eStory.childNodes[i].className;
			if (sClassName==undefined)
			{} else
			{
				if (sClassName.indexOf(psClassName)>0 || sClassName == psClassName)
				{
					iReturn++;
				} 
			}
		}
	} catch(err)
	{
		alert("IE Error in getNodeCountVerbose: Your browser returned the following message for className "+psClassName+" "+err.message+". This appears to be a bug with internet explorer 7. "+iDebugAssist);
	}
	iReturn--;
	return iReturn; 
}
function setBorder(psElement,psStyle,psColor,psWidth)
{
	var e = document.getElementById(psElement);
	e.style.borderStyle=psStyle;
	e.style.borderColor=psColor; // should be a preference
	e.style.borderWidth=psWidth;	
}

/******** INTERFACE FUNCTIONS ******************/
function setColumnWidth(psTextColSize)
{
	try
	{
	/* The following could get moved to the top of the file where they get turned into global constants 
		I leave them here because I'd rather not clutter up global memory
	*/	

	// These are the same as default settings in CSS and c/should be set programatically
	// NB Brian It is very important to realize that the values below override many .css defaults.
 
	// NB Brian Note that some elements, like Col_Width, are no longer necessary

	// Narrow text columns, wide sidebar
	var COL_WIDTH_NARROW = "48%";
	var COLTWO_LEFT_NARROW = "51%";
	var GUTTER_LEFT_NARROW = "48%";
	var CONTENT_WIDTH_NARROW = "76%";

	var TOC_LEFT_NARROW ="56%";
	var TOC_NAVBAR_LEFT_NARROW = "61%";
	var NAVBAR_LEFT_NARROW = "42%";
	var OPTIONS_LEFT_NARROW ="85%";
	var TAB_LEFT_NARROW = "80%";
	var TAB_WIDTH_NARROW = "18%";
	var FOOTER_RIGHT_LEFT_NARROW = "80%";
	var FOOTER_RIGHT_WIDTH_NARROW = "18%";
	var LOGIN_TITLE_LEFT_NARROW = "36px";
	var PREFERENCES_TITLE_LEFT_NARROW = "34px";
	var COMMENT_TITLE_LEFT_NARROW = "72px";
	//var HEADER_WIDTH_NARROW = "77%";
	var FOOTER_WIDTH_NARROW = "72%";
	var YOUR_COMMENT_ROWS_NARROW = "14";
	var YOUR_COMMENT_COLS_NARROW = "17";	
	
	// Wide text columns, narrow sidebar
	var COL_WIDTH_WIDE = "48%";
	var COLTWO_LEFT_WIDE = "51%";
	var GUTTER_LEFT_WIDE = "48%";
	var CONTENT_WIDTH_WIDE = "81%";
	var TOC_LEFT_WIDE = "63%";
	var TOC_NAVBAR_LEFT_WIDE = "63%";
	var NAVBAR_LEFT_WIDE = "43%";
	var OPTIONS_LEFT_WIDE ="86%";
	var TAB_WIDTH_WIDE = "14%";
	var TAB_LEFT_WIDE = "84%";
	var LOGIN_TITLE_LEFT_WIDE = "25%";
	var PREFERENCES_TITLE_LEFT_WIDE = "24%";
	var COMMENT_TITLE_LEFT_WIDE = "50%";
	//var HEADER_WIDTH_WIDE = "81%";
	var FOOTER_WIDTH_WIDE = "84%";
	var FOOTER_RIGHT_LEFT_WIDE = "84%";
	var FOOTER_RIGHT_WIDTH_WIDE = "15%";
	var YOUR_COMMENT_ROWS_WIDE = "8";
	var YOUR_COMMENT_COLS_WIDE = "14";

	
	var sColWidth,sLeft,sGutterLeft, sContentWidth,sTOCLeft,sTOCNavbarLeft,sNavbarLeft,sLoginLeft,sLoginTitleLeft;
	var sTabLeft, sTabWidth,sCommentTitleLeft, sHeaderWidth,sFooterWidth,sOptionsLeft,sYourComentRows,sYourCommentCols;
	var sFooterRightLeft, sFooterRightWide;

	//NB Brian move the option menu update to a funciton
	var e =  document.getElementById("opt5"); /* opt5 is Wide Comments Narrow Comments. Could have a global instead */

	if (psTextColSize == WIDTH_NARROW) 
	{
		
		sColWidth = COL_WIDTH_NARROW;
		sLeft = COLTWO_LEFT_NARROW;	
		sGutterLeft = GUTTER_LEFT_NARROW;
		sContentWidth = CONTENT_WIDTH_NARROW;
		sTOCLeft = 	TOC_LEFT_NARROW;
		sTOCNavbarLeft = TOC_NAVBAR_LEFT_NARROW;	
		sNavbarLeft = NAVBAR_LEFT_NARROW;
		sOptionsLeft = OPTIONS_LEFT_NARROW;
		sTabLeft = TAB_LEFT_NARROW;
		sTabWidth = TAB_WIDTH_NARROW;
		sLoginTitleLeft = LOGIN_TITLE_LEFT_NARROW;
		sPreferencesTitleLeft = PREFERENCES_TITLE_LEFT_NARROW;	
		sCommentTitleLeft = COMMENT_TITLE_LEFT_NARROW;		
		//sHeaderWidth = HEADER_WIDTH_NARROW;
		sFooterWidth = FOOTER_WIDTH_NARROW;
		sFooterRightLeft = FOOTER_RIGHT_LEFT_NARROW;
		sFooterRightWidth = FOOTER_RIGHT_WIDTH_NARROW;
		sYourCommentRows = YOUR_COMMENT_ROWS_NARROW;
		sYourCommentCols = YOUR_COMMENT_COLS_NARROW;
		// NB Brian to function
		try
		{
			e.innerHTML = "Wide";  // NB Brian use global constant
			e =  document.getElementById("tab-wide-narrow-button");
			e.value = "Narrow";
			e =  document.getElementById("preference-title");
			//e.innterHTML = "Preferences"
			e.innerHTML = "Prefs";
			e =  document.getElementById("tab-wide-narrow-img");
			e.src = "pictures/arrow-right.png";
		} catch(err)
		{
			alert("Error setting wide-narrow innerHTML"+" "+psTextColSize+" "+err.message);
		}
	} 
	if (psTextColSize == WIDTH_WIDE)
	{
		sColWidth = COL_WIDTH_WIDE;
		sLeft = COLTWO_LEFT_WIDE;	
		sGutterLeft = GUTTER_LEFT_WIDE;
		sContentWidth = CONTENT_WIDTH_WIDE;
		sTOCLeft = TOC_LEFT_WIDE;	
		sTOCNavbarLeft = TOC_NAVBAR_LEFT_WIDE;	
		sNavbarLeft = NAVBAR_LEFT_WIDE;
		sOptionsLeft = OPTIONS_LEFT_WIDE;
		sTabLeft = TAB_LEFT_WIDE;
		sTabWidth = TAB_WIDTH_WIDE;
		sLoginTitleLeft = LOGIN_TITLE_LEFT_WIDE;
		sPreferencesTitleLeft = PREFERENCES_TITLE_LEFT_WIDE;
		sCommentTitleLeft = COMMENT_TITLE_LEFT_WIDE;
		//sHeaderWidth = HEADER_WIDTH_WIDE;
		sFooterWidth = FOOTER_WIDTH_WIDE;
		sFooterRightLeft = FOOTER_RIGHT_LEFT_WIDE;
		sFooterRightWidth = FOOTER_RIGHT_WIDTH_WIDE;
		sYourCommentRows = YOUR_COMMENT_ROWS_WIDE;
		sYourCommentCols = YOUR_COMMENT_COLS_WIDE;
		//NB Brian to function
		try
		{
			e.innerHTML = "Narrow"; //update options menu item - perhaps separate function
			e =  document.getElementById("tab-wide-narrow-button");
			e.value = "Narrow";
			e =  document.getElementById("preference-title");
			e.innerHTML = "Prefs";
			e =  document.getElementById("tab-wide-narrow-img");
			e.src = "pictures/arrow-left.png";
		} catch(err)
		{
			alert("Error setting wide-narrow innerHTML "+err.message+" "+psTextColSize);
		}
	}
	giCurrentColWidth = psTextColSize;
	
	var e = document.getElementById("eternal-suffering");
	e.style.width = sColWidth;
	e = document.getElementById("when-we-all-have-brains");
	e.style.width = sColWidth;
	e = document.getElementById("skin-deep"); 
	e.style.width = sColWidth;
	e = document.getElementById("food"); 
	e.style.width = sColWidth;
	e = document.getElementById("swimming-with-the-invertebrates");
	e.style.width = sColWidth;
	e = document.getElementById("dream-of-a-perfect-world");
	e.style.width = sColWidth;
	e = document.getElementById("column-one");

	e.style.width = sColWidth;
	e = document.getElementById("column-one-mask");
	e.style.width = sColWidth;
	e = document.getElementById("gutter");
	e.style.left = sGutterLeft;
	e = document.getElementById("column-two");
	//e.style.width = sColWidth;
	e.style.left = sLeft;

	e = document.getElementById("content-header-right-left");
	e.style.left = sLeft;

	e = document.getElementById("column-two-mask");
	e.style.width = sColWidth;
	e.style.left = sLeft;

	e = document.getElementById("content");
	e.style.width = sContentWidth;
	//e = document.getElementById("content-header");
	//e.style.width = sHeaderWidth;


	e = document.getElementById("table-of-contents");
	e.style.left = sTOCLeft;

	e = document.getElementById("table-of-contents-navbar");
	e.style.left = sTOCNavbarLeft;

	e = document.getElementById("options");
	e.style.left = sOptionsLeft;

	//e = document.getElementById("sidebar-right");
	//e.style.left = sSidebarRight;

	e = document.getElementById("tab");
	e.style.left = sTabLeft;
	e.style.width = sTabWidth;

	e = document.getElementById("login-title");
	e.style.left = sLoginTitleLeft;
	
	e = document.getElementById("comments-title");
	e.style.left = sCommentTitleLeft;

	e = document.getElementById("preference-title");
	e.style.left = sPreferencesTitleLeft;
	
	e = document.getElementById("navbar");
	e.style.left = sNavbarLeft;
		
	e = document.getElementById("footer");
	e.style.width = sFooterWidth;

	e = document.getElementById("footer-right");
	e.style.left = sFooterRightLeft;
	e.style.width = sFooterRightWidth;

	e = document.getElementById("your-comments");
	e.cols = sYourCommentCols;
	e.rows = sYourCommentRows;

	drawPage("resize");

	} catch(err)
	{
		alert("error in setColumnWidth "+err.message);
		drawPage("resize");

	}
}
function setColumnWidthEvent()
{
	try
	{
		if (giCurrentColWidth == WIDTH_NARROW)
		{

			setColumnWidth(WIDTH_WIDE);
		} else
		{

			setColumnWidth(WIDTH_NARROW);
		}	
	} catch (err)
	{
		errorHandler("setColumnWidthEvent",err);
	}
}
/******** END INTERFACE FUNCTIONS ***********/

// Tab funcitons
function tabsNormal()
{
	try
	{
		
		var e = document.getElementById("help-title");
		e.style.color = "gray";
		e = document.getElementById("help");
		e.style.zIndex = "301";

		e = document.getElementById("login-title");
		e.style.color = "gray";
		e = document.getElementById("login");
		e.style.zIndex = "302";


		e = document.getElementById("preference-title");
		e.style.zIndex = "301";
		e.style.color = "gray";
		e = document.getElementById("preferences");
		e.style.zIndex = "301";


		e = document.getElementById("comments-title");
		e.style.zIndex = "302";
		e.style.color = "gray";
		e = document.getElementById("comments");
		e.style.zIndex = "302";


		e = document.getElementById("rating-title");
		e.style.zIndex = "303";
		e.style.color = "gray";

		e = document.getElementById("rating");
		e.style.zIndex = "303";



		//	e = document.getElementById("rating-title");
		// e.style.zIndex = "303";		


	} catch(err)
	{
		alert("tabsNormal "+err.message);
	}

}
function addTabToList(piWhichTab)
{
	//This should add tab to end of list.
	for (var i = 0; i<TAB_COUNT;i++)
	{
		//remove it if its already there and add to end of array
		if (giTabList[i]==piWhichTab)
		{
			//alert("about to splice for "+piWhichTab);
			giTabList.splice(i,1);
		} 
		// append to end.
		if (giTabList[i]=="" || giTabList[i]==null)
		{
			//alert("addTabToList " + piWhichTab+" i "+i);
			giTabList[i]=piWhichTab;
			return;
		}
	}	
}
function removeTabFromList(piWhichTab)
{
	// this code assumes only 1 instance in the list, which is a valid assumption enforced by a duplicate check
	//alert("removing tab from list "+piWhichTab);
	for (var i = 0; i<TAB_COUNT;i++)
	{
		if (giTabList[i]==piWhichTab)
		{
			//alert("about to remove for "+piWhichTab);
			giTabList.splice(i,1);
			showNewTab();
			return;
		} 
	}
}
function showNewTab()
{
	// compare the identity of the tab being closed with the list. the last added should be on top. //
	try
	{

		for (var i=TAB_COUNT;i>=0;i--)
		{
			if (giTabList[i] == "" || giTabList[i]==null)
			{
				//alert("null");
			} else
			{
				//alert("about to launch for "+giTabList[i]+ " i"+i);
				tabLaunch(giTabList[i]);
				return;
			};  
		}
	} catch(err)
	{
		alert("Error in showNewTab "+err.message);
	}
}
function tabLaunch(piWhichTab)
{
	//NB should be done with constants
	try
	{
		switch(piWhichTab)
		{
		case TAB_LOGIN:
			//alert("tl login");
			loginShow();
			return;
		case TAB_PREFERENCES:
			//alert("tl preferences");
			preferencesShow();
			return;
		case TAB_COMMENTS:
			//alert("tl comment");
			commentsShow();
			return;
		case TAB_RATING:
			//alert("tl rating");
			//showRating();
			return;
		case TAB_HELP:
			//alert("tl help");
			helpShow();
			return;
		}
	} catch(err)
	{
		alert("Error in tabLaunch "+piWhichTab);
	}
}

// END OF TAB FUNCTIONS

