// *************************************************************
function ______NOTES______ () {}

// Functions to deal with note sets are in prefs.html

var correctionStatus = null;
var firstStatus = null;
var secondStatus = null;


// put status types in an array
var firstStatusTypes = new Array ("Correction/bug Category","eBook text does not match printed text, but should: typo/missing content","eBook text needs to vary from printed text, but doesn't: needs editorial input","Misplaced figure, box, or margintext","Style/design issue","TOC issue","Broken link to supplemental activity","Broken internal link (e.g. to section or chapter)","Page number link goes to wrong content","Missing link");
var secondStatusTypes = new Array ("Correction/bug Severity","Major error/bug -- must be fixed","Minor error/bug -- should be fixed","Suggestion/Question");



// Define note types
var PUBLIC_NOTE = 0;
var PRIVATE_NOTE = 1;
var WIKI_NOTE = 2;

// Define note set types
// Old classification was 0: unsubscribable; 1: subscribable; -1: subscribed to; -2: "ghost set" (see RemoveNoteSet below)
var USER_OWNED = 1;
var SUBSCRIBED_TO = -1;
var INSTRUCTOR_SET = -2;
var GHOST_SET = -9;
var CORRECTIONS_SET = 9;


// Each element of the sections[] array can have a notes array.
// sections[p].notes[0] is always the student's note.
// Other array elements hold subscribed notes (e.g. the student's prof's notes)

// The noteSets array holds the names of the sets from which the user is getting notes
var noteSets = new Array();

// Style settings for note divs
var noteStyle = "padding:10px; margin-bottom:5px";

// individual ebook specific chapter name
// chap# in listen6e_source.xml:    24       25        26         27        28       29        30            31
var listen6e_chapname = new Array ("Unit I","Unit II","Unit III","Unit IV","Unit V","Prelude","Interlude A","Interlude B");   			  
var elrod2_chapname = new Array ("","Chapter 1","Chapter 2.1","Chapter 2.2","Chapter 2.3");


// noteSets and all elements of the notes[] arrays except 0 are populated by textfn.php
// when the textbook first loads into the browser.
function AddNoteSet(setId, setNumber, setName, type) {
	var newSet = new Object();
	newSet.setId = setId;
	newSet.setNumber = setNumber;
	newSet.setName = setName;
	// New classification constants for types are given above.
	// for legacy reasons, USER_OWNED sets might come in as type 0 or 1; set either to USER_OWNED.
	if (type == 0 || type == 1) {
		newSet.type = USER_OWNED;
	} else {
		newSet.type = type;
	}
	noteSets[noteSets.length] = newSet;
}

// Remove a note set, either because it was unsubscribed or deleted
function RemoveNoteSet(setId) {
	var tbr;
	
	// Find the index of the to-be-removed setId
	for (var i = 0; i < noteSets.length; ++i) {
		if (noteSets[i].setId == setId) {
			tbr = i;
			break;
		}
	}
	
	// Go through all sections and delete the notes from this set
	for (var s = 1; s < sections.length; ++s) {
		if (sections[s] != null && GetNote(tbr, s) != "") {
			sections[s].notes[tbr] = null;
			
			// If there aren't any other notes in this section, delete the whole notes array
			for (var i = 0; i < noteSets.length; ++i) {
				if (GetNote(i, s) != "") {
					break;
				}
			}
			if (i == noteSets.length) {
				sections[s].notes = null;
			}
		}
	}
	
	// Remove any custom sections for the set
	var c = 0;
	while (registeredCustomSections != null && c < registeredCustomSections.length) {
		var rs = registeredCustomSections[c];
		if (rs != null && sections[CSSectionsIndex(rs)].setId == setId) {
			// If we're at the custom section when we're doing this, have to jump to attachee section
			var jumpToAttachee = false;
			if (curSection == CSSectionsIndex(rs)) {
				jumpToAttachee = true;
			}

			RemoveCustomSection(rs, jumpToAttachee);
			
			// Have to reset c to make sure we get them all
			c = 0;
		} else {
			++c;
		}
	}
	
	// Now get rid of the set itself.  We can't actually remove it from the noteSets array,
	// because that would screw up the ordering of the notes from the other sets.  Instead
	// we just set that array value to an object with a single field: a type of GHOST_SET.
	// This makes the variable into a kind of "ghost noteSet" that won't disturb the others.
	// We have to be careful, though, to deal with ghost noteSets in places like prefs.html.
	noteSets[tbr] = new Object();
	noteSets[tbr].type = GHOST_SET;
	
	// Update (9/12/2005): Actually, we could just remove it now, but don't worry about changing that.
	
 	// Reload the main text window, in case there was a note from this set on the current page
	LoadSection('reload');
}

function ChangeNoteSetName(setId, newName) {
	for (var i = 0; i < noteSets.length; ++i) {
		if (noteSets[i].setId == setId) {
			noteSets[i].setName = newName;
			break;
		}
	}
}

function NoteSetServerError(err) {
	// This function is called by textfn.php when there is an error with an attempted
	// note subscription.  We need to show an alert with the err string.  But since
	// we know the supplemental window will be in front, we try to show the alert there.
	if (FocusWindow(sw)) {
		sw.alert(err);
	} else {
		alert(err);
	}
}


var modifiableSets = 0;
var firstModifiable = -1;
// Find out how many modifiable notesets there are
// And find the first modifiable set
function GetNoteSetInfo() {
	modifiableSets = 0;
	firstModifiable = -1;
	for (var i = 0; i < noteSets.length; ++i) {
		if (noteSets[i].type > 0) {
			if (firstModifiable == -1) {
				firstModifiable = i;
			}
			++modifiableSets;
		}
	}
}


// Construct a select input for the user's modifiable note sets
function GetNoteSetSelect(selected) {
	if (selected == null) {
		selected = 0;
	}
	
	var s = '<select name="noteSet" style="width:175px">';
	s += '<option value="' + selected + '">Annotation Set:</option>';
	s += '<option value="' + selected + '">---------------</option>';
	for (var i = 0; i < noteSets.length; ++i) {
		// If the set is modifiable offer it as an option
		if (noteSets[i].type > 0) {
			s += '<option value="' + i + '"'
			if (i == selected) {
				s += ' selected';
			}
			s += '>' + noteSets[i].setName + '<\/option>';
		}
	}			
	s += '<\/select>';
	
	return s;
}

function IsCorrectionsNote(note) {
	if (note.setIndex == null) {
		return false;
	} else {
		return (noteSets[note.setIndex].type == CORRECTIONS_SET);
	}
}

var noteWarningIssued = false;
var noteEditorTA;
var noteIndexBeingEdited;
var noteBeingEdited = null;
var notePrefix;
var submitterName;
var addedPrefix = false;

function CreateNote(stuckTo, sposx, sposy) {
	// Create a record for the new note in the notes[] array
	noteIndexBeingEdited = RegisterNote(0, -1, curSection, "", -1, stuckTo);
	noteBeingEdited = sections[curSection].notes[noteIndexBeingEdited];

	// Get handles to notesDiv and the editor
	// If we received a stuckTo value, we want to put the note there.
	var notesDiv;
	if (stuckTo != null) {
		var thisNoteHTML = stickyNoteBaseHTML;
		thisNoteHTML = thisNoteHTML.replace(/XXX/g, noteIndexBeingEdited);

		// Store a reference to the notes[] index in stickyNotesForPage
		++stickyNoteIndex;
		stickyNotesForPage[stickyNoteIndex] = noteIndexBeingEdited;
		thisNoteHTML = thisNoteHTML.replace(/YYY/g, stickyNoteIndex);
		
		// Put in the note's color
		thisNoteHTML = thisNoteHTML.replace(/ZZZ/g, NoteColor(noteBeingEdited));
		thisNoteHTML = thisNoteHTML.replace(/VVV/g, NoteTitleColor(noteBeingEdited));
		
		// insert url start for image (can't do this at the start because in Angel
		// urlStart gets set later)
		thisNoteHTML = thisNoteHTML.replace(/UUU/g, urlStart);
		
		// We don't need the "HHH" here
		thisNoteHTML = thisNoteHTML.replace(/HHH/, "");

		var snSpan = main.document.createElement('DIV');
		// the outer div is absolutely positioned at 0, 0
		snSpan.id = 'stickyNoteOuter' + noteIndexBeingEdited;
		snSpan.style.position = 'absolute';
		snSpan.style.left = "0px";
		snSpan.style.top = "0px";
		// set zIndex to 990 so it appears above most other absolute divs --
		// but not the standard popin, which has zIndex 1000
		snSpan.style.zIndex = "990";
		
		// Attach the note to the top of the body
		snSpan.innerHTML = thisNoteHTML;
		main.document.body.insertBefore(snSpan, main.document.body.firstChild);
			
		notesDiv = main.document.getElementById('stickyNoteHolder' + noteIndexBeingEdited);
		
		main.document.getElementById('stickyNoteTitle' + noteIndexBeingEdited).onmousedown = EngageStickyNotePopInWindow;
		
		// Initialize the sticky note settings: set baselines, then set the things we know
		InitializeStickyNoteSettings(noteBeingEdited);
		noteBeingEdited.dtop = sposy;
		// set horizontal so it's centered on the place the user clicked
		noteBeingEdited.dright = sposx + Math.round(noteBeingEdited.width / 2);
//		noteBeingEdited.dright = 10 + main.document.getElementById("stickyNoteInner" + noteIndexBeingEdited).offsetWidth;
		
		// The following function will make sure the note is visible for editing.
		StickyNoteModifyStuff();

	} else {
		notesDiv = main.document.getElementById('notesDiv');
	}
	
	// Construct a div for the note
	var curDiv = main.document.createElement('DIV');
	curDiv.id = 'note' + noteIndexBeingEdited;
	// noteStyle is declared above in text format; re-create it here using the DOM
	curDiv.style.padding = "10px";
	curDiv.style.marginBottom = "5px";
	curDiv.style.backgroundColor = "#" + NoteColor(noteBeingEdited);

	// Add the header
	var headerDiv = main.document.createElement('DIV');
	headerDiv.id = 'noteHeader' + noteIndexBeingEdited;
	headerDiv.innerHTML = NoteHeader(noteIndexBeingEdited, noteBeingEdited, 'form');
	curDiv.appendChild(headerDiv);
	
	// Add a content div	
	var curContent = main.document.createElement('DIV');
	curContent.id = 'noteContent' + noteIndexBeingEdited;
	
	// Make the content div initially invisible
	curContent.style.display = "none";
	
	// Add the content div to the curDiv
	curDiv.appendChild(curContent);
	
	// Attach curDiv to the notesDiv
	notesDiv.appendChild(curDiv);
	
	// Hide the popup window
	ClosePopInWindow_ebook();
	
	// Move the editor to right before the note's current content
	var editor = main.document.getElementById('noteEditor');	
	editor = editor.parentNode.removeChild(editor);
	curDiv.insertBefore(editor, curContent);

	// Get a handle to the noteTA 
	noteEditorTA = main.document.getElementById('noteTA');
	
	// reset the text area text
	SetNoteEditorText("");
	
	// Set the revert/cancel button to cancel, since there's nothing to revert to
	ChangeNoteEditorRevertButton('Cancel');
	
	// Show the note editor complex
	ShowNoteEditor(editor);
	
	// Hide the custom section buttons, if they are there.
	// If this isn't a custom section, the following line won't do anything.
	SetDisplay(main.document.getElementById('editPageBtnDiv'), "none");
	
	// In the case of end-of-chapter questions pages, we need to move the "Show Printable Answers" link to appear below all existing notes and the note now being created
	ShiftPrintableAnswersDiv();
	
	// Set textAreaToEdit so that InsertText knows where to insert text
	textAreaToEdit = noteEditorTA;

	// Reposition stickies that were moved around by the note -- unless this is itself a sticky!
	if (!IsStickyNote(noteBeingEdited)) {
		RepositionStickyNotes();
	}
	
	// scroll to the note
	ScrollToElement(main, editor, -100);
}

function EditNoteClear() {
	SetNoteEditorText("");
}

function EditNoteDelete() {
	SetNoteEditorText("");
	EditNoteStop("delete");
}

function ShowNoteEditor(editor) {
	SetDisplay(editor, 'block');

	// for AngelStyle, have to show the editor now.
	// main.noteFCKeditor is set by ebook_page.asp
	if (angelStyle == 1 && main.noteFCKeditor != null) {
		main.noteFCKeditor.ReplaceTextarea();
		
		// set noteFCKeditor to null now so we don't add another editor.
		main.noteFCKeditor = null;
	}
}

// The SetHTML function might not work until the editor is loaded.
// so we include the call in a try() block, and on error, we set a flag
var editorTextToBeLoaded = null;
function SetNoteEditorText(text) {
	if (text == null) {
		text = editorTextToBeLoaded;
	}
	if (text == null) {
		return;
	}
	
	var fed = GetFCKEditor();
	if (fed != null) {
		try {
			fed.SetHTML(text);
			fed.Focus();
		} catch(e) {
			editorTextToBeLoaded = text;
		}
	} else {
		noteEditorTA.value = text;
	}
}

