var pageLoaded = false;			// sets to true after page has completely loaded
var recipeCardHTML = '';		// store original recipe HTML in this string
var titleText = '';				// store recipe title in string for re-use in cards
var inTitle = false;
var currentView = 'full';		// keep track of which view is being displayed
var full = 'fullDiv';			// ID of the div containing the full page recipe
var main = 'mainDiv';
/* BEGIN browser detect */
var d, dom, ie, ie4, ie5x, moz, mac, win, lin, old, ie5mac, ie5xwin, op, ie55up;

d = document;
n = navigator;
na = n.appVersion;
nua = n.userAgent;
versionMinor = parseFloat(na);
versionMajor = parseInt(versionMinor);

win = ( na.indexOf( 'Win' ) != -1 );
mac = ( na.indexOf( 'Mac' ) != -1 );
lin = ( nua.indexOf( 'Linux' ) != -1 );

if ( !d.layers ){
	dom = ( d.getElementById );
	op = ( nua.indexOf( 'Opera' ) != -1 );
	konq = ( nua.indexOf( 'Konqueror' ) != -1 );
	saf = ( nua.indexOf( 'Safari' ) != -1 );
	moz = ( nua.indexOf( 'Gecko' ) != -1 && !saf && !konq);
	ie = ( d.all && !op );
	ie4 = ( ie && !dom );
	ie5x = ( d.all && dom );
	ie5mac = ( mac && ie5x );
	mozmac = ( mac && moz );
	ie5xwin = ( win && ie5x );

	ieversion=0;

	if (na.indexOf("MSIE")!=-1){
		temp=na.split("MSIE");
		ieversion=parseFloat(temp[1]);
	}
	ie55up = (ie && ieversion >= 5.5);
	
}
/* END browser detect */

