BrowserHistory = (function() {
	// type of browser
	var browser = {
		ie     : false,
		ie8    : false,
		chrome : false,
		firefox: false,
		safari : false,
		opera  : false,
		modern : false,
		version: -1
	};

	// Default app state URL to use when no fragment ID present
	var defaultHash = '';

	// Last-known app state URL
	var currentHref = document.location.href;

	// Initial URL (used only by IE)
	var initialHref = document.location.href;

	// Initial URL (used only by IE)
	var initialHash = document.location.hash;

	// History frame source URL prefix (used only by IE)
	var historyFrameSourcePrefix = 'history/historyFrame.html?';

	var initialState = createState(initialHref,
			initialHref + '#' + initialHash, initialHash);

	var backStack = [];
	var forwardStack = [];

	var currentObjectId = null;

	// UserAgent detection
	var useragent = navigator.userAgent.toLowerCase();

	if (useragent.indexOf("opera") != -1) {
		browser.opera = true;
	} else if (useragent.indexOf("msie") != -1) {
		browser.ie = true;
		browser.version = parseFloat(useragent.substring(useragent
				.indexOf('msie') + 4));
		if (browser.version == 8) {
			browser.ie = false;
			browser.ie8 = true;
		}
	} else if (useragent.indexOf("chrome") != -1) {
		browser.chrome = true;
		browser.version = parseFloat(useragent.substring(useragent
				.indexOf('chrome') + 7));
	} else if (useragent.indexOf("safari") != -1) {
		browser.safari = true;
		browser.version = parseFloat(useragent.substring(useragent
				.indexOf('safari') + 7));
	} else if (useragent.indexOf("gecko") != -1) {
		browser.firefox = true;
	}
	browser.modern= browser.firefox || browser.safari || browser.chrome || browser.opera;
	
	if (browser.ie == true && browser.version == 7) {
		window["_ie_firstload"] = false;
	}
	
	// Accessor functions for obtaining specific elements of the page.
	function getHistoryFrame() {
		return document.getElementById('ie_historyFrame');
	}

	function getAnchorElement() {
		return document.getElementById('firefox_anchorDiv');
	}

	function getFormElement() {
		return document.getElementById('safari_formDiv');
	}

	function getRememberElement() {
		return document.getElementById("safari_remember_field");
	}

	// Get the Flash player object for performing ExternalInterface callbacks.
	// Updated for changes to SWFObject2.
	function getPlayer(id) {
		var i;

		if (id && document.getElementById(id)) {
			var r = document.getElementById(id);
			if (typeof r.SetVariable != "undefined") {
				return r;
			} else {
				var o = r.getElementsByTagName("object");
				var e = r.getElementsByTagName("embed");
				for (i = 0; i < o.length; i++) {
					if (typeof o[i].browserURLChange != "undefined")
						return o[i];
				}
				for (i = 0; i < e.length; i++) {
					if (typeof e[i].browserURLChange != "undefined")
						return e[i];
				}
			}
		} else {
			var o = document.getElementsByTagName("object");
			var e = document.getElementsByTagName("embed");
			for (i = 0; i < e.length; i++) {
				if (typeof e[i].debugTrace != "undefined") {
					return e[i];
				}
			}
			for (i = 0; i < o.length; i++) {
				if (typeof o[i].debugTrace != "undefined") {
					return o[i];
				}
			}
		}
		return undefined;
	}

	function getPlayers() {
		var i;
		var players = [];
		if (players.length == 0) {
			var tmp = document.getElementsByTagName('object');
			for (i = 0; i < tmp.length; i++) {
				if (typeof tmp[i].debugTrace != "undefined")
					players.push(tmp[i]);
			}
		}
		if (players.length == 0 || players[0].object == null) {
			var tmp = document.getElementsByTagName('embed');
			for (i = 0; i < tmp.length; i++) {
				if (typeof tmp[i].debugTrace != "undefined")
					players.push(tmp[i]);
			}
		}
		return players;
	}

	function getIframeHash() {
		var doc = getHistoryFrame().contentWindow.document;
		var hash = String(doc.location.search);
		if (hash.length == 1 && hash.charAt(0) == "?") {
			hash = "";
		} else if (hash.length >= 2 && hash.charAt(0) == "?") {
			hash = hash.substring(1);
		}
		return hash;
	}

	/* Get the current location hash excluding the '#' symbol. */
	function getHash() {
		// It would be nice if we could use document.location.hash here,
		// but it's faulty sometimes.
		var idx = document.location.href.indexOf('#');
		return (idx >= 0) ? document.location.href.substr(idx + 1) : '';
	}

	/* Get the current location hash excluding the '#' symbol. */
	function setHash(hash) {
		// It would be nice if we could use document.location.hash here,
		// but it's faulty sometimes.
		if (hash == '')
			hash = '#';
		document.location.hash = hash;
	}

	function createState(baseUrl, newUrl, flexAppUrl) {
		return {
			'baseUrl' : baseUrl,
			'newUrl'  : newUrl,
			'flexAppUrl' : flexAppUrl,
			'title'   : null
		};
	}

	/*
	 * Add a history entry to the browser. baseUrl: the portion of the location
	 * prior to the '#' newUrl: the entire new URL, including '#' and following
	 * fragment flexAppUrl: the portion of the location following the '#' only
	 */
	function addHistoryEntry(baseUrl, newUrl, flexAppUrl) {

		// delete all the history entries
		forwardStack = [];

		if (browser.ie) {
			// Check to see if we are being asked to do a navigate for the first
			// history entry, and if so ignore, because it's coming from the
			// creation
			// of the history iframe
			if (flexAppUrl == defaultHash
					&& document.location.href == initialHref
					&& window['_ie_firstload']) {
				currentHref = initialHref;
				return;
			}
			if ((!flexAppUrl || flexAppUrl == defaultHash)
					&& window['_ie_firstload']) {
				newUrl = baseUrl + '#' + defaultHash;
				flexAppUrl = defaultHash;
			} else {
				// for IE, tell the history frame to go somewhere without a '#'
				// in order to get this entry into the browser history.
				getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl;
			}
			setHash(flexAppUrl);
		} else {
			// ADR
			if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) {
				initialState = createState(baseUrl, newUrl, flexAppUrl);
			} else if (backStack.length > 0
					&& backStack[backStack.length - 1].flexAppUrl == flexAppUrl) {
				backStack[backStack.length - 1] = createState(baseUrl, newUrl,
						flexAppUrl);
			}
			setHash(flexAppUrl);
		}
		backStack.push(createState(baseUrl, newUrl, flexAppUrl));
	}

	function handleBackButton() {
		// The "current" page is always at the top of the history stack.
		var current = backStack.pop();
		if (!current) {
			return;
		}
		var last = backStack[backStack.length - 1];
		if (!last && backStack.length == 0) {
			last = initialState;
		}
		forwardStack.push(current);
	}

	function handleForwardButton() {
		// summary: private method. Do not call this directly.

		var last = forwardStack.pop();
		if (!last) {
			return;
		}
		backStack.push(last);
	}

	function handleArbitraryUrl() {
		// delete all the history entries
		forwardStack = [];
	}
	// ie8 onChangeURL
	function onURLChanged() {
		currentHref = document.location.href;
		var flexAppUrl = getHash();
		// ADR: to fix multiple
		if (typeof BrowserHistory_multiple != "undefined"
				&& BrowserHistory_multiple == true) {
			var pl = getPlayers();
			for ( var i = 0; i < pl.length; i++) {
				pl[i].browserURLChange(flexAppUrl);
			}
		} else {
			getPlayer().browserURLChange(flexAppUrl);
		}
	}
	/*
	 * Called periodically to poll to see if we need to detect navigation that
	 * has occurred
	 */
	function checkForUrlChange() {
		if (browser.ie) {
			if (currentHref != document.location.href
					&& currentHref + '#' != document.location.href) {
				// This occurs when the user has navigated to a specific URL
				// within the app, and didn't use browser back/forward
				// IE seems to have a bug where it stops updating the URL it
				// shows the end-user at this point, but programatically it
				// appears to be correct. Do a full app reload to get around
				// this issue.
				if (browser.version < 7) {
					currentHref = document.location.href;
					document.location.reload();
				} else {
					if (getHash() != getIframeHash()) {
						// this.iframe.src = this.blankURL + hash;
						var sourceToSet = historyFrameSourcePrefix + getHash();
						getHistoryFrame().src = sourceToSet;
						currentHref = document.location.href;
					}
				}
			}
		}else if (browser.modern) {
			if (currentHref != document.location.href) {
				var bsl = backStack.length;

				var urlActions = {
					back   : false,
					forward: false,
					set    : false
				};

				if ((window.location.hash == initialHash || window.location.href == initialHref)
						&& (bsl == 1)) {
					urlActions.back = true;
					// FIXME: could this ever be a forward button?
					// we can't clear it because we still need to check for
					// forwards. Ugg.
					// clearInterval(this.locationTimer);
					handleBackButton();
				}

				// first check to see if we could have gone forward. We always
				// halt on
				// a no-hash item.
				if (forwardStack.length > 0) {
					if (forwardStack[forwardStack.length - 1].flexAppUrl == getHash()) {
						urlActions.forward = true;
						handleForwardButton();
					}
				}

				// ok, that didn't work, try someplace back in the history stack
				if ((bsl >= 2) && (backStack[bsl - 2])) {
					if (backStack[bsl - 2].flexAppUrl == getHash()) {
						urlActions.back = true;
						handleBackButton();
					}
				}

				if (!urlActions.back && !urlActions.forward) {
					var foundInStacks = {
						back   : -1,
						forward: -1
					};

					for ( var i = 0; i < backStack.length; i++) {
						if (backStack[i].flexAppUrl == getHash()
								&& i != (bsl - 2)) {
							arbitraryUrl = true;
							foundInStacks.back = i;
						}
					}
					for ( var i = 0; i < forwardStack.length; i++) {
						if (forwardStack[i].flexAppUrl == getHash()
								&& i != (bsl - 2)) {
							arbitraryUrl = true;
							foundInStacks.forward = i;
						}
					}
					handleArbitraryUrl();
				}

				// Firefox changed; do a callback into BrowserManager to tell
				// it.
				onURLChanged();
			}
		}
	}

	var _initialize = function() {
		if (browser.ie) {
			var scripts = document.getElementsByTagName('script');
			for ( var i = 0, s; s = scripts[i]; i++) {
				if (s.src.indexOf("history.js") > -1) {
					var iframe_location = (new String(s.src)).replace(
							"history.js", "historyFrame.html");
				}
			}
			historyFrameSourcePrefix = iframe_location + "?";
			var src = historyFrameSourcePrefix;

			var iframe = document.createElement("iframe");
			iframe.id = 'ie_historyFrame';
			iframe.name = 'ie_historyFrame';
			iframe.src = 'javascript:false;';

			try {
				document.body.appendChild(iframe);
			} catch (e) {
				setTimeout(function() {
					document.body.appendChild(iframe);
				}, 0);
			}
		}else if (browser.modern || browser.ie8) {
			var anchorDiv = document.createElement("div");
			anchorDiv.id = 'firefox_anchorDiv';
			document.body.appendChild(anchorDiv);
		}
		if (browser.ie8)
			document.body.onhashchange = onURLChanged;
		// setTimeout(checkForUrlChange, 50);
	};

	return {
		backStack : function() {
			return backStack;
		},
		forwardStack : function() {
			return forwardStack;
		},
		getPlayer : getPlayer,
		initialize : function(src) {
			_initialize(src);
		},
		setURL : function(url) {
			document.location.href = url;
		},
		getURL : function() {
			return document.location.href;
		},
		getTitle : function() {
			return document.title;
		},
		setTitle : function(title) {
			try {
				backStack[backStack.length - 1].title = title;
			} catch (e) {
			}
			document.title = title;
		},
		setDefaultURL : function(def) {
			var player = getPlayer("flashContent");
			player.debugTrace("setDefaultURL: " + def);
			defaultHash = def;
			def = getHash();
			// trailing ? is important else an extra frame gets added to the
			// history
			// when navigating back to the first page. Alternatively could check
			// in history frame navigation to compare # and ?.
			if (browser.ie) {
				window['_ie_firstload'] = true;
				var sourceToSet = historyFrameSourcePrefix + def;
				var func = function() {
					getHistoryFrame().src = sourceToSet;
					window.location.replace("#" + def);
					setInterval(checkForUrlChange, 50);
				};
				try {
					func();
				} catch (e) {
					window.setTimeout(function() {
						func();
					}, 0);
				}
			}
			if (browser.modern) {
				var reg = new RegExp("#" + def + "$");
				if (window.location.toString().match(reg)) {
					
				} else {
					var newloc = "#" + def;
					window.location.replace(newloc);
				}
				setInterval(checkForUrlChange, 50);
			}

		},

		/*
		 * Set the current browser URL; called from inside BrowserManager to
		 * propagate the application state out to the container.
		 */
		setBrowserURL : function(flexAppUrl, objectId) {
			if (browser.ie && typeof objectId != "undefined") {
				currentObjectId = objectId;
			}
			// fromIframe = fromIframe || false;
			// fromFlex = fromFlex || false;
			// alert("setBrowserURL: " + flexAppUrl);
			// flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ;

			var pos = document.location.href.indexOf('#');
			var baseUrl = pos != -1 ? document.location.href.substr(0, pos)
					: document.location.href;
			var newUrl = baseUrl + '#' + flexAppUrl;

			if (document.location.href != newUrl
					&& document.location.href + '#' != newUrl) {
				currentHref = newUrl;
				addHistoryEntry(baseUrl, newUrl, flexAppUrl);
			}
		},

		browserURLChange : function(flexAppUrl) {
			var objectId = null;
			if (browser.ie && currentObjectId != null) {
				objectId = currentObjectId;
			}
			pendingURL = '';

			if (typeof BrowserHistory_multiple != "undefined"
					&& BrowserHistory_multiple == true) {
				var pl = getPlayers();
				for ( var i = 0; i < pl.length; i++) {
					try {
						pl[i].browserURLChange(flexAppUrl);
					} catch (e) {
					}
				}
			} else {
				try {
					getPlayer(objectId).browserURLChange(flexAppUrl);
				} catch (e) {
				}
			}

			currentObjectId = null;
		},
		getUserAgent : function() {
			return navigator.userAgent;
		},
		getPlatform : function() {
			return navigator.platform;
		}

	};

})();

// Initialization

// Automated unit testing and other diagnostics

function setURL(url) {
	document.location.href = url;
}

function backButton() {
	history.back();
}

function forwardButton() {
	history.forward();
}

function goForwardOrBackInHistory(step) {
	history.go(step);
}

// BrowserHistoryUtils.addEvent(window, "load", function() {
// BrowserHistory.initialize(); });
(function(i) {
	var u = navigator.userAgent;
	var e = /* @cc_on!@ */false;
	var st = setTimeout;
	if ((/mozilla/i.test(u) && !/(compati)/i.test(u))
			|| (/opera/i.test(u)) || (/safari/i.test(u))) {
		document.addEventListener("DOMContentLoaded", i, false);
	} else if (e) {
		(function() {
			var t = document.createElement('doc:rdy');
			try {
				t.doScroll('left');
				i();
				t = null;
			} catch (e) {
				st(arguments.callee, 0);
			}
		})();
	} else {
		window.onload = i;
	}
})(function() {
	BrowserHistory.initialize();
});

