/**************************************************
 * CColumnBook, version 0.14
 * Copyright 2007 Ivengi BV. Benelux
 **************************************************/
 /*
CONSTRUCTOR
new CColumnBook(DivID,colomsPerPage);
DivID 				-> ID of the DIV that needs to be split in columns
colomsPerPage	-> Number of Columns per page

FUNCTIONS
SetPreviousLinkText(string)  -> Alter the text appearing on the back button
SetNextLinkText(string)			 -> Alter the text appearing on the forward button
SetPagePrefixText(string)		 -> Alter the text appearing before the page numbers (XXX 1 of 3 pages)
SetPageMiddleText(string) 	 -> Alter the text appearing in the middle of the page numbers (number 1 XXX 3 pages)
SetPageSuffixText(string)		 -> Alter the text appearing after the page numbers (number 1 of 3 XXX)
startBook() 								 -> Call when page is made, adds makeBook() to the onLoad handler
makeBook()									 -> Initiates the script end starts creating the columns

###########
# EXAMPLE #
###########

<script type="text/javascript" src="CColumnPage.js"></script>
<script type="text/javascript">
	var Book = new CColumnBook("bookcontent",4);
	Book.SetPreviousLinkText("Previous Page"); 
	Book.SetNextLinkText("Next Page");
	Book.SetPagePrefixText("Page ");
	Book.SetPageMiddleText(" of ");
	Book.SetPageSuffixText("");
	Book.startBook();
</script>


<div id="bookcontent">
	
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Mauris hendrerit, 
ipsum et lacinia aliquet, lacus leo pharetra ligula, vel vehicula enim quam id 
tellus. Nam dolor lacus, accumsan eu, consectetuer et, adipiscing eget,  nibh. 
Sed vel lorem sit  amet massa tempor vehicula. (...)

</div>


*/
/* 
Things to keep in mind: 
	- <hr class="newpage"> will force a new page
	
	- images (and other non-text leaf nodes) get resized if they are too big
	
	- currently uses the "start" attribute to continue numbering an <ol> on a new page, 
		but "start" is deprecated. Code is written to use empty <li>'s to continue numbering. 
		Maybe make it an option.
		
	- if an <li> spans two pages, it gets the class "li-continued" on the new page.
		This is useful for hiding the bullet on the second page.
	
	- if an element with an id requires more than one page to display, 
		the element will have the pagenumber appended to its id on subsequent pages.
		e.g. if the entire book content is wrapped in a <div id="foo">, then the contents
		of page 1 will be wrapped in <div id="foo">, the contents of page 2 will be 
		wrapped in <div id="foo-2">, etc.
		
	- the following elements are available for styling: 
		div#book - main book container
		div.pageset - two pages
		div#pageset-n - the nth set of two pages
		div.bookpage - a page of the book. height is required
		div#bookpage-n - the nth page of the book
		li.li-continued - an <li> continued on a page from a previous page
		div#booknav - the container for page navigation elements
		a#booknav-prev - the previous page link
		a#booknav-next - the next page link
		div#booknav-current - the current page indicator
		span.booknav-pagenumber
			#booknav-page1 - the page number of the first page
			#booknav-page2 - the page number of the second page
		
	- IE only allows padding and border on .bookpage to be assigned in px
*/

function CColumnBook(DivID,colomsPerPage)
{
	
	/******************************
	 * Make the book
	 ******************************/
	// define some node types
	this.TEXT_NODE = 3;
	this.COMMENT_NODE = 8;
	
	// set the number of colums per page
	this.colomsPerPage = colomsPerPage;
	
	// default value's
	this.PreviousLinkText =   			"Vorige Pagina"; 
	this.NextLinkText =       			"Volgende Pagina";
	this.PagePrefixText = 					"Pagina ";
	this.PageMiddleText = 					" van ";
	this.PageSuffixText = 					"";
	
	this.DivID = DivID;
	
	// keep track of the number of pages made
	this.pagecount = 0;	
	// keep track of the number of pagesets
	this.setcount = 0;	
	// keep track of the current pageset being displayed
	this.currentset = 1;
	
	this.page = null;
	this.parents = null;
	this.ol_li_count = null;
	this.book = null;
	this.bookClass = null;
}

CColumnBook.prototype.startBook = function()
{
 var _this = this;
 if(document.getElementById && document.createElement)
	 this.addLoadHandler(function(){ _this.makeBook(); });
}