// take recipe html and divide it up into appropriately sized index cards
function writeCards(thetext, co) {

	co.numCards = 0;				// reset count of number of cards for this recipe
	co.holder.innerHTML = '';		// reset the div that is used to calculate content height
	co.target.innerHTML = '';		// reset contents of the div that will display the cards
	var currentNode = co.holder;	// currentNode keeps track of where in the DOM the parser is
	// run through text character by character
	for(i = 0; i < thetext.length; i++) {
		var currentChar = thetext.charAt(i);
		// if character might be part of a tag, decide how to handle it
		if(currentChar == '<') {
			if(thetext.substr(i,3).toLowerCase() == '<b>') {
				var boldNode = document.createElement('b');
				currentNode.appendChild(boldNode);
				currentNode = currentNode.childNodes[currentNode.childNodes.length-1];
				co.nest.push('b');
				i += 2;
			} else if(thetext.substr(i,3).toLowerCase() == '<i>') {
				var italicsNode = document.createElement('i');
				currentNode.appendChild(italicsNode);
				currentNode = currentNode.childNodes[currentNode.childNodes.length-1];
				co.nest.push('i');
				i += 2;
			} else if(thetext.substr(i,3).toLowerCase() == '<u>') {
				var underlineNode = document.createElement('u');
				currentNode.appendChild(underlineNode);
				currentNode = currentNode.childNodes[currentNode.childNodes.length-1];
				co.nest.push('u');
				i += 2;
			} else if(thetext.substr(i,3).toLowerCase() == '<ul>') {
				var ulNode = document.createElement('ul');
				currentNode.appendChild(ulNode);
				currentNode = currentNode.childNodes[currentNode.childNodes.length-1];
				co.nest.push('ul');
				i += 3;
			} else if(thetext.substr(i,3).toLowerCase() == '<li>') {
				var liNode = document.createElement('li');
				currentNode.appendChild(liNode);
				currentNode = currentNode.childNodes[currentNode.childNodes.length-1];
				co.nest.push('li');
				i += 3;
			} else if(thetext.substr(i,4).toLowerCase() == '<br>') {
				var linebreak = document.createElement('br');
				currentNode.appendChild(linebreak);
				i += 3;
			} else if(thetext.substr(i,3).toLowerCase() == '<p>') {
				var linebreak = document.createElement('p');
				currentNode.appendChild(linebreak);
				i += 2;				
			} else if(thetext.substr(i,20).toLowerCase() == '<span class="recipeTitle">') {
				var titleSpan = document.createElement('span');
				titleSpan.setAttribute('class','cardTitle');
				currentNode.appendChild(titleSpan);
				currentNode = currentNode.childNodes[currentNode.childNodes.length-1];
				co.nest.push('span');
				i += 19;
			} else if(thetext.substr(i,4).toLowerCase() == '</b>' && lastIndex(co.nest, 'b') > -1) {
				currentNode = currentNode.parentNode;
				co.nest.pop();
				i += 3;
			} else if(thetext.substr(i,4).toLowerCase() == '</u>' && lastIndex(co.nest, 'u') > -1) {
				currentNode = currentNode.parentNode;
				co.nest.pop();
				i += 3;
			} else if(thetext.substr(i,5).toLowerCase() == '</ul>' && lastIndex(co.nest, 'ul') > -1) {
				currentNode = currentNode.parentNode;
				co.nest.pop();
				i += 4;
			} else if(thetext.substr(i,5).toLowerCase() == '</li>' && lastIndex(co.nest, 'li') > -1) {
				currentNode = currentNode.parentNode;
				co.nest.pop();
				i += 4;
			} else if(thetext.substr(i,4).toLowerCase() == '</i>' && lastIndex(co.nest, 'i') > -1) {
				currentNode = currentNode.parentNode;
				co.nest.pop();
				i += 3;
			} else if(thetext.substr(i,7).toLowerCase() == '</span>' && lastIndex(co.nest, 'span') > -1) {
				currentNode = currentNode.parentNode;
				co.nest.pop();
				i += 6;
			} else {
				writeChar(currentNode, currentChar);
			}
		// else, add character to holder div
		} else {
			writeChar(currentNode, currentChar);
		}

		// if content in the holder div is too high, create a new card
		if( (co.numCards == 0 && co.holder.offsetHeight > co.cardHeight1) || co.holder.offsetHeight > co.cardHeight) {
			currentNode = splitCards(co, currentNode);
		}
	}
	// at the end, create last card with remaining content
	co.holder.innerHTML = stripReturns(co.holder.innerHTML);

	if(co.holder.innerHTML  != '') {
		co.numCards++;
		writeCardTop(co);
		co.cardString += co.newCardStart + co.holder.innerHTML + co.cardDivEnd + co.numCards + co.cardDivEnd2;
	}
	co.target.innerHTML = co.cardString;	// write index card HTML to main div
	addPageNumbers(co.numCards);			// add page numbers to card footers
	showCards();							// display the printer-friendly index cards
}

function arrayPush(a, item) {
	a[a.length] = item;
	return a;
}

function arrayPop(a) {
	a.length = a.length - 1;
	return a;
}

