var navigationHandler = Class.create();
var navigation;
navigationHandler.prototype = {
	/**
	 * Author:		Hans Duedal (Lintoo I/S)
	 * Email & URL:	hans@lintoo.dk www.lintoo.dk
	 * Copyright: 	2006 Lintoo I/S
	 *
	 * Primary function of this class is to provide history (termed record when local), 
	 * and to provide methods for going back and fourth through the record.
	 * There are a lot of specific cases to handle, and execution paths are complex.
	 *
	 */
	
	initialize: function() {
		//set up for use later
		this.history = window.history;
		this.backButton = $('nav_back');
		this.forwardButton = $('nav_forward');
		this.homeButton = $('nav_home');
		
		/**
		 * This will handle the actual record, and perform al kind of checks to find out
		 * what the user is doing. The execution order of the statements is critical,
		 * do not modify without thorough knowledge of the inner workings.
		 */
		
		// at the time, get the record from cookie information, or initialize the record with this site
		this.record = (!this.getHistoryCookie()) ? [$H(document.location)] : this.decodeHistory(this.getHistoryCookie().substr("history=".length));
		// attempt to get the active page from the record, a failure here is intentional, tells us if the user is in progress of backtracing (pushed "back")
		this.active = this.findActive(this.record);
		// if the user is infact backtracking, and has clicked a new page, we must adjust the record to match these events
		if (this.active && this.grapQueryId(this.active.object.search) != this.grapQueryId(document.location.search)) {
			//remove items, until active, this is to prevent: click (1) -> click (2) -> back (1) -> click (3) -> back (2) , which should be (1)
			this.record = this.record.slice(0, this.active.index+1);
			this.resetActive(this.record); //user is no longer backtracking
		}
		//if the user is backtracking, or has clicked a new page, do
		if (!this.active || this.grapQueryId(this.active.object.search) != this.grapQueryId(document.location.search) || this.grapQueryOffset(this.active.object.search) != this.grapQueryOffset(document.location.search)) {
			if (this.grapQueryId(this.record.last().search) != this.grapQueryId(document.location.search)) {
				this.record.push($H(document.location)); //append this page, if the previous page did not have the same id (to accomodate for language change) (refresh)
			} else if(this.grapQueryOffset(this.record.last().search) != this.grapQueryOffset(document.location.search)) {
				this.record.push($H(document.location)); //append this page, if the previous page did not have the same offset
			} else if(this.record.last().href != document.location.href) {
				this.record[this.record.length-1] = $H(document.location); //if href differ then update
			}
			this.active = $H({object: this.record.last(), index: this.record.length-1}); //set the active page to this, used in forwardbutton check, but do not set active in record!
		}
		document.cookie = "history=" + this.encodeHistory(this.record); //set cookie with new record, also called save
		if (this.active.index < this.record.length-1 && this.forwardButton) this.forwardButton.style.visibility = 'visible'; //only show if relevant
		if (this.record.length > 1 && this.backButton) this.backButton.style.visibility = 'visible'; //if there is a record display back button, there should always be
		if (this.homeButton) this.homeButton.style.visibility = 'visible'; //if there is a home button, display it
	},
	
	/**
	 * These methods (back, forward, home) interact with the user interface
	 */
	
	back: function() {
		this.resetActive(this.record); //reset active state
		var newActive = this.record[this.active.index-1]; //go back
		if (this.active.index-1 == 0) { //if the back item is home, go home instead
			this.home(); return;
		}
		if (newActive) {
			newActive.active = true;
			document.cookie = "history=" + this.encodeHistory(this.record); //save the new record
			document.location.href = newActive.href; //go
		}
	},
	
	forward: function() {
		this.resetActive(this.record); //reset active state
		var newActive = this.record[this.active.index+1]; //go forward
		if (newActive) {
			newActive.active = true;
			document.cookie = "history=" + this.encodeHistory(this.record); //save the new record
			document.location.href = newActive.href; //go
		}
	},
	
	home: function() {
		var query = document.location.search.replace(/id=\d+/,'').replace(/&&/,'&'); //return the current query, but without any id property
		var date = new Date(); //initialize date object
		date.setTime(date.getTime()+(-1*24*60*60*1000)); //expire yesterday (-1)
		document.cookie = "history=''; expires="+date.toGMTString(); //clear record
		document.location = './' + query; //go
	},
	
	/**
	 * The following methods are for private use only, they perform various calculations and other
	 * utility stuff. Useful to reduce clutter in initialization method.
	 */
	
	getHistoryCookie: function() { //iterate though the cookies, return history
		if (!document.cookie) return;
		var cookies = $A(document.cookie.split(';'));
		return cookies.find(function (i, it) {
			return (i.indexOf('history=') != -1);
		});
	},
	
	decodeHistory: function(historyString) {
		var elements = unescape(historyString).split(':::');
		return elements.collect(function(docElmLoc) {
			var params = $H(docElmLoc.toQueryParams());
			if (params) {
				params.each(function(pair, i) {
					params[pair[0]] = unescape(pair[1]);
				});
			}
			return params;
		});
	},
	
	encodeHistory: function(historyArray) {
		var historyStrings = historyArray.collect(function(docElmLoc) {
			return $H(docElmLoc).toQueryString();
		});
		return escape(historyStrings.join(':::'));
	},
	
	findActive: function(historyArray) {
		var match;
		historyArray.each(function (historyObj, i) {
			if (historyObj.active == true || historyObj.active == 'true') match = $H({object: historyObj, index: i});return;
		});
		return match;
	},
	
	resetActive: function(historyArray) {
		historyArray.each(function (historyObj, i) {
			if (historyObj.active == true || historyObj.active == 'true') historyObj.active = undefined;
		});
	},
	
	grapQueryId: function(queryString) {
		var idPart = queryString.match(/id=\d+/);
		return (idPart) ? parseInt(idPart[0].replace(/\D+/,'')) : 0;
	},
	
	grapQueryOffset: function(queryString) {
		var offsetPart = queryString.match(/offset=\d+/);
		return (offsetPart) ? parseInt(offsetPart[0].replace(/\D+/,'')) : 0;
	},
	
	grapQueryPart: function(partName, queryString) {
		var part = queryString.match(new RegExp(partName + '=([\\w\\d]+)'));
		return part? part[1] : undefined;
	}
}

addLoadEvent(function() { //initialize and start object
	navigation = new navigationHandler();
});