// make it
CColumnBook.prototype.makeBook = function()
{	
	// read the book's content source
	var source = document.getElementById(this.DivID);
	if(!source) {
		return;
	}
		
	// save its child nodes
	var source_nodes = source.childNodes;
	
	// make the book container
	var book = document.createElement("div");	// create the book
	book.id = "book";							// give it the book id
	
	if(this.bookClass != null) {
		book.className = this.bookClass;
	}
	
	this.book = book;
		
	// put the book in the document, where the content source currently is
	source.parentNode.insertBefore(this.book, source);
	
	// make the first page
	var page = this.makePage();
	this.page = page;
	
	// keep track of the heirarchy in an array
	var parents = new Array();
	this.parents = parents;
	
	// keep track of the number of <li>'s for numbering <ol>'s that break across pages
	var ol_li_count = 0;
	this.ol_li_count = ol_li_count;
		
	// put all of the childnodes in pages (recurse through children of children)

	for(var i=0; i<source_nodes.length; i++) {
		this.placeNodes(source_nodes[i], this.page);
	}

	// remove the book source from the document
	source.parentNode.removeChild(source);

	// hide all but the first pages
	for(var k=2; k<=this.setcount; k++) {
		document.getElementById("pageset-"+k).style.display = "none";
	}
	
	// make the navigation 
	this.makeNav();
	this.loadLastPage();	
	return;
}
		
CColumnBook.prototype.SetPreviousLinkText = function(value)
{
	this.PreviousLinkText	= value;
}
CColumnBook.prototype.SetNextLinkText = function(value)
{
	this.NextLinkText	= value;
}
CColumnBook.prototype.SetPagePrefixText = function(value)
{
	this.PagePrefixText	= value;
}
CColumnBook.prototype.SetPageMiddleText = function(value)
{
	this.PageMiddleText	= value;
}
CColumnBook.prototype.SetPageSuffixText = function(value)
{
	this.PageSuffixText	= value;
}
		
	// recursive function to place all childnodes in pages
	// returns the parent of the node that was placed