function EditNoteStop(ok, correctionStatus, firstStatus, secondStatus) {
	var input;

	// if ok is "delete", we're deleting
	if (ok == "delete") {
		input = "";
		ok = true;
	
	// else get the HTML out of the FCK editor instance
	} else {
		var fed = GetFCKEditor();
		if (fed != null) {
			input = fed.GetHTML();
		} else {
			input = noteEditorTA.value;
		}
	}
	
	var s = sections[curSection];
	
	if (main.document.addNoteForm == null) {
		alert(main.document.addNoteForm);
		noteBeingEdited = null;
		LoadSection('reload');
		return;
	}
	
	// Hide the editor and move it to the bottom of noteDiv
	var editor = main.document.getElementById('noteEditor');
	SetDisplay(editor, 'none');
	editor = editor.parentNode.removeChild(editor);
	main.document.getElementById('notesDiv').appendChild(editor);
	
	// If user pressed "Save", (or clicked one of the corrections radio buttons)
	// *and* input is not null (it could be null if there was an error with the editor
	// or the user clicked edit again before the editor was done loading)...
	if (ok && input != null) {		
		// Encode user input
		input = EncodeProblemCharacters(input);
		
		// add a dummy attribute to anchors, to prevent FormatNote from
		// adding a target attribute (necessary to support legacy notes)
		input = input.replace(/<a /g, '<a foo="bar" ');
		
		// Get note specs -- but not if this is someone else's shared note
		if ((noteBeingEdited != null && noteBeingEdited.setIndex == -1) || (noteBeingEdited != null && noteBeingEdited.setIndex != null && noteSets[noteBeingEdited.setIndex] != null && noteSets[noteBeingEdited.setIndex].type > 0)) {		
			GetNoteSetInfo();
			if (modifiableSets > 1) {
				var setMenu = main.document.addNoteForm.noteSet;
				noteBeingEdited.setIndex = setMenu.options[setMenu.selectedIndex].value;
			} else {
				noteBeingEdited.setIndex = firstModifiable;
			}
	
			var typeMenu = main.document.addNoteForm.noteType;
			noteBeingEdited.noteType = typeMenu.options[typeMenu.selectedIndex].value;
			
			// Set the lastNoteSet/lastNoteType used variables
			lastNoteSetUsed = noteBeingEdited.setIndex;
			lastNoteTypeUsed = noteBeingEdited.noteType;
		}
		
		// Update the note's content in js
		noteBeingEdited.noteText = input;
		
		// alert("value of noteBeingEdited.noteText: " + noteBeingEdited.noteText);
		
		// since the value of noteBeingEdited.noteText came from noteEditorTA,
		// the prefix is not included
			
	}
	
	// Now, if the note is not empty...
	if (noteBeingEdited.noteText != "") {
		// Update the note header and content on the page
		
		// Corrections Note
		if (IsCorrectionsNote(noteBeingEdited)) {
			noteBeingEdited.noteType = 0;
			
			// old note, so correctionStatus is passed from radio buttons
			if (main.document.addNoteForm.correctionStatus != null) {
				if (main.document.addNoteForm.correctionStatus[0].checked) {
					noteBeingEdited.correctionStatus = 0;
				} else if (main.document.addNoteForm.correctionStatus[1].checked) {
					noteBeingEdited.correctionStatus = 1;
				} else if (main.document.addNoteForm.correctionStatus[2].checked) {
					noteBeingEdited.correctionStatus = 2;
				} 

				// also firstStatus and secondStatus
				// this doesn't seem to be working 
				noteBeingEdited.firstStatus = main.document.addNoteForm.firstStatus.selectedIndex;
				noteBeingEdited.secondStatus = main.document.addNoteForm.secondStatus.selectedIndex;
				
				// also need to grab submitterName?
				if (main.document.addNoteForm.submitterName != null) {
					submitterName = main.document.addNoteForm.submitterName.value;
				}
				
				// now put prefix on
				notePrefix = noteBeingEdited.correctionStatus + '' + noteBeingEdited.firstStatus + '' +  noteBeingEdited.secondStatus + submitterName + "|";
				//alert("notePrefix: " + notePrefix);

				noteBeingEdited.noteText = notePrefix + noteBeingEdited.noteText;
			// or this is a new note
			} else {
				// in that case, we add the "000username|" prefix, indicating
				// that this is an outstanding correction, with firstStatus and secondStatus set to default
				noteBeingEdited.noteText = "000" + username + "|" + noteBeingEdited.noteText;
				noteBeingEdited.correctionStatus = 0;
				noteBeingEdited.firstStatus = 0;
				noteBeingEdited.secondStatus = 0;
				// first user of new note is submitter
				submitterName = username;
				// but we need to record that we did this!
				
			
			} 
			
			// By the end of above block, prefix should be there
			
			// Note that we don't show the note if it's a corrections note, b/c notes
			// get reloaded anyway 
			
		// Normal Note
		} else {
			SwapInnerHTML(main.document.getElementById('noteHeader' + noteIndexBeingEdited), NoteHeader(noteIndexBeingEdited, noteBeingEdited, 'text'));
			SwapInnerHTML(main.document.getElementById('noteContent' + noteIndexBeingEdited), FormatNote(noteBeingEdited.noteText));
			// Show the note
			SetDisplay(main.document.getElementById('noteContent' + noteIndexBeingEdited), 'block');
		}
		
		// If this is a sticky note, do some more initialization
		if (IsStickyNote(noteBeingEdited)) {
			StickyNoteEditStopStuff();
		}
		
	// Otherwise, i.e. if note is empty
	} else {
		// If this was a sticky note, have to remove it from the links
		if (IsStickyNote(noteBeingEdited)) {
			RemoveStickyNoteLink(noteIndexBeingEdited);
		}
	
		// value of noteIndexBeingEdited is set in ModifyNote() to noteIndex
	
		// Delete the note from js
		s.notes[noteIndexBeingEdited] = null;
		
		// If there aren't any notes left, delete the whole notes array
		for (var j = 0; j < s.notes.length; ++j) {
			if (s.notes[j] != null) {
				break;
			}
		}
		if (j == s.notes.length) {	// We made it through the loop, so nothing there
			s.notes = null;
		}
		
		// Delete the note's div
		if (IsStickyNote(noteBeingEdited)) {
			main.document.body.removeChild(main.document.getElementById('stickyNoteOuter' + noteIndexBeingEdited));
		} else {
			main.document.getElementById('notesDiv').removeChild(main.document.getElementById('note' + noteIndexBeingEdited));
		}
	}

	// Reposition stickies that were moved around by the note -- unless this is itself a sticky!
	if (!IsStickyNote(noteBeingEdited)) {
		RepositionStickyNotes();
	}

	// Now, if user pressed save, save the note here.  Can't do it above because
	// at the end of the saveNote procedure noteIndexBeingEdited is going to get
	// set to null.
	if (ok) {
		// Save the note
		SaveNote();

		// KC: Per QA testers, we should also close an upload window, if open
		// ??????
		//ClosePopInWindow();

	// If we're not saving, set noteBeingEdited to null now.
	} else {
		// Set noteBeingEdited to null so we can edit something else
		noteBeingEdited = null;
	}

	// Show the custom section buttons, if they are there.
	// If this isn't a custom section, the following line won't do anything.
	SetDisplay(main.document.getElementById('editPageBtnDiv'), "block");
	
	// In the case of end-of-chapter questions pages, we need to move the "Show Printable Answers" back to the top
	if (main.document.getElementById('showDiv') != null) {	
		main.document.getElementById("showDiv").style.top = "75px";
	}
}

// This function is called if a user has clicked on a radio button to change the status of a correction,
// without having used the NoteEditor at all
function SaveCorrectionsNote(noteIndex, correctionStatus, firstStatus, secondStatus) {


	noteBeingEdited = sections[curSection].notes[noteIndex];
	
	// change correctionStatus in noteText
	// we don't need to remove the whole prefix, only the first three char
	// so that 000Pepper|blah becomes 101Pepper|blah (or whatever)
	noteBeingEdited.noteText = correctionStatus + '' + firstStatus + '' + secondStatus + noteBeingEdited.noteText.substr(3);
	//alert(noteBeingEdited.noteText)

		
	SaveNote();
	return;
}
	
// Save the note we've just been editing
function SaveNote() {
	// Guests can't save notes
	if (username == "guest") {
		// Set noteBeingEdited to null so we can edit something else
		noteBeingEdited = null;

		return;
	}

	var tmpSend = "submitNote"
                + "&noteId=" + noteBeingEdited.noteId
                + "&setId=" + noteSets[noteBeingEdited.setIndex].setId
                + "&section=" + curSection
                + "&noteType=" + noteBeingEdited.noteType
                + "&noteText=" + escape(noteBeingEdited.noteText)
                + "&stuckTo=" + ((noteBeingEdited.stuckTo == null) ? "" : noteBeingEdited.stuckTo)
                + "&colorName=" + noteBeingEdited.colorName;

//	alert(tmpSend);

	
	top.Servercom("submitNote"
		+ "&noteId=" + noteBeingEdited.noteId
		+ "&setId=" + noteSets[noteBeingEdited.setIndex].setId
		+ "&section=" + curSection
		+ "&noteType=" + noteBeingEdited.noteType
		+ "&noteText=" + escape(noteBeingEdited.noteText)
		+ "&stuckTo=" + ((noteBeingEdited.stuckTo == null) ? "" : noteBeingEdited.stuckTo)
		+ "&colorName=" + noteBeingEdited.colorName
		// Note: send "" if no stuckTo value
	);
	return;
}



// Function used by textfn.php to set the noteId field of a just-created note
function SetNoteId(noteId) {
	var oldNoteId = noteBeingEdited.noteId;
	if (noteBeingEdited != null) {
		noteBeingEdited.noteId = noteId;
	}
	
	// If this is a new sticky note, save coordinates now, since we just got
	if (IsStickyNote(noteBeingEdited) && (oldNoteId == null || oldNoteId == 0)) {
		SubmitNoteCoordinates(noteBeingEdited);
	}
}

// This is called by textfn.php once it's done submitting a note.
function NoteSubmitDone() {
	// If we just altered a corrections note, we need to reload the page to show it properly
	if (IsCorrectionsNote(noteBeingEdited)) {
		// Set noteBeingEdited to null so we can edit something else
		noteBeingEdited = null;
		LoadSection('reload');
	} else {
		// Set noteBeingEdited to null so we can edit something else
		noteBeingEdited = null;
	}
}

function ModifyNote(noteIndex) {
	// If we're already modifying something...
	if (noteBeingEdited != null) {
		// If this is the note we're editing, save it
		if (noteIndex == noteIndexBeingEdited) {
			EditNoteStop(true);
		} else {		
			alert("You must finish with the note you are already working on before modifying another note.");
		}
		return;
	}
	
	// Set the following globals
	noteIndexBeingEdited = noteIndex;
	noteBeingEdited = sections[curSection].notes[noteIndex];
	
	// Get handles to the editor, the notesDiv, and to the current note's outer div, header div, and content div
	var editor = main.document.getElementById('noteEditor');
	var notesDiv = main.document.getElementById('notesDiv');
	var curDiv = main.document.getElementById('note' + noteIndex);
	var curContent = main.document.getElementById('noteContent' + noteIndex);
	var curHeader = main.document.getElementById('noteHeader' + noteIndex);
	
	// Move the editor to right before the note's current content
	editor = editor.parentNode.removeChild(editor);
	curDiv.insertBefore(editor, curContent);
	
	// Hide the note's current content
	SetDisplay(curContent, 'none');
	
	// Get values of correctionStatus and submitterName for use in NoteHeader
	noteBeingEdited.correctionStatus = noteBeingEdited.noteText.substr(0, 1);
	// And of firstStatus and secondStatus
	noteBeingEdited.firstStatus = noteBeingEdited.noteText.substr(1,1);
	noteBeingEdited.secondStatus = noteBeingEdited.noteText.substr(2,1);
	
	var endExtractIndex = noteBeingEdited.noteText.indexOf("|") - 3;
	submitterName = noteBeingEdited.noteText.substr(3, endExtractIndex);
	//alert("submitterName: " + submitterName);
	
	// Put the form elements in the curHeader
	SwapInnerHTML(curHeader, NoteHeader(noteIndexBeingEdited, noteBeingEdited, 'form'));
	
	// Get a handle to the noteTA 
	noteEditorTA = main.document.getElementById('noteTA');
	
	// Set the text area text to the note's text
	// If this is a corrections note, we want to strip prefix first
	notePrefix = noteBeingEdited.correctionStatus + '' + noteBeingEdited.secondStatus + '' +  noteBeingEdited.secondStatus + submitterName + "|";
	var lengthNotePrefix = notePrefix.length;
	if (IsCorrectionsNote(noteBeingEdited)) {
		textWithoutPrefix = noteBeingEdited.noteText.substr(lengthNotePrefix);
		//alert("textWithoutPrefix = " + textWithoutPrefix);
		SetNoteEditorText(DecodeProblemCharacters(textWithoutPrefix));
	} else {
		// i.e. if this is a normal note
		SetNoteEditorText(DecodeProblemCharacters(noteBeingEdited.noteText));
	}
	
	// Set the revert/cancel button to revert
	ChangeNoteEditorRevertButton('Revert');

	// Show the note editor complex
	ShowNoteEditor(editor);

	// Further initialization for stickies
	if (IsStickyNote(noteBeingEdited)) {
		StickyNoteModifyStuff()
	} 
	
	// Hide the custom section buttons, if they are there.
	// If this isn't a custom section, the following line won't do anything.
	SetDisplay(main.document.getElementById('editPageBtnDiv'), "none");
	
	// Set textAreaToEdit so that InsertText knows where to insert text
	textAreaToEdit = noteEditorTA;
	
	// In the case of end-of-chapter questions pages, we need to move the "Show Printable Answers" link to appear below all existing notes and the note now being created
	ShiftPrintableAnswersDiv();

	// Reposition stickies that were moved around by the note -- unless this is itself a sticky!
	if (!IsStickyNote(noteBeingEdited)) {
		RepositionStickyNotes();
	}

	// scroll to the note to be edited
	ScrollToElement(main, editor, -100);
}

function ShiftPrintableAnswersDiv() {
	// In the case of end-of-chapter questions pages, we need to move the "Show Printable Answers" link to appear below all existing notes and the note now being created
	if (main.document.getElementById('showDiv') != null) {	
		// get handle to first question -- note that this may not be q1.
		var firstQuestion = null;
		for (var x = 1; x < 200; ++x) {	// Assume there will never be more than 200 questions
			firstQuestion = main.document.getElementById('q' + x);
			if (firstQuestion != null) {
				break;
			}
		}
		if (firstQuestion != null) {		
			// apparently we need to temporarily show the firstQuestion in order for ShiftDQShowLink to work
			firstQuestion.style.display = "block";
			ShiftDQShowLink(firstQuestion);
			// now we hide it
			firstQuestion.style.display = "none";
		}
	}
}

// GetNote: Return the indexed note, or "" if it doesn't exist
function GetNote(i, s) {
	if (sections[s].notes == null) {
		return "";
	} else {
		if (sections[s].notes[i] == null) {
			return "";
		} else {
			return sections[s].notes[i];
		}
	}
}

// GetNoteIndex: Return the index of the referenced note in the sections[].notes array, 
// or null if referenced note doesn't exist
function GetNoteIndex(s, noteId) {
	if (sections[s] == null || sections[s].notes == null) {
		return "";
	} else {
		for (var i = 0; i < sections[s].notes.length; ++i) {
			if (sections[s].notes[i].noteId == noteId) {
				return i;
			}
		}
		
		// If we get through all the notes in the section and don't find the one we're looking for,
		// return null
		return null;
	}
}

