/*
	unFocusHistoryKeeper, version 0.8.3 (alpha) (2005/07/29)
	Copyright: 2005, Kevin Newman (http://www.unfocus.com/Projects/HistoryKeeper/)
	License: http://creativecommons.org/licenses/LGPL/2.1/
*/
if (!window.unFocusHistoryKeeper) new function() {
	window.unFocusHistoryKeeper = this;
	
	// private variables
	var _pollInterval = 200;
	var _listeners = []; // there has been much debate over whether this is appropriate as an array on comp.lang.javascript :-)
	var _currentHash = _GetHash();
	
	// do constructor type stuff here
	// :TODO: add alternative hash update detection methods if one is available (anybody?)
	// :NOTE: this method doesn't work to detect changes in IE 5.5 or 6.0 when the back button is 
	// pressed (location and location.hash are not updated - even when an anchor is added like in IE 5.0)
	if (setInterval)
		var _intervalID = setInterval(_CheckHash, _pollInterval);

	// private methods
	function _GetHash() {
		return location.hash.substring(1);
	};
	function _SetHash($newHash) {
		window.location.hash = $newHash;
	};
	function _CheckHash() {
		var $newHash = _GetHash();
		if (_currentHash != $newHash) {
			_currentHash = $newHash;
			_NotifyListeners($newHash);
		}
	};
	function _NotifyListeners($newHash) {
		for (var i = _listeners.length; -1 < --i;)
			_listeners[i].unFocusHistoryUpdate($newHash);
	};
	
	// privileged methods
	this.AddListener = function($obj) {
		// consider throwing exceptions here (can't have NS4 compat then)
		if (!$obj.unFocusHistoryUpdate) return false; // add an exception here
		// check if this is already in here
		for (var i = _listeners.length; -1 < --i;)
			if (_listeners[i] == $obj)
				return false; // add an exception here?
		_listeners.push($obj);
		// do init
		if ($obj.unFocusHistoryLoad)
			$obj.unFocusHistoryLoad(_currentHash);
		return true;
	};
	this.RemoveListener = function($obj) {
		for (var i = _listeners.length; -1 < --i;) {
			if (_listeners[i] == $obj) {
				_listeners.splice(i,1);
				break;
			}
		}
	};
	
	this.AddBookmark = function($newHash) { // adds history and bookmark hash
		_currentHash = $newHash;
		_SetHash($newHash);
		_NotifyListeners($newHash);
	};
	
	/***************************
	* Browser specific patches *
	***************************/
	// do browser sniffing, fixes bugs that can't be detected through feature sniffing
	if (/MSIE/.test(navigator.userAgent) && !/Opera/.test(navigator.userAgent)) {
		// overwrite the old functions (gotta love javascript :-) )
		// IE 5.5 and 6.0 (I'm going to assume IE 7.x too - will test August 3) need the iframe method, since adding a hash makes no history
		if (navigator.appVersion.match(/MSIE (\d\.\d+)/)[1] >= 5.5) {
			// setup history IFrame
			var $historyFrame = false;
			this.AddBookmark = function($newHash) { // adds history and bookmark hash
				_currentHash = $newHash;
				_CreateHistoryHTML($newHash, true);
			};
			this._NotifyListeners = function($newHash) {
				// the first time this is called, it shouldn't notify, so it instead replaces itself with a version that will notify
				this._NotifyListeners = function($newHash) {
					_currentHash = $newHash;
					_SetHash($newHash);
					_NotifyListeners($newHash);
				};
			};
			function _CreateHistoryHTML($newHash) {
				$historyFrame.document.open('text/html');
				$historyFrame.document.write('<html><head></head><body onload="window.parent.unFocusHistoryKeeper._NotifyListeners(\''+$newHash+'\');"></body></html>');
				$historyFrame.document.close();
			};
			// set up the History Frame, for AddHistory method
			function _SetUpHistoryFrame() {
				if (!window.frames['unFocusHistoryFrame']) {
					$historyFrame = document.createElement("iframe");
					$historyFrame.name = 'unFocusHistoryFrame';
					$historyFrame.id = 'unFocusHistoryFrame';
					$historyFrame.style.position = 'absolute';
					$historyFrame.style.top = '-900px';
					//$historyFrame.runtimeStyle.display = 'none';
					document.body.appendChild($historyFrame);
				}
				// reset the reference to the frame using the frames array - for some reason 
				// the other reference can't be used with document.open
				$historyFrame = window.frames[window.frames.length-1];
				// create root frame for the furthest back state
				_CreateHistoryHTML(_currentHash);
			};
			window.attachEvent('onload', _SetUpHistoryFrame);
		} else { // IE 5.0 needs an anchor before it will take a new hash value
			this.AddBookmark = function($newHash) { // adds history and bookmark hash
				_currentHash = $newHash;
				_CreateAnchor($newHash);
				_SetHash($newHash);
				_NotifyListeners($newHash);
			};
			function _CreateAnchor($newHash) {
				var $anchor = document.createElement('a');
				$anchor.setAttribute('name',$newHash);
				if (/MSIE/.test(navigator.userAgent)) $anchor = document.createElement('<a name="'+$newHash+'"></a>');
				$anchor.style.position = 'absolute';
				$anchor.style.left = document.body.scrollLeft;
				$anchor.style.top = document.body.scrollTop;
				//$anchor.innerHTML = $newHash;
				document.body.appendChild($anchor);
			};
		}
	}
};