// calculate proper place to break card off and perform tag clean-up on last and new card
function splitCards(co, currentNode) {

	var newStart = 0;	// keep track of where the next card should start
	var j;

	// if first card, clear out contents of main div
	co.numCards++;
	writeCardTop(co);
	
	// count backwards til we get a logical page break
	for(j = co.holder.innerHTML.length-1; j >= 0; j--) {
		// if we see a space, break card
		if(j != co.holder.innerHTML.length && co.holder.innerHTML.charAt(j) == ' ') {
			co.cardString +=  co.newCardStart + co.holder.innerHTML.substring(0,j);
			break;
		// else if we see a closing tag
		} else if(co.holder.innerHTML.charAt(j) == '>') {
			// if the tag is a paragraph or line break, break off card
			if(co.holder.innerHTML.substr(j-3,4).toLowerCase() == '<br>') {
				co.cardString +=  co.newCardStart + co.holder.innerHTML.substring(0,j-3);
				break;
			} else if(co.holder.innerHTML.substr(j-4,5).toLowerCase() == '<br/>') {
				co.cardString +=  co.newCardStart + co.holder.innerHTML.substring(0,j-4);
				break;
			} else if(co.holder.innerHTML.substr(j-2,3).toLowerCase() == '<p>') {
				co.cardString +=  co.newCardStart + co.holder.innerHTML.substring(0,j-2);
				break;
			}
		}
	}

	// close out any tags immediately closing after a line break or paragraph break, 
	// ie. '<b>lorem ipsum<br></b>dolor' will leave the bold open
	for(k = j; k < co.holder.innerHTML.length; k++) {
		if(co.holder.innerHTML.substr(k,4).toLowerCase() == '</i>') co.cardString += '</i>';
		else if(co.holder.innerHTML.substr(k,4).toLowerCase() == '</b>') co.cardString += '</b>';
		else if(co.holder.innerHTML.substr(k,4).toLowerCase() == '</u>') co.cardString += '</u>';
		else if(co.holder.innerHTML.substr(k,5).toLowerCase() == '</ul>') co.cardString += '</ul>';
		else if(co.holder.innerHTML.substr(k,5).toLowerCase() == '</li>') co.cardString += '</li>';
		else if(co.holder.innerHTML.substr(k,7).toLowerCase() == '</span>') co.cardString += '</span>';
	}

	// determine where the next card should start
	if(j == 0) {
		co.cardString += co.newCardStart + co.holder.innerHTML;
		newStart = co.holder.innerHTML.length;
	} else {
		newStart = j+1;
	}
	
	// if card break in the middle of open formatting tags, close out the formatting
	if(co.nest.length > 0) {
		var appendedLength = 0; // keep track of how many characters are added to close the tags
		// add appropriate closing tags if we are in the middle of formatting when the card break occurs
		for(k=co.nest.length-1; k >=0; k--) {
			co.cardString += '</' + co.nest[k] + '>';
			appendedLength += 3 + co.nest[k].length;
		}
		co.cardString += co.cardDivEnd + co.numCards + co.cardDivEnd2;	// add footer with unique id to card

		// carry over leftover text to new card, without formatting which will be added back in with nodes 
		var newString = stripTags(co.holder.innerHTML.substring(newStart, co.holder.innerHTML.length-appendedLength));
		var newText = document.createTextNode(newString);
		co.holder.innerHTML = '';
		var tempNode = co.holder;	

		// if card break in the middle of open formatting tags, create appropriate formatting nodes for new card
		for(l=0; l < co.nest.length; l++) {
			tempElement = document.createElement(co.nest[l]);
			tempNode.appendChild(tempElement);
			tempNode = tempNode.firstChild;
		}
		tempNode.appendChild(newText);
		currentNode = tempNode;
		
	} else {
	// else close off card and start new card with overflow text
		co.cardString += co.cardDivEnd + co.numCards + co.cardDivEnd2;
		co.holder.innerHTML = stripTags(co.holder.innerHTML.substring(newStart));
		currentNode = co.holder;	
	}
	return currentNode;
}



// write character to holder div, creating new nodes as needed
// n - current node
// c - current character
function writeChar(n, c) {
	if(c != '\n' && c != '\t') {
		// if the currentNode's last child is not a text node, create a text node
		if(n.childNodes.length == 0 || n.childNodes[n.childNodes.length-1].nodeType == 1) {
			// this logic is because of safari's odd handling of spaces
			if(!saf || c != ' ' || (n.childNodes.length > 0 && ( n.childNodes[n.childNodes.length-1].nodeName == 'B' || n.childNodes[n.childNodes.length-1].nodeName == 'I' || n.childNodes[n.childNodes.length-1].nodeName == 'U')) ) {
				var newText = document.createTextNode(c);
				n.appendChild(newText);
			}
		// else add the character to the last text node
		} else {
			n.childNodes[n.childNodes.length-1].nodeValue += c;
		}
	}
}

// determine what to put at the top of each index card
function writeCardTop(co) {	
	// if card is first on the page, add the scissors above it; if it is the first card, don't add page break
	if(co.numCards == 1) co.cardString += co.firstPage;
	else if(co.numCards % co.cardsPerPage == 1) co.cardString += co.newPage;
	co.newCardStart = co.cardDivStart;

	// if it's the first card, use different top for the card
	if(co.numCards == 1) co.newCardStart += co.firstCardTop + titleText + co.firstCardTop2;
	else co.newCardStart += co.cardTop + titleText + co.cardTop2;
}

// add page numbers to the index card footers
function addPageNumbers(n) {
	if(n > 1) {
		for(k=1; k <= n; k++) {
			document.getElementById('footer' + k).innerHTML = k + ' of ' + n;
		}
	}
}