CColumnBook.prototype.placeNodes = function(node, parent) 
{
	if(node.hasChildNodes()) {	
		// if this node is an <ol>, reset the number of <li>'s 
		if(node.nodeName == "OL") {
			this.ol_li_count = 0;
		}
		
		// if this node is an <li>, keep track for <ol> numbering purposes
		if(node.nodeName == "LI") {
			this.ol_li_count++;
		}
					
		// place an empty clone of the node
		var node_clone = parent.appendChild(node.cloneNode(false));
		// if the empty clone causes the page to overflow (like the bullet of an empty <li>),
		// delete the node, make a new page, add the clone to the new page

		if(this.overflow(this.page)) {
			// delete the cloned node
			parent.removeChild(node_clone);
			
			// make a new page
			this.page = this.makePage();
			// recreate the heirarchy on the new page
			var clone_parent = this.makeHeirarchy(this.page, this.parents, this.ol_li_count);
			
			// make the clone again on the new page
			node_clone = clone_parent.appendChild(node.cloneNode(false));
		}
		
		// keep track of the heirarchy
		this.parents.push(node);
			
		// recurse through the children
		for(var j=0; j<node.childNodes.length; j++) {			
			node_clone = this.placeNodes(node.childNodes[j], node_clone);
			
			// nodeClode gets updated above based on whether the placement of a child node
			// causes a new page to be made (and thus a new cloned node to place nodes in)
		}

		
		// keep track of the heirarchy
		this.parents.pop(node);
		
		return node_clone.parentNode;
	}
	
	// if there are no children, this is a text node (or image, etc.)
	else {
		// keep track of the parent node of the placed clone node
		var clone_parent = parent;
	
		// if this is a text node
		if(node.nodeType == this.TEXT_NODE) {					
			// add the text node to the page
			var text_node_clone = this.addNode(parent, node);
			
			// if the text node made the page overflow
			if(this.overflow(this.page)) {							
				// clear the text node that was just made
				text_node_clone.nodeValue = "";
				
				// add words until it's too long
				var text = node.nodeValue;	// the text that wouldn't fit
				var next_word = "";			// the next word to be added			
				
				// keep adding words and making new pages (if necessary) until there is no more text
				while(this.isText(text)) {							
					while(!this.overflow(this.page) && this.isText(text)) {
						// get the next word from the text
						next_word = text.match(/\s*\S+\s*/);
						next_word = next_word.toString();	
						
						// add it to the page
						text_node_clone.nodeValue = text_node_clone.nodeValue + next_word;
													
						// delete it from the text 
						text = text.substr(text.indexOf(next_word)+next_word.length);	
					}			
					
					// if the last word caused the page to overflow, 
					// delete it from the page, and add it back to the text
					if(this.overflow(this.page)) {						
						// delete it from the page
						text_node_clone.nodeValue = text_node_clone.nodeValue.substring(0, text_node_clone.nodeValue.lastIndexOf(next_word));
						
						// add it back to the text
						text = next_word + text;
						
						// if the page now contains an empty node
						var empty_node = null;
						if(text_node_clone.nodeValue == "") {								
							// delete the last node and save it for later
							
							// ********** CAUSES CRASH IN IE! **********/
							//var empty_node = parent.parentNode.removeChild(parent);
							
							// pop the node off the parents array
							//this.parents.pop();
							// ********** CAUSES CRASH IN IE! **********/
						}
					}						
					
					// if there is still text left, make a new page
					if(this.isText(text)) {										
						// make a new page
						this.page = this.makePage();
						
						// recreate the heirarchy on the new page and add the blank text node
						
					 clone_parent = this.makeHeirarchy(this.page, this.parents, this.ol_li_count);
						
						// if the last page ended in an empty node, add it to the heirarchy
						if(empty_node != null) {
							// add it to the end of the heirarchy
							clone_parent = this.addNode(clone_parent, empty_node);
							
							// push it onto the parents array
							this.parents.push(empty_node);
						}
						
						text_node_clone = this.addNode(clone_parent, node);	// add the text node to the heirarhcy
						text_node_clone.nodeValue = "";				// clear the text node				
					} 
				} // endwhile
			} // end if (page overflow)
		} // end if(text node)
		
		// if this is not a text node 
		else {					
			// if the node is <hr class="newpage">
			if(node.nodeName == "HR") {
				// make a new page
				this.page = this.makePage();
				
				// recreate the heirarchy on the new page
				clone_parent = this.makeHeirarchy(this.page, this.parents, this.ol_li_count);
			}
						
			// add the node to the page
			var leaf_node_clone = this.addNode(clone_parent, node);
			// if the node made the page overflow
			if(this.overflow(this.page)) {
				// remove the node
				parent.removeChild(leaf_node_clone);
							
				// make a new page
				this.page = this.makePage();
				
				// recreate the heirarchy on the new page and add the node
				clone_parent = this.makeHeirarchy(this.page, this.parents, this.ol_li_count);	
				leaf_node_clone = this.addNode(clone_parent, node);	// add the node to the heirarhcy	
				// if the node was too tall for the new page, shrink it
				if(this.overflow(this.page)) {
					var aspect_ratio = leaf_node_clone.width/leaf_node_clone.height;

					leaf_node_clone.height = this.pageHeight(this.page)
											- this.style2num(this.CJL_getCurrentStyle(leaf_node_clone, "margin-top"))
											- this.style2num(this.CJL_getCurrentStyle(leaf_node_clone, "margin-bottom"))
											- this.style2num(this.CJL_getCurrentStyle(leaf_node_clone, "padding-top"))
											- this.style2num(this.CJL_getCurrentStyle(leaf_node_clone, "padding-bottom"))
											- this.style2num(this.CJL_getCurrentStyle(leaf_node_clone, "border-top"))
											- this.style2num(this.CJL_getCurrentStyle(leaf_node_clone, "border-bottom"));
											
					leaf_node_clone.width = leaf_node_clone.height*aspect_ratio;
				}
			}
		}
				
		// if a new page was made, notify the calling function that the parent node has changed
		// otherwise, return the original parent
		return clone_parent;
			
	} // endelse (no children)
} // end function 
	

/******************************
 * Functions for making pages
 ******************************/

// makes a page of the book 
// returns the page element
CColumnBook.prototype.makePage = function() {
	// if this is an even numbered page (0, 2, 4, ...), make a new pageset
	if((this.pagecount % this.colomsPerPage) == 0) {
		pageset = this.makePageSet();
	}

	var page = document.createElement("div");	// create the page
	page.className = "bookpage";				// give it the bookpage class
	page.id = "bookpage-" + (this.pagecount + 1);	// set the id based on the number
	page.style.overflow = "hidden";				// hide overflow so IE height stays defined
	
	// put the page in the current set
	pageset.appendChild(page);
	
	// increment the page counter
	this.pagecount++;
	
	return page;
}

