/**
 * HistoryManager
 * 
 * Observes back/forward button usage and saves states
 * for registered modules into the hash. This allows to
 * bookmark specific states for an application.
 * 
 * @version		1.0rc2
 * 
 * @see			Events, Options
 * 
 * @license		MIT License
 * @author		Harald Kirschner <mail [at] digitarald.de>
 * @copyright	2007 Author
 */
 Class.Mutators.Singleton = function(self,flag){
	if(!flag) return;
	self.constructor.__instance = undefined;
	if($defined(self.initialize) && $type(self.initialize) == 'function') var init = self.initialize;
	self.initialize = function(){
		if(!$defined(this.constructor.__instance)){
			if($defined(init) && $type(init) == 'function') init.apply(this,arguments);
			this.constructor.__instance = this;
		}
		return this.constructor.__instance;
	}
}
/**
 * Extends Array with 2 helpers: isSimilar(array) and complement(array)
 * 
 */
Array.implement({

	/**
	 * isSimilar - Returns true for similar arrays, type-insensitive
	 * 
	 * @example
	 *  [1].isSimilar(['1']) == true
	 *  [1, 2].isSimilar([1, false]) == false
	 *  
	 * @return	{Boolean}
	 * @param	{Object} Array
	 */
	isSimilar: function(array) {
		return (this.toString() == array.toString());
	},

	/**
	 * complement - Fills up empty array values from another array, length is the same
	 * 
	 * @example
	 *  [1, null].complement([3, 4]) == [1, 4]
	 *	[undefined, '1'].complement([2, 3, 4]) == [2, '1']

	 * @return	{Array} this
	 * @param	{Object} Array
	 */
	complement: function(array) {
		for (var i = 0, j = this.length; i < j; i++) this[i] = $pick(this[i], array[i] || null);
		return this;
	}
});
var HistoryManagerSingleton = new Class({
        Implements : Events,
		initialize: function() {
			this._currentLocation = this._getHash();
			
			if (window.ie) {
				this.addState = this._addStateIE;
				this._iframe = new Element('iframe', {
					src: "javascript:'<html></html>'",
					styles: {
						'position': 'absolute',
						'top': '-1000px'
					}
				}).inject(document.body).contentWindow;
				
				$justForIE = function(hash) {
					this._getHash = function() { return hash; }
					this._monitorDefault.call(this);
					location.hash = hash;
				}.bind(this);
				
				var waitForLoad = function waitForIframeLoad() {
					if (this._iframe && this._iframe.document && this._iframe.document.body) {
						if (!this._iframe.document.body.innerHTML)
							this.addState(this._currentLocation, true);
						$clear(waitForLoad);
					}
				}.periodical(50, this);
			}
			else if (window.webkit419) {
				this._form = new Element("form", {method: 'get'}).inject(document.body);
				this._historyCounter = history.length;
				this._stateHistory = [];
				this._stateHistory[history.length] = this._getHash();
				
				this.addState = this._addStateSafari;
				this._monitorSafari.periodical(250, this);
			}
			else if (window.opera && navigator.appVersion.toFloat() < 9.5) {
				this.addState = this._addStateDefault;
	
				$justForOpera =  this._monitorDefault.bind(this);
				new Element('img', {
					src: "javascript:location.href='javascript:$justForOpera();';",
					style: "position: absolute; top: -1000px;"
				}).inject(document.body);
			}
			else {
				this.addState = this._addStateDefault;
				this._monitorDefault.periodical(250, this);
			}
		},
		
		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><body onload="top.$justForIE(\'', hash.replace("'", "\\'") ,'\');">Loaded</body></html>');
			this._iframe.document.close();
		},
		
		_addStateSafari: function(hash) {
			if (this._currentLocation == hash) return;
	
			this._form.setProperty('action', '#' + hash).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._currentLocation]);
			}
		},
	
		_addStateDefault: function(hash) {
			if (this._currentLocation == hash) return;
			location.hash = '#' + hash;
			this._currentLocation = hash;
		},
	
		_monitorDefault: function() {
			var hash = this._getHash();
	
			if (hash != this._currentLocation) {
				this._currentLocation = hash;
				this.fireEvent('onHistoryChange', [hash]);
			}
		}
	});