// parse the DOM of the recipe and create a string with the HTML for it
function readRecipe(n) {							// n is a Node 
    var children = n.childNodes;					// Now get all children of n
    for(var i=0; i < children.length; i++) {		// Loop through the children
		if(children[i].nodeType == 1) {
			if(children[i].className == 'recipeTitle' || children[i].style.fontSize == '17px') inTitle = true;
			if(children[i].nodeName == 'B' || children[i].nodeName == 'STRONG') recipeCardHTML += '<b>';
			else if(children[i].nodeName == 'I' || children[i].nodeName == 'EM') recipeCardHTML += '<i>';
			else if(children[i].nodeName == 'U') recipeCardHTML += '<u>';
			else if(children[i].nodeName == 'UL') recipeCardHTML += '<br><br>';
			else if(children[i].nodeName == 'LI') recipeCardHTML += '';
			else if(children[i].nodeName == 'P') recipeCardHTML += '<p>';
			else if(children[i].nodeName == 'BR') recipeCardHTML += '<br>';
		}

		// Recurse on each node as long as it's not part of a script
		if(children[i].nodeName != 'SCRIPT' && children[i].nodeName != 'NOSCRIPT') readRecipe(children[i]);	
		if ( children[i].nodeValue != null ) {
			if ( children[i].nodeType == 3 && children[i].nodeType != 8) {
				if(inTitle) titleText += children[i].nodeValue;
				else recipeCardHTML += children[i].nodeValue;
			}
		} else if(children[i].nodeType == 1) {
			if(children[i].nodeName == 'B' || children[i].nodeName == 'STRONG') recipeCardHTML += '</b>';
			else if(children[i].nodeName == 'I' || children[i].nodeName == 'EM') recipeCardHTML += '</i>';
			else if(children[i].nodeName == 'U') recipeCardHTML += '</u>';
			else if(children[i].nodeName == 'UL') recipeCardHTML += '';
			else if(children[i].nodeName == 'LI') recipeCardHTML += '<br>';
			else if(children[i].className == 'recipeTitle'  || children[i].style.fontSize == '17px') {
				inTitle = false;
			}
		}
    }
    return recipeCardHTML;
}

// show the index cards, hide the full page recipe
function showCards() {
	document.getElementById('mainWrapper').style.display = 'block';
//	document.getElementById('nav').style.display = 'block';
	document.getElementById(full).style.display = 'none';
}

// show the full page print-friendly recipe, hide the index cards
function showFull() {
	document.getElementById('mainWrapper').style.display = 'none';
//	document.getElementById('nav').style.display = 'none';
	document.getElementById(full).style.display = 'block';
	currentView = 'full';
}

// return the last occurrence of item i in array a, return -1 if not found
function lastIndex(a,i) {
	for(n=a.length - 1; n >= 0; n--) {
		if(a[n] == i) return n;
	}
	return -1;
}

// remove any extra closing tags at the beginning of the new card
function stripReturns(s) {
	s = s.replace(/^\s*/, '');
	while(s.indexOf('<') == 0) {
		if(s.substr(1,3).toLowerCase() == 'br>' || s.substr(1,3).toLowerCase() == '/p>' || s.substr(1,2).toLowerCase() == 'p>' )
			s = s.slice(s.indexOf('>') + 1);
		else break;
		s = s.replace(/^\s*/, '');
	}
	s = s.replace(/^\s*/, '');

	return s;
}

// remove paragraph and line breaks at the beginning of a string
function stripFirstReturns(t) {
	t = t.replace(/^\s*/, '');
	while(t.substr(0,3).toLowerCase() == '<p>' || t.substr(0,4).toLowerCase() == '<br>') {
		if(	t.substr(0,3).toLowerCase() == '<p>' ) t = t.slice(3);
		else if( t.substr(0,4).toLowerCase() == '<br>' ) t = t.slice(4);
		else break;
		t = t.replace(/^\s*/, '');
	}
	t = t.replace(/^\s*/, '');

	return t;
}

// remove any extra tags at the beginning of a string
function stripTags(s) {
	s = s.replace(/^\s*/, '');
	while(s.indexOf('<') == 0) {
		if(s.indexOf('>') == -1) break;
		s = s.slice(s.indexOf('>') + 1);
		s = s.replace(/^\s*/, '');
	}
	
	return s;
}