// makes a pageset of the book, which contains two pages
// returns the pageset element
CColumnBook.prototype.makePageSet = function() 
{
	var set = document.createElement("div");	// create the set
	set.className = "pageset";					// give it the pageset class
	set.id = "pageset-" + ((this.pagecount/this.colomsPerPage) + 1);	// set the id based on the number
	
	// put the set in the book
	var book = document.getElementById("book");
	book.appendChild(set);
	
	// increment the set counter
	this.setcount++;
	
	return set;	
}

// recreates the heirarchy of the last filled page on a newly created page
// returns the last node in the heirarchy
CColumnBook.prototype.makeHeirarchy = function(page, parents, ol_li_count) 
{
	var clone_parent = page;
	for(var z=0; z<this.parents.length; z++) {
		clone_parent =  clone_parent.appendChild(parents[z].cloneNode(false));
		
		// if a node with an ID was just placed, append the pagenumber to the ID 
		// to avoid having multiple nodes with the same ID in the DOM tree
		if(clone_parent.id != "") {
			clone_parent.id += "-" + this.pagecount;
		}
		
		// if an <ol> was just placed set the start attribute such that numbering will continue where it left off
		if(clone_parent.nodeName == "OL") {
			clone_parent.setAttribute("start", ol_li_count);
		}
		if(clone_parent.nodeName == "LI") {
			clone_parent.className = "li-continued " + clone_parent.className;
		}
	}
	
	return clone_parent;
}

// Add a node to a parent
// Does not add empty text nodes	
CColumnBook.prototype.addNode = function(parent, node) 
{
	// if it's not a text node, add it
	if(node.nodeType != this.TEXT_NODE) {
		return parent.appendChild(node.cloneNode(true));
	}
	// if it is a text node that has some content, add it
	else if(node.nodeValue.search(/\S/i) != -1) {
		return parent.appendChild(node.cloneNode(true));
	}
	return null;
}

/******************************
 * Navigating pages
 ******************************/
 
// make the navigation 
CColumnBook.prototype.makeNav = function() {
  var _this = this;
	if (this.setcount > 1) {
		// make the navigation container
		var container = document.createElement("div");
		container.id = "booknav";	// give it the id "booknav"
		
		// make the previous link
		var prev = document.createElement("a");
		prev.id = "booknav-prev";
		prev.setAttribute("href", "#");
	  prev.onclick = function() { _this.prevPage(); }
	  var prevPageDiv = document.createElement("div");
	  prevPageDiv.innerHTML = this.PreviousLinkText;
	  prev.appendChild(prevPageDiv);
		
		// make the next link
		var next = document.createElement("a");
		next.id = "booknav-next";
		next.setAttribute("href", "#");
    next.onclick = function() { _this.nextPage(); }
	  
	  var nextPageDiv = document.createElement("div");
	  nextPageDiv.innerHTML = this.NextLinkText;
	  next.appendChild(nextPageDiv);
	  
	  document.getElementById("spacer").onclick = function() { _this.nextPage(); }
	  
		
		// make the current pageset indicator
		var indicator = document.createElement("div");
		indicator.id = "booknav-current";
		indicator.appendChild(document.createTextNode(this.currentset + " of " + this.setcount));
	
		// make the first page number
		var page1 = document.createElement("span");
		page1.className = "booknav-pagenumber";
		page1.id = "booknav-page1";
		page1.appendChild(document.createTextNode("Page"));
		
		// add the components to the container
		container.appendChild(indicator);	// add indicator
		container.appendChild(document.createTextNode(" "));
		container.appendChild(page1);		// add page 1
		container.appendChild(document.createTextNode(" "));
		container.appendChild(prev);		// add previous link 
		container.appendChild(document.createTextNode(" "));
		container.appendChild(next);		// add next link 
	
		// add the container to the end of the book
		document.getElementById("book").appendChild(container);
		
		// update the page navigation
		this.updateNav();
	}
}

// show the next page
CColumnBook.prototype.nextPage = function() {
	if(this.currentset < this.setcount) {
		// get the current and next pagesets
		var current = document.getElementById("pageset-"+this.currentset);
		var next = document.getElementById("pageset-"+(parseInt(this.currentset)+1));
		
		// show the next, hide the current
		if(next == null) {
			// do nothing
		} else {
			next.style.display = current.style.display;
		}
		current.style.display = "none";
		
		// update the current set
		this.currentset++;
		
		// update the page navigation
		this.saveCurrentPage(this.currentset);
		this.updateNav();
	}
}