// Return the icon and note set that should appear in the window for a note
// Last noteSet/noteType used; use these as default for new notes/cs's
var lastNoteSetUsed = 0;
var lastNoteTypeUsed = 0;
function NoteHeader(noteIndex, note, format) {
	var icon;
	
	// Notes from imported sets that aren't wiki are not editable
	// note.setIndex will be -1 if this is a new note, so in this case it must be editable
	if (note.setIndex >= 0 && noteSets[note.setIndex].type < 0 && note.noteType != WIKI_NOTE) {
		icon = '<img title="This note is not modifiable." src="' + urlStartBookID + 'pics/noteicon.gif" width="26" height="26" border="0" style="vertical-align:text-bottom">';
	} else {
		icon = '<a title="Click to modify this note" href="Javascript:top.ModifyNote(' + noteIndex + ')"><img src="' + urlStartBookID + 'pics/noteiconedit.gif" width="26" height="31" border="0" style="vertical-align:text-bottom"></a>';
	}
	
	var set, type, color;
	
	// If we're writing a form, make form elements -- this is used by CreateNote() and ModifyNote()
	if (format == 'form') {
		// Get info about note sets
		GetNoteSetInfo();

		// If there are more than one modifiable sets,
		// write a drop-down menu with the available note sets
		// Use lastNoteSetUsed unless note.setIndex already has a value
		var defaultSet;
		if (note.setIndex >= 0) {
			defaultSet = note.setIndex;
		} else {
			defaultSet = lastNoteSetUsed;
		}
		if (modifiableSets > 1) {
			set = GetNoteSetSelect(defaultSet);
		} else {
			set = '<b>' + noteSets[firstModifiable].setName + '</b>';
		}
		
		// Write a drop-down menu with types
		// Use lastNoteTypeUsed unless note.noteType already has a value
		var defaultType;
		if (note.noteType >= 0) {
			defaultType = note.noteType;
		} else {
			defaultType = lastNoteTypeUsed;
		}
		type = '<select name="noteType" onchange="top.NoteTypeMenuChanged(this)">';
		type += '<option value="' + defaultType + '">Note Type:</option>';
		type += '<option value="">----------</option>';
		if (defaultType == PUBLIC_NOTE) {
			type += '<option value="' + PUBLIC_NOTE + '" selected>Public</option>';
		} else {
			type += '<option value="' + PUBLIC_NOTE + '">Public</option>';
		}
		if (defaultType == WIKI_NOTE) {
			type += '<option value="' + WIKI_NOTE + '" selected>Shared</option>';
		} else {
			type += '<option value="' + WIKI_NOTE + '">Shared</option>';
		}
		if (defaultType == PRIVATE_NOTE) {
			type += '<option value="' + PRIVATE_NOTE + '" selected>Private</option>';
		} else {
			type += '<option value="' + PRIVATE_NOTE + '">Private</option>';
		}
		type += '<option value="">----------</option>';
		type += '<option value="about">ABOUT NOTE TYPES</option>';
		type += '</select>';

	
		color = '<select name="noteColor" onchange="top.NoteColorMenuChanged(this)">';
		color += '<option value="">Note Color:</option>';
		color += '<option value="">-------</option>';
		for (var i = 0; i < noteColorNames.length; ++i) {
			var colorName = noteColorNames[i];
			color += '<option value="' + colorName + '"'
			if (note.colorName == colorName) {
				color += ' selected';
			}
			color += '>' + colorName + '</option>';
		}
		color += '</select>';

		addNoteFormString = '<form style="padding:0; margin:0" name="addNoteForm">'
			+ '<table border="0" cellspacing="0" cellpadding="0" style="margin:0">\r<tr>'
			+ '<td style="padding:0; border-width:0">' + icon + '</td>\r'
			+ '<td style="border-width:0; padding:0 10px; text-align:center; vertical-align:bottom">' + set + '</td>\r'
			+ '<td style="padding:0; border-width:0; padding-right:10px; text-align:center; vertical-align:bottom">' + type + "</td>\r";

		// For everything except corrections notes, we want a menu to choose note color
		if (noteBeingEdited.noteText == "" || !IsCorrectionsNote(note)) {
			addNoteFormString += '<td style="padding:0; border-width:0; text-align:center; vertical-align:bottom">' + color + "</td>\r";
		}
			
		// if this is a corrections note, we need to add radio buttons to the form
		
		// noteBeingEdited IS defined if we're coming here from ModifyNote()
		
		// if we're coming here from CreateNote(), this is not so.
		
		if (noteBeingEdited.noteText != "") {
			if (IsCorrectionsNote(noteBeingEdited)) {
				addNoteFormString += '\r<td style="padding:0; border-width:0; font-size:12px; text-align:center; vertical-align:bottom; white-space:nowrap">';
				addNoteFormString += '<nobr>&nbsp;&nbsp;';
				addNoteFormString += '&nbsp;O<input type="radio" name="correctionStatus" value="0"';
				
				if (noteBeingEdited.correctionStatus == 0) {
					addNoteFormString += ' checked';
				}
				addNoteFormString += '>';
				addNoteFormString +=  '&nbsp;FS<input type="radio" name="correctionStatus" value="1"';
				if (noteBeingEdited.correctionStatus == 1) {
					addNoteFormString += ' checked';
				}
				addNoteFormString += '>';
				addNoteFormString +=  '&nbsp;FH<input type="radio" name="correctionStatus" value="3"';
				if (noteBeingEdited.correctionStatus == 3) {
					addNoteFormString += ' checked';
				}
				addNoteFormString += '>';
				addNoteFormString +=  '&nbsp;C<input type="radio" name="correctionStatus" value="2"';
				if (noteBeingEdited.correctionStatus == 2) {
					addNoteFormString += ' checked';
				}


				addNoteFormString += '></nobr></td>';

						
				addNoteFormString += '</tr><tr><td>&nbsp;</td><td><select name="firstStatus" style="width:175px">';

				for (j = 0; j < firstStatusTypes.length; j++) {
					addNoteFormString += '<option value="' + j + '"';
					if (noteBeingEdited.firstStatus == j) {
						addNoteFormString += " selected";
					}
					addNoteFormString += '>' + firstStatusTypes[j] + '</option>';
				}
	
				addNoteFormString += '</select></td>';

				addNoteFormString += '<td><select name="secondStatus" style="width:175px">';

				for (j = 0; j < secondStatusTypes.length; j++) {
					addNoteFormString += '<option value="' + j + '"';
					if (noteBeingEdited.secondStatus == j) {
						addNoteFormString += " selected";
					}
					addNoteFormString += '>' + secondStatusTypes[j] + '</option>';
				}

				
				addNoteFormString += '</select></td>';


			}
			// also need to pass submitterName
			addNoteFormString += '<input type="hidden" name="submitterName" value="' + submitterName + '">';
		
		}
		
		addNoteFormString += '</tr></table></form>';
		//alert("addNoteFormString = " + addNoteFormString);
		return addNoteFormString;

	// Else just return the text -- this is used by WriteNotes()
	} else {
		set = noteSets[note.setIndex].setName;
		
		if (IsCorrectionsNote(note)) {
			type = "";
		} else if (note.noteType == PRIVATE_NOTE) {
			type = " (Private)";
		} else if (note.noteType == WIKI_NOTE) {
			type = " (Shared)";
		} else {
			type = " (Public)";
		}

		return icon + ' <b>' + set + '</b>' + type + ':';
	}
}

function NoteTypeMenuChanged(menu) {
	if (menu.options[menu.selectedIndex].value == 'about') {
		Help('notesharing');
		menu.options[0].selected = true;
	} else if (menu.options[menu.selectedIndex].value == "") {
		menu.options[0].selected = true;
	}
}

function NoteColorMenuChanged(menu) {
	var noteColorName = menu.options[menu.selectedIndex].value;
	noteBeingEdited.colorName = noteColorName;
	if (IsStickyNote(noteBeingEdited)) {
		main.document.getElementById("stickyNoteInner" + noteIndexBeingEdited).style.backgroundColor = "#" + NoteColor(noteBeingEdited);
		main.document.getElementById("stickyNoteTitle" + noteIndexBeingEdited).style.backgroundColor = "#" + NoteTitleColor(noteBeingEdited);
		main.document.getElementById("stickyNoteTitleClose" + noteIndexBeingEdited).style.backgroundColor = "#" + NoteTitleColor(noteBeingEdited);
	}
	main.document.getElementById('note' + noteIndexBeingEdited).style.backgroundColor = "#" + NoteColor(noteBeingEdited);
}