// object that contains properties of the card
function cardObject(h, h1, cpp, cds, fp, np, ct, ct2, fct, fct2, cde, cde2, hn, nv, tn) {
	this.cardHeight = h;
	this.cardHeight1 = h1;
	this.cardsPerPage = cpp;
	this.cardDivStart = cds;
	this.firstPage = fp;
	this.newPage = np;
	this.cardTop = ct;
	this.cardTop2 = ct2;
	this.firstCardTop = fct;
	this.firstCardTop2 = fct2;
	this.cardDivEnd = cde;
	this.cardDivEnd2 = cde2;
	this.holderName = hn;
	this.newView = nv;
	this.targetName = tn;
	this.cardString = '';
	this.numCards = 0;
	this.nest = new Array();
	this.setHolder = card_setHolder;
	this.setTarget = card_setTarget;
	this.writeCards = card_writeCards;
}

// write the appropriate card HTML
function card_writeCards() {
	if(recipeCardHTML != '') {
		if(this.newView != currentView) {
			this.setTarget();
			if(this.cardString == '') {
				this.setHolder();
				writeCards(recipeCardHTML, this);
			} else {
				this.target.innerHTML = this.cardString;
				addPageNumbers(this.numCards);
				showCards(this);
			}
			currentView = this.newView;
		} else {
			if(!window.print){		
				alert("To print this page, please close this window and hit either CTRL + P or Command + P");		
				return;
			} else {
				window.print();
			}
		}
	} 
/*	else if(!pageLoaded) { 
		alert('Please wait for the page to finish loading.');
		location.reload();
	}
*/
}

// set the holder div for the card size
function card_setHolder() {
	this.holder = document.getElementById(this.holderName);
}

// set the target div for the card size
function card_setTarget() {
	this.target = document.getElementById(this.targetName);
}

// functions to call when page loads
function init() {
	if(document.getElementById('prnttxt')) {
		recipeCardHTML = readRecipe(document.getElementById('prnttxt')); 
		recipeCardHTML = stripFirstReturns(recipeCardHTML);
	}
//	pageLoaded = true;
	if(!ie55up && ie)
		document.getElementById('navFull').style.display = 'none';
}

// 3x5 card properties
var card3 = new cardObject(
				233,
				208,
				2,
				'<div class="cardDiv3"><div class="cardPadding3">',
				'',
				'<br class=\"pagebreak\" />',
				'<div class="cardTop3">',
				' (continued)</div>',
				'<div class="cardTopFirst"><div class="cardLogo3"><img src="/images/logo-print.gif" alt="Ghirardelli" /></div><div class="cardFirstAd3"></div><div class="cardFirstTitle">',
				'</div></div>',
				'</div><div class="cardFooter3" id="footer',
				'">&nbsp;</div></div>',
				'holderDiv3',
				'3x5',
				main);

// 4x6 card properties
var card4 = new cardObject(
				329,
				304,
				2,
				'<div class="cardDiv4"><div class="cardPadding4">',
				'',
				'<br class=\"pagebreak\" />',
				'<div class="cardTop4">',
				' (continued)</div>',
				'<div class="cardTopFirst"><div class="cardLogo4"><img src="/images/logo-print.gif" alt="Ghirardelli" /></div><div class="cardFirstAd4"></div><div class="cardFirstTitle">',
				'</div></div>',
				'</div><div class="cardFooter4" id="footer',
				'">&nbsp;</div></div>',
				'holderDiv4',
				'4x6',
				main);

// 5x7 card properties
var card5 = new cardObject(
				425,
				400,
				1,
				'<div class="cardDiv5"><div class="cardPadding5">',
				'',
				'<br class=\"pagebreak\" />',
				'<div class="cardTop5">',
				' (continued)</div>',
				'<div class="cardTopFirst"><div class="cardLogo5"><img src="/images/logo-print.gif" alt="Ghirardelli" /></div><div class="cardFirstAd5"></div><div class="cardFirstTitle">',
				'</div></div>',
				'</div><div class="cardFooter5" id="footer',
				'">&nbsp;</div></div>',
				'holderDiv5',
				'5x7',
				main);