// show the previous page
CColumnBook.prototype.prevPage = function() {
	if(this.currentset > 1) {
		// get the current and previous pagesets
		var current = document.getElementById("pageset-"+this.currentset);
		var prev = document.getElementById("pageset-"+(parseInt(this.currentset)-1));
		
		// show the next, hide the current
		prev.style.display = current.style.display;
		current.style.display = "none";
		
		// update the current set
		this.currentset--;
		
		// update the page navigation
		this.saveCurrentPage(this.currentset);
		this.updateNav();
	}
}

CColumnBook.prototype.gotoPage = function(page) {
	if((page > 1) && (page <= this.setcount)) {
		// get the current and previous pagesets
		var current = document.getElementById("pageset-"+this.currentset);
		var prev = document.getElementById("pageset-"+page);
		
		// show the next, hide the current
		prev.style.display = current.style.display;
		current.style.display = "none";
		
		// update the current set
		this.currentset = page;
		
		// update the page navigation
		this.saveCurrentPage(this.currentset);
		this.updateNav();
	}
}

CColumnBook.prototype.determinePageId = function() {
	var pageLocation = document.location.href;
	pageLocation = pageLocation.replace("#","");
	var lastLocation = pageLocation.lastIndexOf("/",(pageLocation.length-5));
	var pageId = pageLocation.substr(lastLocation);
	pageId = pageId.replace(/\//gi,"");
	return pageId;
}

CColumnBook.prototype.loadLastPage = function() {
	var pageId	= this.determinePageId();
	var currentPage = readCookie(pageId);
	if(currentPage != null) {
		this.gotoPage(currentPage);
	}
}

CColumnBook.prototype.saveCurrentPage = function(currentPage) {
	var pageId	= this.determinePageId();
	createCookie(pageId,currentPage,1);
}

// if there are no "next" or "previous" pages, hide the link 
// update the current page indicator
CColumnBook.prototype.updateNav = function() {
	// if there are no more next pages
	if(this.currentset == this.setcount) {
		// hide the next link
		document.getElementById("booknav-next").style.visibility = "hidden";
	}
	else {
		var next = document.getElementById("booknav-next");
		next.style.visibility = "visible";
//		next.firstChild.nodeValue = "Next ("+(setcount - currentset) +" more)";
	}
	
	// if there are no more previous pages
	if(this.currentset == 1) {
		// hide the previous link
		document.getElementById("booknav-prev").style.visibility = "hidden";;
	}
	else {
		var prev = document.getElementById("booknav-prev");
		prev.style.visibility = "visible";
//		prev.firstChild.nodeValue = "Previous ("+(currentset-1) +" more)";
	}
	
	// update the current page indicator
	this.updateIndicator();
	
	// update the page numbers
	this.updatePageNums();
}

// update the current page indicator
CColumnBook.prototype.updateIndicator = function() {
	var indicator = document.getElementById("booknav-current");
	indicator.firstChild.nodeValue = (this.currentset + " of " + this.setcount);
}

// update the page numbers
CColumnBook.prototype.updatePageNums = function() {
	// get page numbers spans
	var page1 = document.getElementById("booknav-page1");
	
	// calculate page numbers
	var num1 = this.PagePrefixText + (((this.currentset-1))+1) + this.PageMiddleText + this.setcount + this.PageSuffixText;

	// put page numbers in spans	
	page1.firstChild.nodeValue = num1;
}

// returns true if there is non-whitespace content in text, false otherwise
CColumnBook.prototype.isText = function(text) {
	return text.length && (text.search(/\S/) != -1);
}

// return true if the page has overflown, false otherwise
CColumnBook.prototype.overflow = function(page) {
	return this.childBottom(page) > this.pageBottom(page);
}

// returns the distance from the top of the body to the bottom of the last child
CColumnBook.prototype.childBottom = function(page) {
	if(!page.lastChild)
		return 0;
	else
		var child = page.lastChild;
		
	if(child.offsetParent == document.body) {
		return child.offsetHeight+child.offsetTop;
	}
	else {
		return child.offsetHeight+child.offsetTop+this.getTotalOffset(child.offsetParent);
	}
}

// returns the distance from the top of the body to the bottom of the content of the page
CColumnBook.prototype.pageBottom = function(page) {
	var paddingB = 0;	// bottom padding of the page
	var borderB = 0;	// bottom border of the page
	
	paddingB = this.CJL_getCurrentStyle(page, "padding-bottom");
	borderB = this.CJL_getCurrentStyle(page, "border-bottom");
	
	// strip the "px" from the padding and border values
	paddingB = this.style2num(paddingB);	
	borderB = this.style2num(borderB);
		
	if(page.offsetParent == document.body)
		return page.offsetHeight+page.offsetTop-paddingB-borderB;
	else
		return page.offsetHeight+page.offsetTop+this.getTotalOffset(page.offsetParent)-paddingB-borderB;
}

// returns the offset from the top of the screen to the top of element
// no matter how many offsetParents are in between
CColumnBook.prototype.getTotalOffset = function(element) {
	if(element == undefined) {
		return 0;
	}
	if(element.offsetParent == null) {
		return 0;
	}
	
	if(element.offsetParent == document.body) {
		return element.offsetTop;
	}
	else {
		return element.offsetTop+this.getTotalOffset(element.offsetParent);
	}
}

// returns the height of the page
CColumnBook.prototype.pageHeight = function(page) {
	var paddingB = 0;	// bottom padding of the page
	var borderB = 0;	// bottom border of the page
	var paddingT = 0;	// top padding of the page
	var borderT = 0;	// top border of the page
		
	paddingB = this.CJL_getCurrentStyle(page, "padding-bottom");
	borderB = this.CJL_getCurrentStyle(page, "border-bottom");
	paddingT = this.CJL_getCurrentStyle(page, "padding-top");
	borderT = this.CJL_getCurrentStyle(page, "border-top");
	
	// strip the "px" from the padding and border values
	paddingB = this.style2num(paddingB);
	borderB = this.style2num(borderB);
	paddingT = this.style2num(paddingT);
	borderT = this.style2num(borderT);
	
	return page.offsetHeight-paddingB-borderB-paddingT-borderT;
}

CColumnBook.prototype.style2num = function(value) {
	if(value)
		return (+value.substring(0,value.search(/\D/)));
	else
		return 0;
}

CColumnBook.prototype.addLoadHandler = function(handler)
{
	if(window.addEventListener)
	{
		window.addEventListener("load",handler,false);
	}
	else if(window.attachEvent)
	{
		window.attachEvent("onload",handler);
	}
	else if(window.onload)
	{
		var oldHandler = window.onload;
		window.onload = function piggyback()
		{
			oldHandler();
			handler();
		};
	}
	else
	{
		window.onload = handler;
	}
}

// Cross-platform JavaScript method for retrieving style information.
// From http://www.codehouse.com/javascript/scripts/cjl/get_current_style/
CColumnBook.prototype.CJL_getCurrentStyle = function(elem, prop) 
{
   if( elem.currentStyle )
   {  
      var ar = prop.match(/\w[^-]*/g);
      var s = ar[0];
      
      for(var i = 1; i < ar.length; ++i)		   
      {
         s += ar[i].replace(/\w/, ar[i].charAt(0).toUpperCase());
      }
      return elem.currentStyle[s]
   }
   else if( document.defaultView.getComputedStyle )
   {
      return document.defaultView.getComputedStyle(elem, null).getPropertyValue(prop);
   }
   return null;
}

/******************************
 * Supplemental functions
 ******************************/
 
// IE 5.0 does not support the push or pop methods for arrays
// implement them using code from http://www.dithered.com/javascript/array/index.html
var undefined;
function isUndefined(property) {
  return (typeof property == 'undefined');
}
// Array.push() - Add an element to the end of an array
if (isUndefined(Array.prototype.push) == true) {
  Array.prototype.push = function() {
     var currentLength = this.length;
     for (var i = 0; i < arguments.length; i++) {
        this[currentLength + i] = arguments[i];
     }
     return this.length;
  };
}
// Array.pop() - Remove the last element of an array and return it
if (isUndefined(Array.prototype.pop) == true) {
  Array.prototype.pop = function() {
     var lastItem = undefined;
    if ( this.length > 0 ) {
        lastItem = this[this.length - 1];
        this.length--;
    }
    return lastItem;
  };
}


function createCookie(name,value,days) {
	if (days) {
		var date = new Date();
		date.setTime(date.getTime()+(15*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
}

function readCookie(name) {
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++) {
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
	}
	return null;
}

function eraseCookie(name) {
	createCookie(name,"",-1);
}