/*
unFocus.History, version 1.9.3 (alpha) (2007/02/13)
Copyright: 2005-2007, Kevin Newman (http://www.unfocus.com/Projects/HistoryKeeper/)
License: http://creativecommons.org/licenses/LGPL/2.1/
*/
if (typeof unFocus == "undefined") var unFocus = {};

unFocus.History = (function() {

function Keeper() {
	var _this = this,
		_pollInterval = 200, _intervalID,
		_currentHash;

	var _getHash = function() {
		return location.hash.substring(1);
	};
	_currentHash = _getHash();
	
	var _setHash = function($newHash) {
		window.location.hash = $newHash;
	}
	
	function _watchHash() {
		var $newHash = _getHash();
		if (_currentHash != $newHash) {
			_currentHash = $newHash;
			_this.notifyListeners("historyChange", $newHash);
		}
	}
	if (setInterval) _intervalID = setInterval(_watchHash, _pollInterval);
	
	function _createAnchor($newHash) {
		if (!_checkAnchorExists($newHash)) {
			var $anchor = document.createElement("a");
			$anchor.setAttribute("name", $newHash);
			if (/MSIE/.test(navigator.userAgent) && !window.opera)
				$anchor = document.createElement('<a name="'+$newHash+'">'+$newHash+"</a>");
			with ($anchor.style) {
				position = "absolute";
				display = "block";
				top = getScrollY()+"px";
				left = getScrollX()+"px";
			}
			document.body.insertBefore($anchor,document.body.firstChild);
		}
	}
	function _checkAnchorExists($name) {
		if (document.getElementsByName($name).length > 0)
			return true;
	}
	if (typeof self.pageYOffset == "number") {
		function getScrollY() {
			return self.pageYOffset;
		}
	} else if (document.documentElement && document.documentElement.scrollTop) {
		function getScrollY() {
			return document.documentElement.scrollTop;
		}
	} else if (document.body) {
		function getScrollY() {
			return document.body.scrollTop;
		}
	}
	eval(String(getScrollY).toString().replace(/Top/g,"Left").replace(/Y/g,"X"));
	
	_this.getCurrent = function() {
		return _currentHash;
	};
	
	_this.addHistory = function($newHash) { // adds history and bookmark hash
		_createAnchor(_currentHash);
		_this.addHistory = function($newHash) {
			if (_currentHash != $newHash) {
				_createAnchor($newHash);
				_currentHash = $newHash;
				_setHash($newHash);
				_this.notifyListeners("historyChange",$newHash);
			}
			return true;
		};
		// ...do first call
		return _this.addHistory($newHash);
	};

	if (/WebKit\/\d+/.test(navigator.appVersion) && navigator.appVersion.match(/WebKit\/(\d+)/)[1] < 420) {
		var _unFocusHistoryLength = history.length,
			_historyStates = {}, _form,
			_recentlyAdded = false;
		
		function _createSafariSetHashForm() {
			_form = document.createElement("form");
			_form.id = "unFocusHistoryForm";
			_form.method = "get";
			document.body.insertBefore(_form,document.body.firstChild);
		}
		
		_setHash = function($newHash) {
			_historyStates[_unFocusHistoryLength] = $newHash;
			_form.action = "#" + _getHash();
			_form.submit();
		}
		
		_getHash = function() {
			return _historyStates[_unFocusHistoryLength];
		};
		
		_historyStates[_unFocusHistoryLength] = _currentHash;
		
		_this.addHistory = function($newHash) { // adds history and bookmark hash
			_createAnchor(_currentHash);
			_createSafariSetHashForm();
			_this.addHistory = function($newHash) {
				if (_currentHash != $newHash) {
					_createAnchor($newHash);
					_currentHash = $newHash;
					_unFocusHistoryLength = history.length+1;
					_recentlyAdded = true;
					_setHash($newHash);
					_this.notifyListeners("historyChange",$newHash);
					_recentlyAdded = false;
				}
				return true;
			};
			// ...do first call
			return _this.addHistory($newHash);
		};
		function _watchHistoryLength() {
			if (!_recentlyAdded) {
				var _historyLength = history.length;
				if (_historyLength != _unFocusHistoryLength) {
					_unFocusHistoryLength = _historyLength;
					
					var $newHash = _getHash();
					if (_currentHash != $newHash) {
						_currentHash = $newHash;
						_this.notifyListeners("historyChange", $newHash);
					}
				}
			}
		};
		
		clearInterval(_intervalID);
		_intervalID = setInterval(_watchHistoryLength, _pollInterval);
		
	} else if (typeof ActiveXObject != "undefined" && window.print && 
			   !window.opera && navigator.userAgent.match(/MSIE (\d\.\d)/)[1] >= 5.5) {
		/* iframe references */
		var _historyFrameObj, _historyFrameRef;
		
		function _createHistoryFrame() {
			var $historyFrameName = "unFocusHistoryFrame";
			_historyFrameObj = document.createElement("iframe");
			_historyFrameObj.setAttribute("name", $historyFrameName);
			_historyFrameObj.setAttribute("id", $historyFrameName);
			// :NOTE: _Very_ experimental
			_historyFrameObj.setAttribute("src", 'javascript:;');
			_historyFrameObj.style.position = "absolute";
			_historyFrameObj.style.top = "-900px";
			document.body.insertBefore(_historyFrameObj,document.body.firstChild);
			// get reference to the frame from frames array (needed for document.open)
			// :NOTE: there might be an issue with this according to quirksmode.org
			// http://www.quirksmode.org/js/iframe.html
			_historyFrameRef = frames[$historyFrameName];
			
			// add base history entry
			_createHistoryHTML(_currentHash, true);
		}
		
		function _createHistoryHTML($newHash) {
			with (_historyFrameRef.document) {
				open("text/html");
				write("<html><head></head><body onl",
					'oad="parent.unFocus.History._updateFromHistory(\''+$newHash+'\');">',
					$newHash+"</body></html>");
				close();
			}
		}
		
		_this._updateFromHistory = function() {
			// hides the first call to the method, and sets up the real method for the rest of the calls
			_this._updateFromHistory = function($hash) {
				_currentHash = $hash;
				_this.notifyListeners("historyChange", $hash);
			};
		};
		//if (navigator.userAgent.match(/MSIE (\d\.\d)/)[1] < 5.5) {
			_this.addHistory = function($newHash) {
				_createHistoryFrame();
				_this.addHistory = function($newHash) { // adds history and bookmark hash
					if (_currentHash != $newHash) {
						_currentHash = $newHash;
						// sets hash and notifies listeners
						_createHistoryHTML($newHash);
					}
					return true;
				};
				// call the first call
				return _this.addHistory($newHash);
			};
			// anonymouse method - subscribe to self to update the hash when the history is updated
			_this.addEventListener("historyChange", function($hash) { _setHash($hash) });
		//} else { /* IE 5.0 */ }
	
	}
}
Keeper.prototype = new unFocus.Utilities.EventManager("historyChange");

return new Keeper();

})();
