// History manager.
var HistoryManager = function() {
	this.initialize();
};

HistoryManager.prototype = {
	initialize: function() {
		this.pollFrequency = 0.1; // Seconds.
		this._currentLocation = this._getHash();
		
		var historyManager = this;
		
		if (Prototype.Browser.IE) {
			this.addState = this._addStateIE;
			var iframe = document.getElementById("_historyFrameIE");
			if (iframe == null) {
				//alert("HistoryManager: need IFRAME with ID '_historyFrameIE' in document.");
				//return;
				// Following does not always work:
				document.write("<iframe id='_historyFrameIE' style='position: absolute; top: -1000px' src=\"javascript:'<html></html>'\"></iframe>");
				//iframe = document.createElement("IFRAME");
				//iframe.src = "javascript:'<html></html>'";
				//iframe.style.position = "absolute";
				//iframe.style.top = "-1000px";
				//document.body.appendChild(iframe);
				iframe = document.getElementById("_historyFrameIE");
			}
			this._iframe = iframe.contentWindow;
			
			$justForIE = function(hash) {
				historyManager._getHash = function() { return hash; }
				historyManager._monitorDefault.call(historyManager);
				location.hash = hash;
			}
			function waitForIframeLoad() {
				if (historyManager._iframe && historyManager._iframe.document && historyManager._iframe.document.body) {
					if (!historyManager._iframe.document.body.innerHTML) {
						historyManager.addState(historyManager._currentLocation, true);
					}
				} else {
					setTimeout(waitForIframeLoad, 50);
				}
			}
			waitForIframeLoad();
		}
		else if (Prototype.Browser.WebKit && !window.xpath /* WebKit419 */) {
			this._form = document.createElement("FORM");
			this._form.method = "get";
			document.body.appendChild(this._form);
			
			this._historyCounter = history.length;
			this._stateHistory = [];
			this._stateHistory[history.length] = this._getHash();
			
			this.addState = this._addStateSafari;
			
			new PeriodicalExecuter(this._monitorSafari.bind(this), this.pollFrequency);
		}
		else if (Prototype.Browser.Opera) {
			this.addState = this._addStateDefault;

			Event.observe(window, "load", function() {
				$justForOpera = function() {
					historyManager._monitorDefault.call(historyManager);
				}
				var img = document.createElement("IMG");
				img.src = "javascript:location.href='javascript:$justForOpera();';";
				img.style.position = "absolute";
				img.style.top = "-1000px";
				document.body.appendChild(img);
			}.bind(this));
		}
		else {
			this.addState = this._addStateDefault;
			new PeriodicalExecuter(this._monitorDefault.bind(this), this.pollFrequency);
		}
	},
	
	getCurrentLocation: function() {
		return this._currentLocation;
	},
	
	_getHash: function() {
		return location.href.split('#')[1] || '';
	},
	
	_addStateIE: function(hash, override) {
		if (this._currentLocation == hash && !override) {
			return;
		}
		this._currentLocation = hash;
		this._iframe.document.write('<html>');
		if (this.frameTitle != null) {
			this._iframe.document.write("<head><title>" + this.frameTitle + "</title></head>");
		}
		this._iframe.document.write('<body hash=\"' + hash + '\" onload="top.$justForIE(document.body.hash);">Loaded</body></html>');
		this._iframe.document.close();
	},
	
	_getFrameStateIE: function() {
		return this._iframe.document.body.hash;
	},
	
	_addStateSafari: function(hash) {
		if (this._currentLocation == hash) return;

		this._form.action = '#' + hash;
		this._form.submit();
		this._currentLocation = hash;
		this._stateHistory[history.length] = this._getHash();
		this._historyCounter = history.length;
	},

	_monitorSafari: function() {	
		if (history.length != this._historyCounter) {
			this._historyCounter = history.length;
			this._currentLocation = this._stateHistory[history.length];
			this.fireEvent('onHistoryChange', [this._stateHistory[history.length]]);
		}
	},

	_addStateDefault: function(hash) {
		if (this._currentLocation == hash) return;
		this._currentLocation = hash;
		location.hash = '#' + hash;
	},

	_monitorDefault: function() {
		var hash = this._getHash();
		if (hash != this._currentLocation) {
			this._currentLocation = hash;
			this.fireEvent('onHistoryChange', hash);
		}
	},
	
	addEvent: function(type, fn) {
		this.listener = fn;
	},
	
	fireEvent: function(type, hash) {
		if (this.listener != null) {
			this.listener(hash);
		}
	}
};

var historyManager = new HistoryManager();