// Format the given note text, expanding some special tags
function FormatNote(text) {
//	if (text == null) {
//		return "";
//	}

		if (bookId == 'life') {

		// IML photos (life)
		text = text.replace(/<IMLphoto number="(\d+).(\d+)">/g, 
				'<div style="padding:8px 0px; text-align:center">'
				+ '<img src="http://life7eiml.sinauer.com/ebook_supplemental/'
				+ 'SuppPhoto$1-$2.jpg">'
				+ '</div>'
			);
		
		// IML videos (life)
		text = text.replace(/<IMLvideo number="(\d+).(\d+)">/g, 
				'<div style="padding:8px 0px; text-align:center">'
				+ '<object classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" width="352" height="254" codebase="http://www.apple.com/qtactivex/qtplugin.cab">'
				+ '<param name="src" value="http://life7eiml.sinauer.com/Videos/' 
				+ 'Video-$1-$2.mpg' 
				+ '"><param name="controller" value="true"><param name="autoplay" value="false">'
				+ '<param name="kioskmode" value="true">'
				+ '<embed src="http://life7eiml.sinauer.com/Videos/' 
				+ 'Video-$1-$2.mpg' 
				+ '" autoplay="false" width="352" height="254" controller="true" kioskmode="true" pluginspace="http://www.apple.com/quicktime/download/"></embed>'
				+ '</object>'
				+ '</div>'
			);
		
	} else if (bookId == 'life8e') {
	
	
		// IML photos (life8e)
		text = text.replace(/<IMLphoto number="(\d+).(\d+)">/g, 
				'<div style="padding:8px 0px; text-align:center">'
				+ '<img src="http://life8eiml.sinauer.com/ebook_supplemental/'
				+ 'SuppPhoto$1-$2.jpg">'
				+ '</div>'
			);
		
		// IML videos (life8e)
		text = text.replace(/<IMLvideo number="(\d+).(\d+)">/g, 
				'<div style="padding:8px 0px; text-align:center">'
				+ '<object classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" width="352" height="254" codebase="http://www.apple.com/qtactivex/qtplugin.cab">'
				+ '<param name="src" value="http://life8eiml.sinauer.com/Videos/' 
				+ 'Video-$1-$2.mpg' 
				+ '"><param name="controller" value="true"><param name="autoplay" value="false">'
				+ '<param name="kioskmode" value="true">'
				+ '<embed src="http://life8eiml.sinauer.com/Videos/' 
				+ 'Video-$1-$2.mpg' 
				+ '" autoplay="false" width="352" height="254" controller="true" kioskmode="true" pluginspace="http://www.apple.com/quicktime/download/"></embed>'
				+ '</object>'
				+ '</div>'
			);
		
	}


	// User-uploaded images
	text = text.replace(/<UserImage name="([^"]+)">/g,
			'<div style="padding:8px 0px; text-align:center">'
			+ '<img src="' + urlStart + 'notes/useruploads/$1">'
			+ '</div>'
		);
	
	// User-uploaded documents
	text = text.replace(/<UserDocument name="([^"]+)" description="([^"]+)">/g,
			'<a href="' + urlStart + 'notes/useruploads/$1" target="_blank">$2</a>'
		);
	
	// Links: add 'target="_blank"' to *legacy* links,
	// UNLESS it's a javascript link.  We detect this by making sure
	// the href attribute starts with "h" ("http"). Checking for href right after
	// <a ensures it's a legacy link.
	text = text.replace(/(<a href="h[^"]+")/g, '$1 target="_blank"');	//"
	
	// Now add class ba to ALL links
	text = text.replace(/<a /g, '<a class="ba" ');
	
	return text;
}


// Add a note to a section
function RegisterNote(noteId, setIndex, section, noteText, noteType, stuckTo, colorName) {
	var notedSection = sections[section];
	
	if (notedSection == null) {
		return;
	}

	// Create the notes array first if necessary
	if (notedSection.notes == null) {
		notedSection.notes = new Array();
	}
	
	// Create and assign properties to the object
	var newNote = new Object();
	newNote.noteId = noteId;
	newNote.setIndex = setIndex;
	newNote.noteText = noteText;
	newNote.noteType = noteType;
	if (stuckTo == "") {
		newNote.stuckTo = null;
	} else {
		// A sticky note
		newNote.stuckTo = stuckTo;
		
		// For now, initialize the positional settings; we need to save these and retrieve them here eventually...
		InitializeStickyNoteSettings(newNote);
	}
	
	// default color is blue
	if (colorName != null && colorName != "") {
		newNote.colorName = colorName;
	} else {
		newNote.colorName = "blue";
	}
	
	// Put the object in the array
	var newIndex = notedSection.notes.length;
	notedSection.notes[newIndex] = newNote;
	
	// Return the index of the object just created
	return newIndex;
}

// this writes radio buttons  -- writing of radio buttons in NoteHeader function
// could use this too if we generalized it to accept "other attributes" argument (for onClick, etc.)
function WriteRadioButtonCode (noteIndex, correctionStatus, firstStatus, secondStatus) {

	if (firstStatus == null) {
		firstStatus = 0;
	}
	if (secondStatus == null) {
		secondStatus = 0;
	}

codeString = '<nobr>&nbsp;&nbsp;&nbsp;O<input type="radio" name="correctionStatus" value="0" onClick="top.SaveCorrectionsNote(' + noteIndex + ', 0,' + firstStatus + ',' + secondStatus + ');"';
if (correctionStatus == 0) {
	codeString = codeString + ' checked';
}
codeString = codeString + '>';
codeString = codeString + '&nbsp;FS<input type="radio" name="correctionStatus" value="1" onClick="top.SaveCorrectionsNote(' + noteIndex + ', 1,' + firstStatus + ',' + secondStatus + ');"';
if (correctionStatus == 1) {
	codeString = codeString + ' checked';
}
codeString = codeString + '>';
codeString = codeString + '&nbsp;FH<input type="radio" name="correctionStatus" value="3" onClick="top.SaveCorrectionsNote(' + noteIndex + ', 3,' + firstStatus + ',' + secondStatus + ');"';
if (correctionStatus == 3) {
	codeString = codeString + ' checked';
}
codeString = codeString + '>';
codeString = codeString + '&nbsp;C<input type="radio" name="correctionStatus" value="2" onClick="top.SaveCorrectionsNote(' + noteIndex + ', 2,' + firstStatus + ',' + secondStatus + ');"';
if (correctionStatus == 2) {
	codeString = codeString + ' checked';
}
codeString = codeString + '></nobr>';
		
return codeString;

}

// this writes additional corrections drop downs
function WriteCorrexDropDowns(noteIndex, firstStatus, secondStatus) {

	//alert("firstStatus = " + firstStatus + " secondStatus = " + secondStatus);

	if (firstStatus == null) {
		firstStatus = 0;
	}
	if (secondStatus == null) {
		secondStatus = 0;
	}

	// put status types in an array
	var firstStatusTypes = new Array ("Correction/bug Category","eBook text does not match printed text, but should: typo/missing content","eBook text needs to vary from printed text, but doesn't: needs editorial input","Misplaced figure, box, or margintext","Style/design issue","TOC issue","Broken link to supplemental activity","Broken internal link (e.g. to section or chapter)","Page number link goes to wrong content","Missing link");
	var secondStatusTypes = new Array ("Correction/bug Severity","Major error/bug -- must be fixed","Minor error/bug -- should be fixed","Suggestion/Question");	
			
	codeString = '<br><select name="firstStatus" style="width:175px" onChange="firstStatus = this.selectedIndex; top.SaveCorrectionsNote(' + noteIndex + ', ' + correctionStatus + ', this.selectedIndex, ' + secondStatus + ');">';

	for (j = 0; j < firstStatusTypes.length; j++) {
		codeString += '<option value="' + j + '"';
		if (firstStatus == j) {
			codeString += " selected";
		}
		codeString += '>' + firstStatusTypes[j] + '</option>';
	}
	
	codeString += '</select>&nbsp;&nbsp;&nbsp;';

	codeString += '<select name="secondStatus" style="width:175px" onChange="firstStatus = this.selectedIndex; top.SaveCorrectionsNote(' + noteIndex + ', ' + correctionStatus + ', ' + firstStatus + ', this.selectedIndex);">';

	for (j = 0; j < secondStatusTypes.length; j++) {
		codeString+= '<option value="' + j + '"';
		if (secondStatus == j) {
			codeString += " selected";
		}
		codeString += '>' + secondStatusTypes[j] + '</option>';
	}

				
	codeString += '</select>';

//alert("codeString = " + codeString);
return codeString;

}
	

function noteorder(a,b) { 
	// a or b could be null
	if (a == null) {
		return 1;
	}
	if (b == null) {
		return -1;
	}
	
	return (a.noteText.charCodeAt(0) - b.noteText.charCodeAt(0)) 
}
	
// called from each html page
// For historical reasons this function is called WriteNotes, but really
// it writes more than just the notes.
function WriteNotes() {
	var s = sections[curSection];

	if (s == null) {
		return;
	}
	
	// Reset noteBeingEdited
	noteBeingEdited = null;
	
	// Write the pop-in window code
	WritePopInWindow_ebook();
	
	if (top.bannerminimizeF == null) {
		if (IsCustomSection()) {
			// KC: these are not highlightable, and if we're in a custom section we don't show custom section options, so...
			main.document.write('<div class="noteLinkDiv"><a class="noteLink" href="Javascript:top.ShowPageOptions()" title="Show note options for this page">[Notes]</a></div>');
		} else {
			// Write the eBook tools link for angel
			if (angelStyle == 1) {
				WriteToolsMenuLink();
			// or the [Notes/Highlighting] link for standalone
			} else {
				main.document.write('<div class="noteLinkDiv"><a class="noteLink" href="Javascript:top.ShowPageOptions()" title="Show note, highlighting, and custom section options for this page">[Notes/Highlighting]</a></div>');
			}
		}
	}

	// Start the bodyholder div for the notes and the rest of the page
	main.document.write('<div class="bodyHolder2">');
	
	// Start a div for all notes, even if we don't have any yet
	main.document.write('<div id="notesDiv">');
	
	// Add a div to hold sticky note links
	main.document.write('<div id="stickyNoteLinksDiv" style="padding-bottom:5px; display:none"></div>');
	
	// initialize some stickyNotes vars
	stickyNotesForPage = new Array();
	stickyNoteIndex = 0;
	currentlyFocusedStickyNote = null;
	stickyNoteZIndex = 700;

	// If any notes are present, write it/them
	if (s.notes != null) {
		// if this is a corrections set, we need to sort so that outstandings appear first, then fixed, then confirmed
		for (var j = 0; j < s.notes.length; ++j) {
			if (s.notes[j] == null) {
				continue;
			}
			if (IsCorrectionsNote(s.notes[j])) {
				s.notes.sort(noteorder);
				break;
			}
		}		
	
		// Go through each note
		// var firstNoteWritten = false;
		for (var j = 0; j < s.notes.length; ++j) {
			// can't do sticky notes now
			if (s.notes[j] != null && !IsStickyNote(s.notes[j])) {
				main.document.write(NoteHTML(s, j));
			}
		}
	}
	
	// Write the noteEditor, for creating new notes and modifying old ones
	main.document.write('<div id="noteEditor" style="margin-top:5px;display:none">');
	// WriteRightEditorBtns('top.EditNote');
	// note tb="eBookNotes", for angelstyle fck editor
	var taWidth = textFarRight - 60;	// width has to be at least 490 pixels
	if (taWidth < 490) {
		taWidth = 490;
	}
	// Let's just make taWidth always 490, shall we?
	taWidth = 490;
	
	main.document.write('<textarea tb="eBookNotes" id="noteTA" style="width:' + (taWidth) + 'px; height:250px; font-size:12px; font-family:Verdana, Arial, sans-serif"></textarea>');
	
	// Buttons are on the bottom now, for everything
	// Have to add this empty line; otherwise IE screws up the button positioning
	// I made top -5px below to compensate.
	main.document.write('&nbsp;');
	
	main.document.write('<div id="noteEditorButtonsNew" style="position:relative; top:0px; height:', btnHeight, 'px">');	
	WriteBtn(3, "<b>SAVE</b>", "top.EditNoteStop(true)", 0, 0, "");
	WriteBtn(2, "<b>Clear</b>", "top.EditNoteClear()", btnWidth + btnExtraMargin, 0, "");
	WriteBtn(2, "<b><span id='noteEditorRevertButton2'>Revert</span></b>", "top.EditNoteStop(false)", btnWidth*2 + btnExtraMargin*2, 0, "");
	WriteBtn(2, "<b>Delete</b>", "top.EditNoteDelete()", btnWidth*3 + btnExtraMargin*3, 0, "");
	main.document.write('</div>');

	main.document.write('</div>');
	
	// Close the notes div
	main.document.write('</div>');
}

function NoteHTML(s, j) {
	var theNote = s.notes[j]
	var html = "";

	if (IsCorrectionsNote(theNote)) {
		// extract status and submitter name from note text
		correctionStatus = theNote.noteText.substr(0, 1);
		// we need to make this backwards compatible with old system (where corrections notes had the form #username|noteText)
		// ie, if it's of that form, we'll need to insert two zeroes for firstStatus and secondStatus
		if (theNote.noteText.substr(0,2).match(/^\d[a-zA-Z]/)) {
			// then this is old type
			// alert("old type correx note");
			theNote.noteText = theNote.noteText.substr(0,1) + "00" + theNote.noteText.substr(1);
		} else {
			// alert("new type correx note");
		}
		firstStatus = theNote.noteText.substr(1,1);
		secondStatus = theNote.noteText.substr(2,1);
		//alert("noteText = " + theNote.noteText);
		//alert("firstStatus = " + firstStatus);
		//alert("secondStatus = " + secondStatus);

		if (isNaN(firstStatus)) {
		//	alert("error: firstStatus is not a number");
		}

		var endExtractIndex = theNote.noteText.indexOf("|") - 3;
		//alert("endExtractIndex = " + endExtractIndex);
		if (endExtractIndex <= 0) {
			// this is bad
			alert("Problem with note formatting: " + theNote.noteText);
		}
		var submitterName = theNote.noteText.substr(3, endExtractIndex);
		
		//alert("submitterName = " + submitterName);
		// we'll add firstStatus and secondStatus (see WriteCorrexDropDowns) here
		var notePrefix = correctionStatus + firstStatus + secondStatus + submitterName + "|";
		var lengthNotePrefix = notePrefix.length;
		
		// remove prefix from note text 
		var textWithoutPrefix = theNote.noteText.substr(lengthNotePrefix);
		
		// Color code note according to status
		var correctionsNoteStyle;
		if (correctionStatus == 0) {
			// outstanding is red
			correctionsNoteStyle = "padding:10px; margin-bottom:5px; background-color:#ffcccc";
		} else if (correctionStatus == 1 || correctionStatus == 3) {
			// fixed is yellow
			correctionsNoteStyle = "padding:10px; margin-bottom:5px; background-color:#ffffcc";
		} else if (correctionStatus == 2) {
			// confirmed is green
			correctionsNoteStyle = "padding:10px; margin-bottom:5px; background-color:#ccffcc";
		} else {
			correctionsNoteStyle = noteStyle;
		}
		
		// Start the note div
		html += ('<div id="note'+ j+ '" style="'+ correctionsNoteStyle+ '">');
		
		// start the noteHeader div
		
		// Write the icon + noteset + submitterName
		// We need a dummy form here so that the radio buttons act properly
		html += ('<div id="noteHeader' + j + '">'
			+ '<form name="dummyForm'+ j+ '" style="margin:0; padding:0">'
			+ NoteHeader(j, theNote, 'text')
			+ submitterName);
			
		// RADIO BUTTONS O ¥ F ¥ C ¥
		html += WriteRadioButtonCode(j, correctionStatus, firstStatus, secondStatus);

		// Two more drop-downs for corrections notes
		html += WriteCorrexDropDowns(j, firstStatus, secondStatus);
		//alert(html);
		
		// view all corrections link
		// html += ('&nbsp;&nbsp;&nbsp;<a href="JavaScript:top.OpenSupp(\'notes\',0)">[View All Corrections]</a>');
		
		// End the form
		html += ('</form>');
		// end the noteHeader div
		html += ('</div>');
		
		// Write the content in a noteContent div
		html += ('<div id="noteContent'+ j+ '">'+ FormatNote(textWithoutPrefix)+ '</div>');

		// End the note div
		html += ('</div>');

		// now clear out correctionStatus for new note
		correctionStatus = null;
		firstStatus = null;
		secondStatus = null;
	
	// Normal (non-corrections) note
	} else {
		//////////////////// This is code for normal note
		
		// Start the note div -- use the note's color
		html += ('<div id="note' + j + '" style="' + noteStyle + '; background-color:' + NoteColor(theNote) + '">');
		
		// Write the icon + noteset
		html += ('<div id="noteHeader' + j + '">'
			+ NoteHeader(j, theNote, 'text')
			+ '</div>'
			);
		
		// Write the content in a noteContent div
		html += ('<div id="noteContent' + j + '">' + FormatNote(theNote.noteText) + '</div>');	

		// End the note div
		html += ('</div>');
		//////////////////// End code for normal note
	}
	
	return html;
}

 function WriteAllNotesInternal (newWindow, win, start, end, correctionStatus, firstStatus, secondStatus) {
	var notesWritten = 0;
	for (var s = start; s < end; ++s) {
		// If the section is valid and has note(s), write it/them
		if (sections[s] != null && sections[s].notes != null) {
			var secString = "";
			
			// Enclose the section's note(s) in a pseudo-bullet point
			secString += '<table cellspacing="0" cellpadding="0" border="0" width="100%"><tr><td width="10" valign="top"><b>&bull;&nbsp;</b></td><td>';
			
			// Write an appropriate heading for the page, 
			// in a hyperlink to open the book to the page
			if (newWindow) {
				secString += '<b><i>';
			} else {
				secString += '<a href="javascript:top.LoadSection(' + s + ')">';
			}

			if (s == 1) {
				secString += 'Table of Contents';
			} else {
				// if there is a bookmark title, use it instead
				if (sections[s].bt != null) {
					secString += sections[s].bt;
				} else {
				
					switch (bookId)
					{
						case "listen6e":
							var sn = SectionNumber(s);
							var dot = sn.indexOf(".");
							var cn = sn.substring(0,dot);
	   					if (cn>=24) {
								sn = sn.substr(dot+1);
	   						sn = listen6e_chapname[cn-24]; //listen6e_chapname defined at top of this file
	   					} 						
							secString += sn;
							break;

						default:
							secString += 'Section ' + SectionNumber(s);
					}
				
				
				}
						
			}
			if (newWindow) {
				secString += '</i></b>';
			} else {
				secString += '</a>';
			}
			secString += '<br>';
			
			for (var j = 0; j < sections[s].notes.length; ++j) {
				var note = sections[s].notes[j];
				
				if (note == null) {
					continue;
				}
				if (correctionStatus == null) {
					if (IsCorrectionsNote(note)) {
						continue;
					}
				} else {
					if (!IsCorrectionsNote(note) || note.noteText.charAt(0) != correctionStatus) {
						continue;
					}
				}
					
				
				if (note.noteText == "") {
					continue;
				}
				
				// At this point we know we're going to write at least one note
				if (notesWritten == 0) {
					// Enclose corrections notes in a bordered div
					if (correctionStatus == 0) {
						win.document.write('<div style="border:4px solid #ff0000; padding:5px; margin-bottom:10px">');
					} else if (correctionStatus == 1 || correctionStatus == 3) {
						win.document.write('<div style="border:4px solid #cccc00; padding:5px; margin-bottom:10px">');
					} else if (correctionStatus == 2) {
						win.document.write('<div style="border:4px solid #008000; padding:5px; margin-bottom:10px">');
					}
				}
				++notesWritten;
				
				if (secString != "") {
					win.document.write(secString);
					secString = "";
				}
				// Write the set name and the note
				
				// for corrections notes, need to strip off prefix from note.noteText
				var endOfPrefix = note.noteText.indexOf('|') + 1;
				if (correctionStatus != null) {
					var textWithoutPrefix = note.noteText.substr(endOfPrefix);
					
				}
				
				noteBullet = "";
				// and add color
				if (correctionStatus == 0) {
					// outstanding is red
					noteBullet = "<span style='background-color:#ff0000'>&nbsp;&nbsp;</span>&nbsp;";
				} else if (correctionStatus == 1 || correctionStatus == 3) {
					// fixed is yellow
					noteBullet = "<span style='background-color:#cccc00'>&nbsp;&nbsp;</span>&nbsp;";
				} else if (correctionStatus == 2) {
					// confirmed is green
					noteBullet = "<span style='background-color:#008000'>&nbsp;&nbsp;</span>&nbsp;";
				} 
				
				// if corrections note, print textWithoutPrefix, otherwise normal noteText
				if (correctionStatus != null) {
					win.document.write('<b>', noteSets[note.setIndex].setName, ':</b><br>', noteBullet, FormatNote(textWithoutPrefix));
				} else {
					win.document.write('<b>', noteSets[note.setIndex].setName, ':</b><br>', noteBullet, FormatNote(note.noteText));
				}

				win.document.write('<hr>');
			}
			
			// Close bullet point for note(s)
			win.document.write('</td></tr></table>');
		}
		

	}
	
	// Write number of corrections and close div for corrections notes
	if (correctionStatus != null && notesWritten > 0) {
		var typeString = "";
		if (correctionStatus == 0) {
			typeString = "outstanding";
		} else if (correctionStatus == 1 || correctionStatus == 3) {
			typeString = "fixed";
		} else if (correctionStatus == 2) {
			typeString = "confirmed";
		}
		win.document.write('Total number of <b>' + typeString + '</b> corrections: <b>' + notesWritten + '</b>');
		win.document.write('</div>');
	}
	return (notesWritten > 0);
}



// Write all notes (student's and subscribed) for chapter c in the supplemental window.  
// This function is called from the body of allnotes.html, which is opened by 
// the function OpenAllNotes().
function WriteAllNotes(c, newWindow) {
	var win;
	
	// If newWindow is true, open a new window
	if (newWindow) {
		win = window.open('', "Notes", "top=10,left=10,width=600,height=500,menubar,resizable,scrollbars,status", true);
		win.document.open();
		win.document.write('<html><head><style type="text/css">li {margin-bottom:10px} body {margin:10px}</style><title>Notes</title></head><body>');

		// Start the document
		win.document.write('<b>', firstName, " ", lastName, '</b><br>');
		win.document.write(new Date().toLocaleString(), "<br><br>");
		if (c == 0) {
			if (bookId == "expmod") {
				win.document.write('Notes for all modules:<br>');
			} else {
				win.document.write('Notes for all chapters:<br>');
			}
		} else {
			win.document.write('Notes for Chapter ', c, ':<br>');
		}
		
	} else {
		win = sw.main;

		// Start the document
		win.document.write('<table cellspacing="0" cellpadding="0" border="0" width="100%"><tr><td>');
		if (c == 0) {
			if (bookId == "expmod") {
				win.document.write('<h3>Notes for all modules:<\/h3><\/td><td align="right">');			
			} else {
				win.document.write('<h3>Notes for all chapters:<\/h3><\/td><td align="right">');
			}
		} else {
			/*if (bookId == "expmod") { //original code in this else block
				win.document.write('<h3>Notes for Module ', c, ':<\/h3><\/td><td align="right"><a style="font-size:12px" href="JavaScript:top.opener.OpenSupp(\'notes\',0)">[Show all notes]<\/a>&nbsp;');
			} else {
				win.document.write('<h3>Notes for Chapter ', c, ':<\/h3><\/td><td align="right"><a style="font-size:12px" href="JavaScript:top.opener.OpenSupp(\'notes\',0)">[Show all notes]<\/a>&nbsp;');
			}*/
			switch (bookId)
			{
			  case "expmod":
   				win.document.write('<h3>Notes for Module ', c, ':<\/h3><\/td><td align="right"><a style="font-size:12px" href="JavaScript:top.opener.OpenSupp(\'notes\',0)">[Show all notes]<\/a>&nbsp;');
   				break;
   				
   			case "listen6e":
   				//chap# in listen6e_source.xml: 24   25        26         27        28       29        30            31
   			  //var listen6e_chapname = new Array ("Unit I","Unit II","Unit III","Unit IV","Unit V","Prelude","Interlude A","Interlude B")   			  
   			  var cname;
   			  if (c>=24) { 
   			    cname = listen6e_chapname[c-24]; 
   			  } else {
   			    cname = "Chapter " + c;
   			  }
  				win.document.write('<h3>Notes for ', cname, ':<\/h3><\/td><td align="right"><a style="font-size:12px" href="JavaScript:top.opener.OpenSupp(\'notes\',0)">[Show all notes]<\/a>&nbsp;');
          break;

			 case "elrod2":
   			   var cname;
   			     cname = elrod2_chapname[c];
  			         win.document.write('<h3>Notes for ', cname, ':<\/h3><\/td><td align="right"><a style="font-size:12px" href="JavaScript:top.opener.OpenSupp(\'notes\',0)">[Show all notes]<\/a>&nbsp;');
          break;

          
        default :
			    win.document.write('<h3>Notes for Chapter ', c, ':<\/h3><\/td><td align="right"><a style="font-size:12px" href="JavaScript:top.opener.OpenSupp(\'notes\',0)">[Show all notes]<\/a>&nbsp;');
			} //end switch bookId
		}
		win.document.write('<a style="font-size:12px" href="JavaScript:top.opener.WriteAllNotes(', c, ',true)">[Printable version]<\/a>');
		win.document.write('</td></tr></table>');
	}
	
	var somethingWritten = false;
	
	// Go through all sections in the chapter (or the book)
	var start, end;
	if (c == 0 || c == null) {
		start = 0;
		end = sections.length;
	} else {
		start = c * 100;
		end = start + 98;
	}
	
	
	// This outputs all outstanding corrections by section, then all fixed corrections, etc. then normal notes
	somethingWritten = WriteAllNotesInternal(newWindow,win,start,end,0) || somethingWritten;
	somethingWritten = WriteAllNotesInternal(newWindow,win,start,end,1) || somethingWritten;
	somethingWritten = WriteAllNotesInternal(newWindow,win,start,end,2) || somethingWritten;
	somethingWritten = WriteAllNotesInternal(newWindow,win,start,end,null) || somethingWritten;
	

	// If no notes written, send a message to this effect.
	if (!somethingWritten) {
		if (c == 0 || c == null) {
			win.document.write('<p>No notes on file.</p>');
		} else {
			if (bookId == "expmod") {
				win.document.write('<p>No notes on file for this module.</p>');
			} else if (bookId == "elrod2") {
			   	var cname;
   				cname = elrod2_chapname[c];
				win.document.write('<p>There are no notes on file for ', cname, '.</p>');
			} else {
				win.document.write('<p>No notes on file for this chapter.</p>');
			}
		}
	}
	
	// If we're writing a new window, close it
	if (newWindow) {
		win.document.write('</body></html>');
		win.document.close();
	}
}

var noteColorNames = new Array("blue", "green", "yellow", "orange", "pink", "purple", "gray", "white");
var noteColorVals = {blue:"ccccff", green:"b2ffa1", yellow:"fef49c", orange:"FFCC66", pink:"ffc7c7", purple:"cc66ff", gray:"dddddd", white:"ffffff"};
var noteTitleVals = {blue:"666699", green:"529941", yellow:"ffcc00", orange:"ff6600", pink:"cc3300", purple:"663366", gray:"777777", white:"000000"};
function NoteColor(n) {
	if (n.colorName != null) {
		return noteColorVals[n.colorName];
	} else {
		return noteColorVals['blue'];
	}
}

function NoteTitleColor(n) {
	if (n.colorName != null) {
		return noteTitleVals[n.colorName];
	} else {
		return noteTitleVals['blue'];
	}
}

// Return a pointer to the fck note editor
function GetFCKEditor() {
	var fe = main.FCKeditorAPI;
	if (fe != null) {
		return fe.GetInstance('noteTA');
	} else {
		return null;
	}
}

// *************************************************************
function ______PAGE_OPTION_POPIN______() {}


function ShowPageOptions() {

	var optionText = '';
	if (!IsCustomSection()) {
		optionText += '<div style="padding-bottom:3px; margin-bottom:3px; border-bottom:1px solid #000000">';
	} else {
		optionText += '<div style="padding-bottom:3px; margin-bottom:3px">';
	}
	
	optionText += '&raquo;&nbsp;<a class="ba" href="JavaScript:top.AddNoteStart()">Add Top Note</a><br>'
		+ '&raquo;&nbsp;<a class="ba" href="JavaScript:top.InitiateStickyNote()">Add Sticky Note</a>&nbsp;<a style="color:#900; font-size:80%" href="javascript:top.StickyNoteBetaMessage()">BETA</a><br>'
		+ '&raquo;&nbsp;<a class="ba" href="JavaScript:top.ModifyNoteStart()">Modify Note</a><br>';
	
	// Can't create custom section for custom sections or for title page
	if (!IsCustomSection() && curSection >= MAIN_TOC) {
		optionText += '&raquo;&nbsp;<a class="ba" href="JavaScript:top.GetCustomSectionOptions()">Add Custom Section</a><br>'
	}
	
	optionText += "</div>";
	
	
	// KC: Can't add highlighting in custom sections either
	if (!IsCustomSection()) {
		
		optionText += '&raquo;&nbsp;<a class="ba" href="JavaScript:top.ShowHighlightingInstructions()">Add Highlighting</a><br>'
				   + '&raquo;&nbsp;<a class="ba" href="JavaScript:top.ClearHighlighting()">Clear Highlighting</a>'
		           ;
		
		// PW: add ability to add supplemental links, if we're on the staging server
		// and the user has a pro account
		if (urlStart.indexOf("staging") > 0 && accountType == "pro") {
			optionText += SupplementLinkOptionText();
		}
	} 
	
	if (!IsCustomSection()) {
		ShowPopInWindow_ebook("Note/Highlighting Options", optionText , null, 220, 55, 350);
	} else {
		ShowPopInWindow_ebook("Note Options", optionText , null, 220, 55, 350);
	}
}


function ModifyNoteStart() {
	// If we're already entering/editing a note, can't modify something else
	if (noteBeingEdited != null) {
		ShowPopInWindow_ebook("Modifying Notes"
			, "You will have to finish the note you're working on now before modifying another note."
			, null, 300);
		return;
	}

	// If the user has one and only one note on the page, call ModifyNote to edit it
	var noteToModify = null;
	// Go through the notes
	var notes = sections[curSection].notes;
	if (notes != null) {
		for (var i = 0; i < notes.length; ++i) {
			// If we find one with a note...
			var note = notes[i];
			if (note != null) {
				if (noteSets[note.setIndex].type > 0 || note.noteType == WIKI_NOTE) {
					// ... then if noteToModify has already been set to an index, 
					// there are multiple notes, so we have to show an alert.
					if (noteToModify != null) {
						ShowPopInWindow_ebook("Modifying Notes"
							, "To modify a note, click the \"EDIT\" icon at the top-left of the note text."
							, null, 300);
						return;
					
					// ... else if noteToModify hasn't been set yet, set it.
					} else {
						noteToModify = i;
					}
				}
			}
		}
	}
	
	// If we made it through the above loop and noteToModify isn't still null,
	// modify that note
	if (noteToModify != null) {
		ModifyNote(noteToModify);
		// Also close the popin window
		ClosePopInWindow_ebook();

	// Else there aren't any notes to modify, so show an alert to this effect.
	} else {
		ShowPopInWindow_ebook("Modifying Notes"
			, "You don't have any notes on this page to modify."
			, null, 300);
	}
}


function AddNoteStart() {
	// If we're already modifying something, return
	if (noteBeingEdited != null) {
		alert("You must finish with the note you are already working on before modifying another note.");
		return;
	}
	
//	alert("bookId:" + bookId);

	// If the user won't be able to save notes, issue a warning
	if (username == 'guest' && !noteWarningIssued && bookId != "design") {
		alert ('You may enter notes while you\'re using the eBook in Preview mode, but the notes will not be recorded permanently -- as soon as you close the Textbook Window, your notes (and highlighting and bookmarks) will be lost.');
		noteWarningIssued = true;
	}
		
	CreateNote();
	return;

	// DEAD CODE
	
	// Get info about note sets
//	GetNoteSetInfo();
//	
//	var noteSetContent = "";
//	// If there are more than one modifiable sets,
//	// write a drop-down menu with the available note sets
//	if (modifiableSets > 1) {
//		noteSetContent = '&bull; Add your note to Annotation Set:<br>'
//		+ '&nbsp;&nbsp;&nbsp;' + GetNoteSetSelect()
//		+ '<br><br>'
//		;
//	}
//		
//	// Construct the form
//	var csForm =
//		'<form style="padding:0; margin:0" name="addNoteForm" onsubmit="top.CreateCustomSection();return false">'
//		
//		+ noteSetContent
//		
//		+ '&bull; Make your note:'
//		+ '<table border="0" cellspacing="0" cellpadding="0" style="margin:0">'
//		+ '<tr><td style="font-size:11px; white-space:nowrap; border:0; padding:0" align="right" valign="top">&nbsp;&nbsp;&nbsp;<input name="noteType" type="radio" value="public" checked> </td><td style="font-size:11px; border:0; padding:0 0 2px 0"><b>Public</b> (any subscribers to your Annotation Set will be able to <i>view, but not alter</i>, the note)</td></tr>'
//		+ '<tr><td style="font-size:11px; white-space:nowrap; border:0; padding:0" align="right" valign="top">&nbsp;&nbsp;&nbsp;<input name="noteType" type="radio" value="wiki"> </td><td style="font-size:11px; border:0; padding:0 0 2px 0"><b>Shared</b> (any subscribers to your Annotation Set will be able to <i>view and alter</i> the note)</td></tr>'
//		+ '<tr><td style="font-size:11px; white-space:nowrap; border:0; padding:0" align="right" valign="top">&nbsp;&nbsp;&nbsp;<input name="noteType" type="radio" value="private"> </td><td style="font-size:11px; border:0; padding:0"><b>Private</b> (only you will be able to view and alter the note)</td></tr>'
//		+ '</table>'
//
//		+ '</form>'
//		;
//	
//	ShowPopInWindow_ebook("Note Options"
//		, csForm
//		, '<a class="ba" href="JavaScript:top.CreateNote()">Create the Note</a>'
//		, 300);
}


function ShowHighlightingInstructions() {
	ShowPopInWindow_ebook("Adding Highlighting"
		, "Double-click any phrase in the text to highlight the phrase (the phrase will then appear on a yellow background). Double-click the phrase again to de-highlight it. Your highlighting will be automatically saved whenever you move to a new page of text."
		, null, 300);
}


function GetCustomSectionOptions() {
	// Guests can't create custom sections
	if (username == "guest") {
		alert("Preview users cannot create Custom Sections.");
		ClosePopInWindow_ebook();
		return;
	}
	
	// Get info about note sets
	GetNoteSetInfo();
	
	var noteSetContent = "";
	// If there are more than one modifiable sets,
	// write a drop-down menu with the available note sets
	if (modifiableSets > 1) {
		noteSetContent = '&bull; Add your custom section to Annotation Set:<br>'
		+ '&nbsp;&nbsp;&nbsp;' + GetNoteSetSelect()
		+ '<br><br>'
		;
	}
	
	var whereContent = "";
	// For the toc, before/after doesn't really make sense; just put them all after.
	if (curSection != MAIN_TOC) {
		whereContent = '&bull; Add your custom section:<br>'
			+ '&nbsp;&nbsp;&nbsp;<input name="customWhere" type="radio" value="before" checked> before or <input name="customWhere" type="radio" value="after"> after &nbsp;the current section.<br><br>'
		;
	}
	
// 		+ '&nbsp;&nbsp;&nbsp;<input name="customType" type="radio" value="public" checked> public, <input name="customType" type="radio" value="private"> private, or <input name="customType" type="radio" value="wiki"> shared<br><br>'
	
	// Construct the form
	var csForm =
		'<form style="padding:0; margin:0" name="customSectionForm" onsubmit="top.CreateCustomSection();return false">'
		
		+ noteSetContent
		
		+ '&bull; Make your custom section:'
		+ '<table border="0" cellspacing="0" cellpadding="0" style="margin:0">'
		+ '<tr><td style="font-size:11px; white-space:nowrap; border:0; padding:0" align="right" valign="top">&nbsp;&nbsp;&nbsp;<input name="customType" type="radio" value="public" checked> </td><td style="font-size:11px; border:0; padding:0 0 2px 0"><b>Public</b> (any subscribers to your Annotation Set will be able to <i>view, but not alter</i>, the section)</td></tr>'
		+ '<tr><td style="font-size:11px; white-space:nowrap; border:0; padding:0" align="right" valign="top">&nbsp;&nbsp;&nbsp;<input name="customType" type="radio" value="wiki"> </td><td style="font-size:11px; border:0; padding:0 0 2px 0"><b>Shared</b> (any subscribers to your Annotation Set will be able to <i>view and alter</i> the section)</td></tr>'
		+ '<tr><td style="font-size:11px; white-space:nowrap; border:0; padding:0" align="right" valign="top">&nbsp;&nbsp;&nbsp;<input name="customType" type="radio" value="private"> </td><td style="font-size:11px; border:0; padding:0"><b>Private</b> (only you will be able to view and alter the section)</td></tr>'
		+ '</table><br>'

		+ whereContent

		+ '&bull; Enter a title for your custom section:<br>'
		+ '&nbsp;&nbsp;&nbsp;<input name="customTitle" type="text" style="width:270px">'
		+ '</form>'
		;
	
	ShowPopInWindow_ebook("Custom Section Options"
		, csForm
		, '<a class="ba" href="JavaScript:top.CreateCustomSection()">Create the Custom Section</a>'
		, 300);
}


// *************************************************************
function ______EDITOR_FUNCTIONS______() {}

function WriteBtn(type, text, fn, left, top, jsFrame, width) {
	if (jsFrame == null) {
		jsFrame = "top.";
	} else if (jsFrame != "") {
		jsFrame = jsFrame + ".";
	}
	
	if (width == null || width == "") {
		width = 80;
	}
	
	main.document.write('<a class="noteBtn', type, 'A" href="Javascript:', jsFrame, fn, '"><div class="noteBtn', type, 'Div" style="position:absolute; width:', width, 'px; left:', left, 'px; top:', top, 'px"><table border="0" cellspacing="0" cellpadding="0" style="margin:0"><tr><td class="noteBtnTD" style="padding:0; border-width:0; width:', width, 'px"><a class="noteBtn', type, 'A" href="Javascript:', jsFrame, fn, '">', text, '</a></td></tr></table></div></a>');
}

var btnHeight = 27;		// 25 + 2 margin
var btnExtraMargin = 5;
var btnWidth = 82;	// 80 + 2 margin
function WriteRightEditorBtns(fnPrefix) {
	main.document.write('<div id="noteEditorButtons" style="position:absolute; left:' + (textFarRight + 5) + 'px;">');
	
	var lastBtnPosition = 0;

	WriteBtn(2, "<b>Clear</b>", fnPrefix + "Clear()", 0, lastBtnPosition, "");
	WriteBtn(2, "<b><span id='noteEditorRevertButton'>Revert</span></b>", fnPrefix + "Stop(false)", 0, lastBtnPosition + btnHeight, "");
	WriteBtn(3, "<b>SAVE</b>", fnPrefix + "Stop(true)", 0, lastBtnPosition + btnHeight * 2 + btnExtraMargin, "");
	
	main.document.write('</div>');
}

function ChangeNoteEditorRevertButton(val) {
	if (main.document.getElementById('noteEditorRevertButton') != null) {
		SwapInnerHTML(main.document.getElementById('noteEditorRevertButton'), val);
	}
	if (main.document.getElementById('noteEditorRevertButton2') != null) {
		SwapInnerHTML(main.document.getElementById('noteEditorRevertButton2'), val);
	}
}

function ChangeNoteEditorDeleteButton(val) {
	SetDisplay(main.document.getElementById('noteEditorDeleteButton'), val);
	SetDisplay(main.document.getElementById('noteEditorDeleteButton2'), val);
}

function AddBold() {
	var newText = prompt("Enter bold text:", "");
	if (newText == null) {
		return;
	}

	InsertText("<b>" + newText + "</b>");
}

function AddItalic() {
	var newText = prompt("Enter italic text:", "");
	if (newText == null) {
		return;
	}

	InsertText("<i>" + newText + "</i>");
}

function AddLink() {
	// CHANGE - TO . WHEN APPROPRIATE
	var url = prompt("Enter a URL, e.g. \"http://www.google.com\", for a link to an external website; or enter a section number, e.g. \"8-5\", for a link to that section of the eBook:", "");
	
	// Try to determine type and validity of link
	var linkType, text;

	// Nothing entered -- just return
	if (url == null) {
		return;

	// Outside link: starts with http
	} else if (url.substr(0, 4) == "http") {
		linkType = "external";
		text = "";
		
	// or, in all probability, www so we have to add http:// (KC)
	 } else if (url.substr(0, 3) == "www") {
		linkType = "external";
		text = "";
		url = "http://" + url;
		
	// Internal link: includes nothing but numbers or . or -
	} else if (!url.search(/^[\d\.-]/)) {
		linkType = "internal";
		text = "Section " + url;

	// brb - some sections begin with a letter or letters
	// C1, MLA-1a
	} else if (!url.search(/^[A-Za-z]+([\d]+)?(-[a-zA-Z0-9]+)?$/)) {
	    linkType = "internal";
	    text = "Section " + url;
	    
	// or it may be a JS reference, e.g. JavaScript:top.OpenSupp('syscheck')
	} else if (url.substr(0, 10) == "JavaScript") {
		linkType = "javascript";
		text = "";

	// something we can't parse
	} else {
		if (confirm("Your link could not be parsed. Links to outside sites must start with \"http\", and links to other sections must include only section numbers. Try again?")) {
			AddLink();
			return;
		} else {
			return;
		}
	}
	
	// Get the link text
	text = prompt("Enter link text, e.g. \"Gooooogle\" or \"Section 8.5\":", text);
	if (text == null) {
		return;
	}
	
	// If we make it to here we have a valid link, so insert it.
	if (linkType == "external")	{
		InsertText('<a href="' + url + '" target="_blank">' + text + '</a>');
	} else if (linkType == "internal") {
		InsertText('<a href="JavaScript:top.JumpToPageNumber(\'' + url + '\')">' + text + '</a>');
	} else {
		InsertText('<a href="' + url + '">' + text + '</a>');
	}
}

function AddImage() {
	var url = prompt("Enter the URL of the image, e.g. \"http://www.sinauer.com/images/covers175/8565.jpg\":", "");
	if (url == null) {
		return;
	}
	
	InsertText('<img src="' + url + '" border="0">');
}

function AddPhoto() {
	var num = prompt("Enter the Supplemental Photograph number from the IML catalog, e.g. \"08.002\":", "");
	if (num == null) {
		return;
	}
	
	InsertText('<IMLphoto number="' + num + '">');
}

function AddVideo() {
	var num = prompt("Enter the Video Sequence number from the IML catalog, e.g. \"08.03\":", "");
	if (num == null) {
		return;
	}
	
	InsertText('<IMLvideo number="' + num + '">');
}

// Upload an image or a file
function Upload(type) {
	// We have to send directly to the upload form processor on the eBook server...
	var formText = '<form style="padding:0; margin:0" name="fileForm" method="post" enctype="multipart/form-data" action="' + urlStart + 'notes/uploadNoteFile.php" target="servercomF">'
		+ '<input type="hidden" name="username" value="' + username + '">'
		
		// And specify a file to call once it's done to make the final js calls
		+ '<input type="hidden" name="returnurl" value="' + GetFilename(urlStart + 'notes/uploadNoteFileFinished.html') + '">';

	if (type == "Image") {
		formText +=
			'Click the "Browse"/"Choose File" button to select an image file to upload (gif and jpeg files are allowed).'
			+ '<div style="padding:4px 0"><input type="file" name="uploadedImage"></div>'
			+ '<div style="text-align:center"><input type="submit" name="submitBut" value="Submit" onclick="top.ContinueUpload(); return false">'
			+ '&nbsp;&nbsp;<input type="submit" name="submitBut" value="Cancel" onclick="top.CancelUpload(); return false"></div>'
			;
	} else {
		formText +=
			'Click the "Browse"/"Choose File" button to select a document to upload.'
			+ '<div style="padding:4px 0"><input type="file" name="uploadedDocument"></div>'
			+ '<div style="padding:4px 0">Document description (this will appear as the link text):<br><input type="text" name="docDesc" style="width:300px"></div>'
			+ '<div style="text-align:center"><input type="submit" name="submitBut" value="Submit" onclick="top.ContinueUpload(); return false">'
			+ '&nbsp;&nbsp;<input type="submit" name="submitBut" value="Cancel" onclick="top.CancelUpload(); return false"></div>'
			;
	}
	formText += '</form>';

	ShowPopInWindow_ebook(type + " Upload", formText , null, 400, null, null);
}

function WriteUploadFormStuff() {
	main.document.write('<input type="hidden" name="username" value="', username, '">');
}

function ContinueUpload() {
	main.document.fileForm.submit();
	ClosePopInWindow_ebook();
}

function CancelUpload(type) {
	ClosePopInWindow_ebook();
}

var textAreaToEdit = null;
function InsertText(text) {
	if (textAreaToEdit == null) {
		return;
	}
	
	// FCK version, added by PW 12/18
	// Deal with custom sectinons (4/8/2008)
	var fed;
	if (main.pageEditorTA != null) {
		fed = main.GetFCKPageEditor();
	} else {
		fed = GetFCKEditor();
	}
	if (fed != null) {
		fed.InsertHtml(FormatNote(text));
		return;
	}
	
	
	// var noteField = main.document.noteform.note;
	
	//IE support
	//if (document.selection) {
	//	textAreaToEdit.focus();
	//	sel = document.selection.createRange();
	//	sel.text = text;

	// KC: adapted from
	// http://the-stickman.com/web-development/javascript/finding-selection-cursor-position-in-a-textarea-in-internet-explorer/
	
	if( document.selection ) {

		document.selection.createRange().text = text;
		
//		
//		// The current selection
//        var range = document.selection.createRange();                                                 
//
//        // We'll use this as a 'dummy'
//        var stored_range = range.duplicate();                                                         
//
//        // Select all text
//        stored_range.moveToElementText( textAreaToEdit );                                             
//
//        // Now move 'dummy' end point to end point of original range
//        stored_range.setEndPoint( 'EndToEnd', range );                                                
//
//        // Now we can calculate start and end points
//        textAreaToEdit.selectionStart = stored_range.text.length - range.text.length;                 
//        textAreaToEdit.selectionEnd = textAreaToEdit.selectionStart + range.text.length;                    
//        
//        var startPos = textAreaToEdit.selectionStart;
//		var endPos = textAreaToEdit.selectionEnd;
//		textAreaToEdit.value = textAreaToEdit.value.substring(0, startPos)
//						+ text
//						+ textAreaToEdit.value.substring(endPos, textAreaToEdit.value.length);
//        
//
	//MOZILLA/NETSCAPE support
	} else if (textAreaToEdit.selectionStart || textAreaToEdit.selectionStart == '0') {
		var startPos = textAreaToEdit.selectionStart;
		var endPos = textAreaToEdit.selectionEnd;
		textAreaToEdit.value = textAreaToEdit.value.substring(0, startPos)
						+ text
						+ textAreaToEdit.value.substring(endPos, textAreaToEdit.value.length);
	} else {
		textAreaToEdit.value += text;
	}

	textAreaToEdit.focus();
}

// *************************************************************
function ______CUSTOM_SECTIONS______() {}

// Encode "section numbers" of custom sections as an offset + the csId 
// from the database
var customSectionOffset = 100000;	// Should allow for 1000 chapters

// Have to have a global newCS object to communicate between
// CreateCustomSection and CreateCustomSectionReturn
var newCS;
function CreateCustomSection() {
//	ShowPopInWindow_ebook("Custom Sections"
//		, 'Custom sections will be debuting soon...'
//		, null, 300);
//	return;
	
	var f = main.document.customSectionForm;

	var customSetIndex;
	GetNoteSetInfo();
	if (modifiableSets > 1) {
		customSetIndex = f.noteSet.value;
	} else {
		customSetIndex = firstModifiable;
	}
	
	var customType;
	if (f.customType[0].checked) {
		customType = PUBLIC_NOTE;
	} else if (f.customType[1].checked) {
		customType = WIKI_NOTE;
	} else {
		customType = PRIVATE_NOTE;
	}
	
	var customTitle = f.customTitle.value;

	var customWhere;
	// For the main TOC, only add cs's after -- we won't have written the radio button above.
	if (curSection == MAIN_TOC) {
		customWhere = "after";
	} else if (f.customWhere[0].checked) {
		customWhere = "before";
	} else {
		customWhere = "after";
	}
	
	// Create the new customSection item
	newCS = new Object();
	newCS.setId = noteSets[customSetIndex].setId;
	newCS.attacheeSection = curSection;
	newCS.relativeLocation = customWhere;
	newCS.csType = customType;
	newCS.csTitle = EncodeProblemCharacters(customTitle);
		
	// Save the new custom section to the server; 
	// upon return we'll actually go to the custom section page
	var s = "createCustomSection"
		+ "&setId=" + newCS.setId
		+ "&section=" + newCS.attacheeSection
		+ "&relativeLocation=" + newCS.relativeLocation
		+ "&csType=" + newCS.csType
		+ "&csTitle=" + escape(newCS.csTitle);
	Servercom(s);
}

// Register a custom section imported when the user logs in
var registeredCustomSections = new Array();
function RegisterCustomSection(addToCCNow, csId, setId, attacheeSection, relativeLocation, csType, csTitle) {
	// If the attacheeSection doesn't exist in the user's version, don't do anything
	if (sections[attacheeSection] == null) {
		return;
	}
	
	// Create the new customSection item
	newCS = new Object();

	// Assign the values
	newCS.setId = setId;
	newCS.attacheeSection = attacheeSection;
	newCS.relativeLocation = relativeLocation;
	newCS.csType = csType;
	newCS.csTitle = csTitle
	
	// Call CreateCustomSectionReturn, as if we were creating the cs from scratch
	CreateCustomSectionReturn(csId, false);
	
	// Stash the csId so we can add it to CC and TOC when appropriate
	// (e.g. once the frameset is all loaded up, unless addToCCNow is set to true)
	registeredCustomSections[registeredCustomSections.length] = csId;
	
	if (addToCCNow == true) {
		AddCustomSectionToTOC(chaptercontentsF, newCS);
	}
}

function CreateCustomSectionReturn(csId, justCreated) {
	// Store the csId
	newCS.csId = csId;
	
	// Have to store a fn attribute for left TOC use
	newCS.fn = 'CS_' + csId;
	
	// Update sections[] for the section associated with the CS
	var attSec = sections[newCS.attacheeSection];
	// Create the cs[] array if necessary
	if (attSec.cs == null) {
		attSec.cs = new Array();
	}
	// Push CSSectionsIndex(csId) onto the end of the array
	attSec.cs[attSec.cs.length] = CSSectionsIndex(newCS.csId);
	
	// Set the .par attribute of newCS to that of its attached parent
	if (attSec.par != null) {
		newCS.par = attSec.par;
	}
	
	// Add the newCS to sections[]
	sections[CSSectionsIndex(newCS.csId)] = newCS;

	// If we've just created the cs...
	if (justCreated == true) {
		// Update the left TOC
		AddCustomSectionToTOC(chaptercontentsF, newCS);
	
		// Jump to the custom section via LoadSection
		LoadSection(CSSectionsIndex(newCS.csId));
		
		// Add the cs to the registeredCustomSections array so that
		// it'll be written to the main TOC when we go there.
		registeredCustomSections[registeredCustomSections.length] = newCS.csId;
	}
	// Otherwise we'll add the custom section later
}

function AddRegisteredCSsToTOC(frame) {
	for (var i = 0; i < registeredCustomSections.length; ++i) {
		AddCustomSectionToTOC(frame, sections[CSSectionsIndex(registeredCustomSections[i])]);
	}
}

function AddCustomSectionToTOC(frame, theCS) {
	// We don't put cs's attached to the main TOC in the left frame
	if (theCS.attacheeSection == MAIN_TOC && frame == chaptercontentsF) {
		// alert("no cs attached to cc frame");
		return;
	}
	
	var tocEntry = '<div class="customSectionClass"><a href="JavaScript:top.LoadSection(' 
		+ CSSectionsIndex(theCS.csId) + ')">'
		+ '<span class="sn"><b>&raquo;</b></span>&nbsp;<b><span id="CS_' + theCS.csId + '_titleSpan">' + theCS.csTitle + '</span></b>&nbsp;<span class="sn"><b>&laquo;</b></span>'
		+ '</a></div>'
		;
		
	// Create the new CC entry block; chapterContentsBlockType is defined as 'TR' in defaults.js
	// but can be changed to 'DIV' in config.js
	var ntr = frame.document.createElement(chapterContentsBlockType);
	
	var ntd = null;
	// if blocks are TR's, Create a TD to go inside it.
	// Can't do this with innerHTML because setting the colSpan attribute
	// doesn't seem to work in IE or Mozilla
	if (chapterContentsBlockType == 'TR') {
		ntd = frame.document.createElement('TD');
		ntd.setAttribute('colSpan', 2);
		ntd.id = 'tda' + theCS.fn;
		ntd.innerHTML = tocEntry;
	
		ntr.appendChild(ntd);
	} else {
		ntr.id = 'tda' + theCS.fn;
		ntr.innerHTML = tocEntry;
	}
	
	// establish whether we're adding before or after a section.
	// we might have to change this below...
	var relativeLocation = theCS.relativeLocation;
	
	// Get the element at which to insert before/after, and its parent
	// alert(sections[theCS.attacheeSection].fn);
	var elementBefore = frame.document.getElementById('tda' + sections[theCS.attacheeSection].fn);
	
	// if elementBefore is null, it might be because we're trying to add between parts
	// e.g. fn might be "4_2-3", in which case we should add after 4_2.
	if (elementBefore == null) {
		var theFN = sections[theCS.attacheeSection].fn;
		if (theFN.indexOf('-') > -1) {
			theFN = theFN.substr(0,theFN.indexOf('-'));
			elementBefore = frame.document.getElementById('tda' + theFN);
			// make sure we're going *after* this section
			relativeLocation = 'after';
		}
	}
	
	var parent = null;
	if (elementBefore != null) {
		parent = elementBefore.parentNode;
		while (parent != null && elementBefore.tagName.toUpperCase() != chapterContentsBlockType) {
			elementBefore = parent;
			parent = parent.parentNode;
		}
	}
	
	if (parent == null) {
		// alert("couldn't find " + chapterContentsBlockType + " node: " + theCS.attacheeSection);
		return;
	}
	
	// Insert it
	// If we want to insert before, it's easy, since there is an element.insertBefore
	// method in the DOM
	if (relativeLocation == "before") {
		parent.insertBefore(ntr, elementBefore);
	// But it's a little trickier for afters
	} else {
		// Try to get the next sibling of elementBefore
		var elementAfter = elementBefore.nextSibling;
		
		// But have to skip supp rows, for TR-type books
		if (chapterContentsBlockType == 'TR') {
			while (elementAfter != null) {
				// elementAfter is a row.
				// Find the first td in this row
				var eaChild = elementAfter.firstChild;
				while (eaChild != null && eaChild.tagName != "TD") {
					eaChild = eaChild.nextSibling;
				}
				
				// If this child is a TD and its id starts with tda, we're done.
				if (eaChild != null && eaChild.id.substr(0,3) == 'tda') {
					break;
				} else {
					elementAfter = elementAfter.nextSibling;
				}
			}
		}
		
		// If there is no next sibling, insert at the end
		if (elementAfter == null) {
			parent.appendChild(ntr);
		// Otherwise insert before elementAfter
		} else {
			parent.insertBefore(ntr, elementAfter);
		}
	}


	// If we added to chaptercontentsF, stash the block element in theCS, 
	// in case we need to delete it later
	if (frame == chaptercontentsF) {
		theCS.trElement = ntr;
	}

	// If we're attaching something to the main toc, have to show the "chapter 0" div	
	if (theCS.attacheeSection == MAIN_TOC) {
		SetDisplay(main.document.getElementById('div0'), 'block');
		
		// Also try to make the td so that it doesn't have any border
		if (chapterContentsBlockType == 'TR') {
			ntd.style.borderBottomWidth = ntd.style.borderTopWidth = "0px";
		}
	}

}

// This function can be used to add anything 
// (including custom sections and supplemental links) 
// to the left-side or main TOC
function AddToTOC(tocEntry, frame, itemFn, attacheeSection, relativeLocation, tdClass) {
	// Create the new CC entry block; chapterContentsBlockType is defined as 'TR' in defaults.js
	// but can be changed to 'DIV' in config.js
	var ntr = frame.document.createElement(chapterContentsBlockType);
	
	var ntd = null;
	// if blocks are TR's, Create a TD to go inside it.
	// Can't do this with innerHTML because setting the colSpan attribute
	// doesn't seem to work in IE or Mozilla
	if (chapterContentsBlockType == 'TR') {
		ntd = frame.document.createElement('TD');
		ntd.setAttribute('colSpan', 2);
		ntd.id = 'tda' + itemFn;
		ntd.innerHTML = tocEntry;
		ntd.className = tdClass;
	
		ntr.appendChild(ntd);
	} else {
		ntr.id = 'tda' + itemFn;
		ntr.innerHTML = tocEntry;
		ntr.className = tdClass;
	}
	
	// establish whether we're adding before or after a section.
	// we might have to change this below...
	var relativeLocation = relativeLocation;
	
	// Get the element at which to insert before/after, and its parent
	//alert(attacheeSection);
	var elementBefore;
	if (sections[attacheeSection] != null && sections[attacheeSection].fn != null) {
		elementBefore = frame.document.getElementById('tda' + sections[attacheeSection].fn);
	}
	
	// if elementBefore is null, it might be because we're trying to add between parts
	// e.g. fn might be "4_2-3", in which case we should add after 4_2.
	if (elementBefore == null) {
		var theFN = "";
		if (sections[attacheeSection] != null && sections[attacheeSection].fn != null) {
			theFN = sections[attacheeSection].fn;
		}
		if (theFN.indexOf('-') > -1) {
			theFN = theFN.substr(0,theFN.indexOf('-'));
			elementBefore = frame.document.getElementById('tda' + theFN);
			// make sure we're going *after* this section
			relativeLocation = 'after';
		}
	}
	
	var parent = null;
	if (elementBefore != null) {
		parent = elementBefore.parentNode;
		while (parent != null && elementBefore.tagName.toUpperCase() != chapterContentsBlockType) {
			elementBefore = parent;
			parent = parent.parentNode;
		}
	}
	
	if (parent == null) {
		// alert("couldn't find " + chapterContentsBlockType + " node: " + attacheeSection);
		return;
	}
	
	// Insert it
	// If we want to insert before, it's easy, since there is an element.insertBefore
	// method in the DOM
	if (relativeLocation == "before") {
		parent.insertBefore(ntr, elementBefore);
	// But it's a little trickier for afters
	} else {
		// Try to get the next sibling of elementBefore
		var elementAfter = elementBefore.nextSibling;
		
		// But have to skip supp rows, for TR-type books
		if (chapterContentsBlockType == 'TR') {
			while (elementAfter != null) {
				// elementAfter is a row.
				// Find the first td in this row
				var eaChild = elementAfter.firstChild;
				while (eaChild != null && eaChild.tagName != "TD") {
					eaChild = eaChild.nextSibling;
				}
				
				// If this child is a TD and its id starts with tda, we're done.
				if (eaChild != null && eaChild.id.substr(0,3) == 'tda') {
					break;
				} else {
					elementAfter = elementAfter.nextSibling;
				}
			}
		}
		
		// If there is no next sibling, insert at the end
		if (elementAfter == null) {
			parent.appendChild(ntr);
		// Otherwise insert before elementAfter
		} else {
			parent.insertBefore(ntr, elementAfter);
		}
	}
	
	// If we're attaching something to the main toc, have to show the "chapter 0" div	
	if (attacheeSection == MAIN_TOC) {
		SetDisplay(main.document.getElementById('div0'), 'block');
		
		// Also try to make the td so that it doesn't have any border
		if (chapterContentsBlockType == 'TR') {
			ntd.style.borderBottomWidth = ntd.style.borderTopWidth = "0px";
		}
	}

	// return the block element
	return ntr;
}

function UpdateCustomSectionCCTitle(csId, csTitle) {
	var sp = chaptercontentsF.document.getElementById('CS_' + csId + '_titleSpan');
	if (sp != null) {
		sp.innerHTML = csTitle;
	}
}


/*
Take out 1 from 0,1,2
i	j	action
0	0	0=0
1	0	--
2	1	1=2

Take out 0 from 0,1,2
i	j	action
0	-1	--
1	0	0=1
2	1	1=2

Take out 2 from 0,1,2
i	j	action
0	0	0=0
1	1	1=1
2	1	--

Take out 0 from 0
i	j	action
0	-1	--
*/
function RemoveCustomSection(csId, jumpToAttachee) {
	// Remove from attacheeSection
	var csSec = sections[CSSectionsIndex(csId)];
	var attSec = csSec.attacheeSection;
	sections[attSec].cs = RemoveFromArray(sections[attSec].cs, CSSectionsIndex(csId));
	// And delete it if there are none left
	if (sections[attSec].cs.length == 0) {
		sections[attSec].cs = null;
	}

	// Remove from registeredCustomSections
	registeredCustomSections = RemoveFromArray(registeredCustomSections, csId);
	
	// Remove from CC frame
	if (csSec.trElement != null) {
		csSec.trElement.parentNode.removeChild(csSec.trElement);
	}

	// Remove from sections
	sections[CSSectionsIndex(csId)] = null;
	
	// Jump to the attachee section
	LoadSection(attSec);
}

// Return the index of a custom section's entry in the sections[] array
function CSSectionsIndex(csId) {
	return customSectionOffset + csId;
}

function IsCustomSection(s) {
	if (s == null) {
		s = curSection;
	}
	return (s >= customSectionOffset);
}

function CustomSectionTitle(s) {
	if (s < customSectionOffset) {
		s += customSectionOffset;
	}
	return sections[s].csTitle;
}

// Return the "real" section the custom section is attached to
function CustomSectionAttachee(s) {
	if (s == null) {
		s = curSection;
	}
	// If this isn't a custom section, return MAIN_TOC (shouldn't ever happen)
	if (!IsCustomSection(s)) {
		return MAIN_TOC;
	} else if (sections[s] == null) {
		return MAIN_TOC;
	} else {
		return sections[s].attacheeSection;
	}
}

function RemoveFromArray(a, val) {
	// Take the item out of the array, moving later items up
	var j = -1;
	for (var i = 0; i < a.length; ++i) {
		if (a[i] != val) {
			++j;
			a[j] = a[i];
		}
	}

	// Remove the last item
	a.length -= 1;
	
	return a;
}

function ______STICKY_NOTES______() {}
// ------------------------------------------------------------
// sticky note text, added by PW 12/2006
var stickyNoteBeingEstablished = false;

var defaultStickyNoteWidth = 280;
var defaultStickyNoteHeight = 160;
var stickyNoteCollapsedWidth = 150;

var stickyNoteResizerSize = 15;
var stickyNoteRightPadding = 5;

// Keep a hash of all stickyNotes indexed by noteId, so we can easily find them when we need to set their coordinates
var stickyNoteHash = new Object();

// These are for keeping track of the sticky notes on a page
var stickyNoteIndex, stickyNotesForPage, currentlyFocusedStickyNote, stickyNoteZIndex;

function IsStickyNote(n) {
	return (n.stuckTo != null)
}

// Set stickyNoteSettings to default values; 
// this is called when registering a previously saved note or creating a new note
function InitializeStickyNoteSettings(n) {
	n.closed = 0;
	n.width = defaultStickyNoteWidth;
	n.height = defaultStickyNoteHeight;
	n.dright = defaultStickyNoteWidth;
	n.dtop = 0;
	
	// Store the sticky note in the hash
	stickyNoteHash["sn_" + n.noteId] = n;
}


// This function is called when loading the notes in upon login
function SetStickyNoteCoordinates(noteId, closed, width, height, dright, dtop) {
	var n = stickyNoteHash["sn_" + noteId];
	if (n != null) {
		n.closed = closed;
		n.width = width;
		n.height = height;
		n.dright = dright;
		n.dtop = dtop;
	}
	
	//alert('set coords: ' + n.dright);
	
	// We don't have to draw anything now because we do that upon loading sections.
}

// Initiate a stickynote
function InitiateStickyNote() {
	// show directions to the user
	ShowPopInWindow_ebook("Initiate Sticky Note", "Click anywhere on the page to initiate your sticky note (you can always move it later).", null, null, null, null, null, CancelStickyNoteEventHandler);

	// set stickyNoteBeingEstablished to true, so that the next time 
	// the user double-clicks somewhere, we know where to put the stickynote
	// function hl() in ebookHighlighting.js will catch it and send back to PlaceStickyNote
	// stickyNoteBeingEstablished = true;
	main.document.body.onclick = PlaceStickyNote;
}

function CancelStickyNoteEventHandler() {
	main.document.body.onclick = null;
}

// KC: 10/22/2008 made Sticky Note header bold per QA (difficult to read otherwise)
var stickyNoteBaseHTML = 		// '<span style="position:relative">' +
	'<div id="stickyNoteInnerXXX" style="position:absolute; left:0px; top:0px; border:1px solid #000000; background-color:#ZZZ; font-size:12px; text-align:left; z-index:500">'
	+ '    <table border="0" cellspacing="0" cellpadding="0" width="100%" style="margin:0px; padding:0px"><tr>'
	+ '        <td id="stickyNoteTitleXXX" class="popInTitleS" style="font-size:11px; font-family:Verdana, sans-serif; padding:2px 3px 4px 3px; cursor:move; width:95%; border-width:0px; background-color:#VVV; font-weight:bold; color:#QQQ"><a name="stickyNoteAnchorYYY"></a>Sticky Note YYY</td>'
	+ '        <td id="stickyNoteTitleCloseXXX" class="popInTitleS" style="font-size:11px; font-family:Verdana, sans-serif; padding:2px 3px 4px 3px; cursor:pointer; text-align:right; border-width:0px; background-color:#VVV"><a id="stickyNoteTogglerXXX" href="Javascript:top.ToggleStickyNote(XXX)" class="popInCloseLinkS" style="font-weight:bold; cursor:pointer; white-space:nowrap; color:#fff">[&ndash;]</a></td>'
	+ '    </tr></table>'
	+ '    <div id="stickyNoteOuterHolderXXX" style="padding-bottom:15px">'
	+ '    <div id="stickyNoteHolderXXX" style="padding-right:5px; overflow:auto">'
	+ 'HHH'
	+ '    </div>'
	+ '    </div>'
	+ '    <div id="stickyNoteResizeXXX" style="position:absolute; width:15px; height:15px; right:0; bottom:0px; cursor:nw-resize; background-image:url(UUUcommon/popinresize.gif); background-position-x:right; background-repeat:none"></div>'
	+ '</div>';	// + '</span>'

// Called during the ModifyNote() function
function StickyNoteModifyStuff() {
	// Set widths/heights to auto
	var inner = main.document.getElementById("stickyNoteInner" + noteIndexBeingEdited);
	var holder = main.document.getElementById("stickyNoteHolder" + noteIndexBeingEdited);

	inner.style.width = '520px';
	inner.style.height = '360px';
	holder.style.width = 'auto';
	holder.style.height = 'auto';
	
	// Set default position info, if not already set
	// If one setting is null, assume all are null
	if (noteBeingEdited.width == null) {
		InitializeStickyNoteSettings(noteBeingEdited);
	}
	
	// Hide the resizer
	main.document.getElementById('stickyNoteResize' + noteIndexBeingEdited).style.display = "none";

	// Store the fact that we're editing it, so we don't change the default size
	noteBeingEdited.editing = true;
	
	// Call PositionStickyNote
	PositionStickyNote(noteIndexBeingEdited);
	
	// But if we end up off the screen to the left, reset left to 5
	if (inner.offsetLeft < 5) {
		inner.style.left = "5px";
	}
	
	// make sure this sticky is at the top
	FocusStickyNote(noteIndexBeingEdited);
}

// Called during the EditNoteStop() function
function StickyNoteEditStopStuff() {
	// Reset widths/heights
	SetStickyNoteSize(noteIndexBeingEdited, null);
	
	// Show and enable the resizer
	main.document.getElementById('stickyNoteResize' + noteIndexBeingEdited).style.display = "block";
	main.document.getElementById('stickyNoteResize' + noteIndexBeingEdited).onmousedown = EngageStickyNoteResize;
	
	// Update the sticky note links at the top of the page
	WriteStickyNoteLinks();
	
	// note that we're no longer editing
	noteBeingEdited.editing = false;
	
	// Save the position, now that we've resized
	// Have to call PositionStickyNote first, though, since the location may have shifted
	// left or right when we started editing
	PositionStickyNote(noteIndexBeingEdited);
	SaveStickyNoteCoordinates(main.document.getElementById('stickyNoteInner' + noteIndexBeingEdited));
}

function PlaceStickyNote(e) {
	// close pop-in window with instructions, if open
	if (PopInShowing_ebook() == "Initiate Sticky Note") {
		ClosePopInWindow_ebook();
	}
	
	// Cancel the event handler
	CancelStickyNoteEventHandler();

	// Find an element to attach the sticky to
	
	// Get the target of the mouse click (from quirksmode)
	var targ;
	if (!e) var e = main.window.event;
	if (e.target) targ = e.target;
	else if (e.srcElement) targ = e.srcElement;
	if (targ.nodeType == 3) // defeat Safari bug
		targ = targ.parentNode;
	
	var originalTarg = targ;
	
	// We can only attach a sticky to a node with an id or a class specified
	// so look for such a target.
	var levelsUp = 0;
	// move up while...
	while (
			(targ != null && targ.tagName != "BODY") 	// we haven't gotten to BODY (we should never get to null)
			&& (targ.id == null || targ.id == "")		// and the target doesn't have an id
			&& (targ.className == null || targ.className == "")	// and it doesn't have a class name
		) {
		// get the first child of the next sibling if possible
		// or failing that, the next sibling itself if possible
		if (targ.nextSibling != null) {
			targ = targ.nextSibling;
			if (targ.firstChild != null) {
				targ = targ.firstChild;
			}
			
		// otherwise go up to the parent
		} else {
			targ = targ.parentNode;
		}
		++levelsUp;
	}
	
	// targ.style.backgroundColor = "#ff9";
	// highlightedTarg = targ;
	
	var targClass = "";
	var targTag = "";
	var tagClassCount = "";
	
	// If we got all the way up to the body tag, that's all we can do...
	// (although I suppose we could go through *all* named nodes and find the one that 
	// is closest in position to the clicked location)
	if (targ.tagName == "BODY") {
		//alert("body");
		sanchor = "body";
		
	// If we found an id, we're golden...
	} else if (targ.id != null && targ.id != "") {
		//alert(levelsUp + " found ID: " + targ.id);
		sanchor = "id:" + targ.id;
	
	// else we found something with a class...
	} else {
		// So get the className and tag type (tagName)
		targClass = targ.className
		targTag = targ.tagName;
		
		// then get all the elements with this tag type
		var allOfThisTag = main.document.getElementsByTagName(targTag);
		
		// go through them and count how many have this class
		tagClassCount = 0;
		for (var i = 0; i < allOfThisTag.length; ++i) {
			var el = allOfThisTag[i];
			if (el.className == targClass) {
				++tagClassCount;
			}
			// break when we get to targ
			if (el == targ) {
				break;
			}
		}
		
		//alert(levelsUp + " found class: " + targClass + ", #" + tagClassCount);
		sanchor = "class:" + targTag + ":" + tagClassCount + ":" + targClass;
	}
	
	// Some things don't work well, often
	// because then we won't account for top notes. So in these situations,
	// use the third bodyHolder2 (first holds title, second holds top notes)
	// (unless there aren't 3 bodyHolder2's)
	if (sanchor == "body" || targClass == "bodyHolder1" 
		|| (targClass == "bodyHolder2" && targClassCount < 3)
		|| targClass.indexOf("note") > -1 || targ.id.indexOf("note") > -1
		) {
		// Have to set targ to the this div too
		
		var newTarg = null;
		targTag = "DIV";
		targClass = "bodyHolder2";
		var allOfThisTag = main.document.getElementsByTagName(targTag);
		
		// go through and try to find the 3rd with this targClass
		tagClassCount = 0;
		for (var i = 0; i < allOfThisTag.length; ++i) {
			var el = allOfThisTag[i];
			if (el.className == targClass) {
				++tagClassCount;
				// Here, we want newTarg to end up with the relevant el
				newTarg = el;
			}
			// break when tagClassCount is 3
			if (tagClassCount == 3) {
				break;
			}
		}

		// If we got something new, change to it.
		if (newTarg != null) {
			targ = newTarg;
			sanchor = "class:" + targTag + ":" + tagClassCount + ":" + targClass;
		}
	}
	
	// -----------------------------------------
	// Now find position, relative to our target element.
	
	// First get position of mouse click...
	// from quirksmode, of course
	var mposx = 0;
	var mposy = 0;
	if (e.pageX || e.pageY) 	{
		mposx = e.pageX;
		mposy = e.pageY;
	}
	else if (e.clientX || e.clientY) 	{
		mposx = e.clientX + main.document.body.scrollLeft
			+ main.document.documentElement.scrollLeft;
		mposy = e.clientY + main.document.body.scrollTop
			+ main.document.documentElement.scrollTop;
	}
	// mposx and mposy contain the mouse position relative to the document
	
	// Now get the vertical position of the target element
	var targposy = targ.offsetTop;
	
	// Subtract targposy from mposy to get the sticky location
	// and use mposx
	var dtop = mposy - targposy;		// mposy = targposy + dtop
	var dright = mposx;
	
	// ------------------------------------------------
	// finally, create the note!
	CreateNote(sanchor, dright, dtop);
	
	// And return false to cancel further event bubbling
	return false;
}

// Return the actual element that the sticky note is attached to
function GetStickyNoteAnchor(sanchor) {
	// alert(sanchor);
	
	var targ = null;
	
	var arr = sanchor.split(":");
	
	// id
	if (arr[0] == "id") {
		targ = main.document.getElementById(arr[1]);
		// alert('id: ' + targ);
	
	// or class...
	} else if (arr[0] == "class") {
		// get vars out of sanchor
		var targTag = arr[1];
		var tagClassCount = arr[2] * 1;
		var targClass = arr[3];
		
		// Get all tags of the anchor's type
		var allOfThisTag = main.document.getElementsByTagName(targTag);
		
		// go through them until we're left with targ pointing to the right one
		for (var i = 0; i < allOfThisTag.length; ++i) {
			targ = allOfThisTag[i];
			if (targ.className == targClass) {
				--tagClassCount;
			}
			// break when we get to the right target
			if (tagClassCount == 0) {
				break;
			}
		}

		// alert('class: ' + targ);
	}
	
	// if we haven't found a targ yet -- either because arr[0] was "body"
	// or because the targeted element is now missing -- return main.document.body
	if (targ == null) {
		targ = main.document.body;

		// alert('body: ' + targ);
	}
	
	return targ;
}

function EngageStickyNotePopInWindow(e) {
	// Get the mouse event (see note in popinAPI/SetMousePositions)
	if (!e) var e = main.window.event;

	var id = GetEventTargetId(e);

	var popInBeingMoved = id.replace(/stickyNoteTitle/, "");
	var snpiw = main.document.getElementById('stickyNoteInner' + popInBeingMoved);
	
	// Bring this note to the fore
	FocusStickyNote(popInBeingMoved);

	EngagePopInWindow_ebook(e, snpiw, SaveStickyNoteCoordinates);
}

function EngageStickyNoteResize(e) {
	// Get the mouse event (see note in popinAPI/SetMousePositions)
	if (!e) var e = main.window.event;

	var id = GetEventTargetId(e);

	var popInBeingResized = id.replace(/stickyNoteResize/, "");
	var snpiw = main.document.getElementById("stickyNoteInner" + popInBeingResized);
	var snpiwid = main.document.getElementById("stickyNoteHolder" + popInBeingResized);
	var titleBarHeight = main.document.getElementById('stickyNoteTitle' + popInBeingResized).offsetHeight;

	// Bring this note to the fore
	FocusStickyNote(popInBeingResized);

	EngagePopInResize_ebook(e, snpiw, snpiwid, -1 * stickyNoteRightPadding, -1 * StickyNoteTitleBarHeight(popInBeingResized) - stickyNoteResizerSize, SaveStickyNoteCoordinates);
}

// Get the target ID for an event
function GetEventTargetId(e) {
	// FF, Safari
	if (e.target != null) {
		return e.target.id;
	// IE
	} else if (e.srcElement != null) {
		return e.srcElement.id;
	// ???
	} else {
		return "";
	}
}

// Sticky notes have to be attached to spans in the page, so we can't write them until
// the page has loaded
function WriteStickyNotes() {
	var s = sections[curSection];

	if (s == null) {
		return;
	}

	if (s.notes != null) {
		// Go through all the notes
		for (var j = 0; j < s.notes.length; ++j) {
			var n = s.notes[j];
			// When we find a sticky note, write it
			if (n != null && IsStickyNote(n)) {
				WriteStickyNote(j);
			}
		}
		
		// Now put links to the stickies, if any exist
		WriteStickyNoteLinks();
	}
	
	// Have to reposition the notes (if any) now, because of the space added
	// by the link div
	RepositionStickyNotes();
}

function WriteStickyNote(noteIndex, thisStickyNoteIndex) {
	var s = sections[curSection];
	var n = s.notes[noteIndex];

	var thisNoteHTML = stickyNoteBaseHTML;
	thisNoteHTML = thisNoteHTML.replace(/XXX/g, noteIndex);

	// Store a reference to the notes[] index in stickyNotesForPage
	if (thisStickyNoteIndex == null) {
		++stickyNoteIndex;
		thisStickyNoteIndex = stickyNoteIndex;
	}
	stickyNotesForPage[thisStickyNoteIndex] = noteIndex;
	thisNoteHTML = thisNoteHTML.replace(/YYY/g, thisStickyNoteIndex);

	// Put in the note's color
	thisNoteHTML = thisNoteHTML.replace(/ZZZ/g, NoteColor(n));
	thisNoteHTML = thisNoteHTML.replace(/VVV/g, NoteTitleColor(n));
	// KC: If this is a white note, we need to make the title's text color white; otherwise, default to black
	/*
	if (NoteColor(n) == "ffffff") {
		thisNoteHTML = thisNoteHTML.replace(/QQQ/g, 'ffffff'); 
	} else {
		thisNoteHTML = thisNoteHTML.replace(/QQQ/g, '000000');
	}
	*/
	// PW 11/18/2008: actually, all colors seem to look best when the title color is white
	thisNoteHTML = thisNoteHTML.replace(/QQQ/g, 'ffffff'); 

	// insert url start for image (can't do this at the start because in Angel
	// urlStart gets set later)
	thisNoteHTML = thisNoteHTML.replace(/UUU/g, urlStart);

	// Put in the note's text
	thisNoteHTML = thisNoteHTML.replace(/HHH/, NoteHTML(s, noteIndex));

	var snSpan = main.document.createElement('DIV');
	snSpan.id = 'stickyNoteOuter' + noteIndex;
	snSpan.style.position = 'relative';
	// set zIndex to 990 so it appears above most other absolute divs --
	// but not the standard popin, which has zIndex 1000
	snSpan.style.zIndex = '990';
	snSpan.innerHTML = thisNoteHTML;

	main.document.body.insertBefore(snSpan, main.document.body.firstChild);
	main.document.getElementById('stickyNoteTitle' + noteIndex).onmousedown = EngageStickyNotePopInWindow;
	main.document.getElementById('stickyNoteResize' + noteIndex).onmousedown = EngageStickyNoteResize;
		
	// Set the width and position of the note
	SetStickyNoteSize(noteIndex, null);
	PositionStickyNote(noteIndex, null);
	
	// And close it if necessary
	if (n.closed == 1) {
		ToggleStickyNote(noteIndex, 1)
	}
}

function JumpToStickyNote(i, index) {
	ToggleStickyNote(index, 0);
	main.location.hash = "stickyNoteAnchor" + i;
	return false;
}

function WriteStickyNoteLinks() {
	var linksDiv = main.document.getElementById("stickyNoteLinksDiv");

	if (stickyNoteIndex > 0) {
		var stickyNoteLinks = "";
		
		var numStickyNotes = 0;
		for (var i = 1; i <= stickyNoteIndex; ++i) {
			var index = stickyNotesForPage[i];
			if (index != null) {
				stickyNoteLinks += ' <a class="ba" href="#" onclick="return top.JumpToStickyNote(' + i + ',' + index + ');">[' + i + ']</a>';
				++numStickyNotes;
			}
		}

		// 0 notes
		if (numStickyNotes == 0) {
			linksDiv.innerHTML = "";
			linksDiv.style.display = "none";
		} else {
			if (numStickyNotes == 1) {
				stickyNoteLinks = '<i>This page includes a sticky note:</i>' + stickyNoteLinks;
			} else {
				stickyNoteLinks = '<i>This page includes sticky notes:</i>' + stickyNoteLinks;
			}
			linksDiv.innerHTML = stickyNoteLinks;
			linksDiv.style.display = "block";
		}
	} else {
		linksDiv.innerHTML = "";
		linksDiv.style.display = "none";
	}
}

function RemoveStickyNoteLink(noteIndex) {
	var linkToRemove = null;
	for (var i = 1; i <= stickyNoteIndex; ++i) {
		if (stickyNotesForPage[i] == noteIndex) {
			linkToRemove = i;
			break;
		}
	}
	if (linkToRemove != null) {
		stickyNotesForPage[linkToRemove] = null;
	
		// If we removed the only link, kill the div altogether by setting stickyNoteIndex to 0
		if (linkToRemove == 1 && stickyNoteIndex == 1) {
			stickyNoteIndex = 0;
		}
		
		WriteStickyNoteLinks();
	}
}

function SetStickyNoteSize(noteIndex, newWidth, newHeight) {
	// Get handles to the whole pop-in window and the "holder" div (the one with the scroll bars)
	var inner = main.document.getElementById("stickyNoteInner" + noteIndex);
	var holder = main.document.getElementById("stickyNoteHolder" + noteIndex);
	var n = sections[curSection].notes[noteIndex];	
	
	// if we got "null", set widths and heights of inner to saved values, or defaults if we don't have any
	if (newWidth == null) {
		newWidth = (n.width == null) ? defaultStickyNoteWidth : n.width;
		newHeight = (n.height == null) ? defaultStickyNoteHeight : n.height;
	}
	
	// Width/height of inner is as given
	inner.style.width = newWidth + "px";
	inner.style.height = newHeight + "px";
	
	// For holder, compensate for padding, title bar height, and resizer height
	holder.style.width = (newWidth - stickyNoteRightPadding) + "px";
	holder.style.height = (newHeight - StickyNoteTitleBarHeight(noteIndex) - stickyNoteResizerSize) + "px";

	// Since we measure width from the right, we also may have to shift left/right, if dright is set
	if (n.dright != null) {
		// But do this in 50 ms, so that the new size is set
		inner.style.left = (n.dright - inner.offsetWidth) + "px";
	}
}

// Move the sticky note to where it should go
function PositionStickyNote(noteIndex, dright, dtop) {
	var n = sections[curSection].notes[noteIndex];
	var el = main.document.getElementById("stickyNoteInner" + noteIndex);

	if (dright == null) {
		dright = n.dright;
		dtop = n.dtop;
	}
	
	// The sticky is attached to the top of the body
	// sposy is the position of the note relative to the stuckTo element.
	// So we want it positioned at:
	el.style.top = (dtop + GetStickyNoteAnchor(n.stuckTo).offsetTop) + "px";
	// old: el.style.top = dtop + "px";

	el.style.left = (dright - el.offsetWidth) + "px";
	//alert('positioned: ' + dright + '/' + el.style.left);
}

function RepositionStickyNotes() {
	var s = sections[curSection];

	if (s == null) {
		return;
	}

	if (s.notes != null) {
		// Go through all the notes
		for (var j = 0; j < s.notes.length; ++j) {
			var n = s.notes[j];
			// When we find a sticky note, position it
			if (n != null && IsStickyNote(n)) {
				PositionStickyNote(j);
			}
		}
	}
}

function ToggleStickyNote(noteIndex, toggleTo) {
	var n = sections[curSection].notes[noteIndex];
	var inner = main.document.getElementById("stickyNoteInner" + noteIndex);
	var holder = main.document.getElementById('stickyNoteHolder' + noteIndex);
	
	// If toggleTo was set in, change n.closed to its opposite
	// so that we'll toggle to the value desired
	if (toggleTo != null) {
		if (toggleTo == 1) {
			n.closed = 0;	// set n.closed to 0 so that we'll set it to 1 below
		} else {
			n.closed = 1;	// set n.closed to 1 so that we'll set it to 0 below
		}
	}
	
	// Open the note
	if (n.closed == 1) {
		holder.style.display = "block";
		main.document.getElementById('stickyNoteOuterHolder' + noteIndex).style.display = "block";
		main.document.getElementById('stickyNoteResize' + noteIndex).style.display = "block";
		SwapInnerHTML(main.document.getElementById('stickyNoteToggler' + noteIndex), "[&ndash;]");
		SetStickyNoteSize(noteIndex, null);
		PositionStickyNote(noteIndex, null);
		n.closed = 0;

		// Bring it to the fore
		FocusStickyNote(noteIndex);
	
	// Close the note
	} else {
		holder.style.display = "none";
		main.document.getElementById('stickyNoteOuterHolder' + noteIndex).style.display = "none";
		main.document.getElementById('stickyNoteResize' + noteIndex).style.display = "none";
		SwapInnerHTML(main.document.getElementById('stickyNoteToggler' + noteIndex), "[+]");
		
		// Collapse width to stickyNoteCollapsedWidth
		inner.style.width = stickyNoteCollapsedWidth + "px";
		inner.style.height = StickyNoteTitleBarHeight(noteIndex) + "px";
		inner.style.left = (n.dright - stickyNoteCollapsedWidth) + "px";
		
		n.closed = 1;
	}
	
	// Save coordinates, so we save the fact that it's closed or open
	// but only if we really toggled
	if (toggleTo == null) {
		SubmitNoteCoordinates(n);
	}
}

function StickyNoteTitleBarHeight(noteIndex) {
	return main.document.getElementById('stickyNoteTitle' + noteIndex).offsetHeight;
}

function SaveStickyNoteCoordinates(inner) {
	var id = inner.id.replace(/stickyNoteInner/, "") * 1;
	var n = sections[curSection].notes[id];
	
	// stash old coords, so we know if we need to re-save
	var old_width = n.width;
	var old_height = n.height;
	var old_dright = n.dright;
	var old_dtop = n.dtop;

	// Store dright and dtop
	// right is absolute
	n.dright = inner.offsetLeft + inner.offsetWidth;
	// top is relative to stuckTo
	n.dtop = inner.offsetTop - GetStickyNoteAnchor(n.stuckTo).offsetTop;
	// alert(inner.offsetTop + " / " + n.dtop);
	
	// If the note is open and we're not editing, store width and height
	if (!n.closed && !n.editing) {
		n.width = inner.offsetWidth;
		n.height = inner.offsetHeight;
	}
	
	// If we changed, save to db
	if (old_width != n.width || old_height != n.height || old_dright != n.dright || old_dtop != n.dtop) {
		SubmitNoteCoordinates(n);
	}
}

function SubmitNoteCoordinates(n) {	
	// Can't submit coordinates unless we have a noteId
	if (n.noteId == null || n.noteId == 0) {
		return;
	}
	
	top.Servercom("submitNoteCoordinates"
		+ "&noteId=" + n.noteId
		+ "&closed=" + n.closed
		+ "&width=" + n.width
		+ "&height=" + n.height
		+ "&dright=" + n.dright
		+ "&dtop=" + n.dtop
	);
}

function FocusStickyNote(noteIndex) {
	if (currentlyFocusedStickyNote == noteIndex) {
		return;
	}
	currentlyFocusedStickyNote = noteIndex;
	++stickyNoteZIndex;
	main.document.getElementById('stickyNoteInner' + currentlyFocusedStickyNote).style.zIndex = stickyNoteZIndex;
}

// For some reason IE doesn't like to let us set innerHTML sometimes
// (possibly when the item was originally inserted using the DOM)
// So set innerHTML for an el by pulling it out of the DOM, setting it, 
// and putting it back.
function SwapInnerHTML(oldChild, innerHTML) {
	// Get the parentNode
	var parentNode = oldChild.parentNode;
	
	// Create and insert a placeholder node before the oldChild
	var phNode = main.document.createElement('DIV');
	phNode.id = 'placeHolderXXX';
	phNode = parentNode.insertBefore(phNode, oldChild)
	
	// Remove the oldChild; stick it in newChild
	var newChild = parentNode.removeChild(oldChild);
	
	// Modify innerHTML on newChild
	newChild.innerHTML = innerHTML;
	
	// Stick newChild back in before phNode
	parentNode.insertBefore(newChild, phNode);
	
	// Remove phNode
	parentNode.removeChild(phNode);
	
	// Easy, right?
}

function StickyNoteBetaMessage() {
	alert("Sticky notes are a beta feature of our eBooks in Winter/Spring 2008. Please try them out and let us know if you have any problems or suggestions. The worst that could happen would that a sticky note would become \"unstuck\" and show up at the top of the page.\n\n\"Top Notes\" appear at the top of the section text.\n\nNote that the rich text editor, available when editing both top notes and sticky notes, is also a beta feature this term.");
}
