(function($) {
	window.navigation2 = {
		currentHash: "",
		timer: null,
		initialLoad: true,
		initialPage: "",
		hashTrim: /^.*#/,
		pageLoadKey: 0,
		loadStartCallbackFunc: null,
		loadCompleteCallbackFunc: null,

		msie: {
			iframe: null,

	        getDoc: function() {
				try
				{
					return this.iframe.contentWindow.document;
				}
				catch( err )
				{
					return null;
				}
	        },

	        getHash: function() {
	            doc = this.getDoc();
	            if( doc == null )
	            	return null;
	            return doc.location.hash;
	        },

	        setHash: function(hash) {
	        	var html = '<html><head><title></title></head><body></body></html>';
	            var doc = this.getDoc();
	            doc.open();
	            doc.write(html);
	            doc.close();
	            doc.location.hash = hash;
	        }
		},

		utfEncodeUrlNeeded: function( url )
		{
			url = url.replace( /\r\n/g, "\n" );

			for( var n = 0; n < url.length; n++ )
			{
				var c = url.charCodeAt( n );

				if( c > 127 )
					return true;
			}

			return false;
		},

		utfEncodeUrl: function( url )
		{
			var result = "";

			if( ( url == null ) || ( url == undefined ) || ( url == "" ) )
				return result;

			url = url.replace(/%20/g, " ");

			var urlParts = url.split( "?" );
			if( urlParts.length > 0 )
			{
				result = urlParts[ 0 ] + "?";
			}

			if( urlParts.length == 2 )
			{
				var params = url.substring( url.indexOf( "?" ) + 1 ).split( "&" );

				for( var i = 0; i < params.length; i++ )
				{
					var paramParts = params[i].split( "=" );

					if( paramParts.length == 2 )
					{
						result += paramParts[0] + "=" + Url.encode( paramParts[1] );
					}
					else
					{
						result += params[i];
					}

					if( i + 1 < params.length )
						result += "&";
				}
			}

			return result;
		},

		encodeUrl: function( url )
		{
			return url.replace(/ /g, ":-:").replace(/%20/g, ":-:").replace(/%26/g, ":a:").replace("?", "::");
		},

		decodeUrl: function( url )
		{
			return url.replace(/:-:/g, "%20").replace(/:a:/g, "%26").replace("::", "?");
		},

		loadStart: function()
		{
			this.pageLoadKey++;

			if( this.loadStartCallbackFunc )
				this.loadStartCallbackFunc( this.pageLoadKey );
		},

		loadComplete: function( pageLoadKey )
		{
			if( this.loadCompleteCallbackFunc )
				this.loadCompleteCallbackFunc( pageLoadKey );
		},

		checkHashState: function()
		{
			var pageHash = location.hash.replace( this.hashTrim, '' );

			if( this.utfEncodeUrlNeeded( pageHash ) )
			{
				pageHash = this.encodeUrl( this.utfEncodeUrl( this.decodeUrl( pageHash ) ) );
			}

			if( this.msie.iframe )
			{
				var iframeHash = this.msie.getHash();
				if( iframeHash == null )
					return ;

				iframeHash = iframeHash.replace( this.hashTrim, '' );

				if( !this.initialLoad )
				{
					if( iframeHash != this.currentHash )
					{
						pageHash = location.hash = iframeHash;
					}
					else if( pageHash != this.currentHash )
					{
						this.msie.setHash( "#" + pageHash );
					}
				}
			}

			if( pageHash != this.currentHash )
			{
				this.currentHash = pageHash;

				if( pageHash == "" )
				{
					$("#divbody").html( this.initialPage );
				}
				else
				{
					var loadUrl = this.decodeUrl( pageHash );
					this.loadStart();
					var curPageLoadKey = this.pageLoadKey;
					var self = this;
					$("#divbody").load( loadUrl, {}, function() { self.loadComplete( curPageLoadKey ); } );
				}
			}

			this.initialLoad = false;

			if (!this.timer) {
				var self = this;
				this.timer = setInterval( function() { self.checkHashState() }, 500 );
			}
		},


		setLoadStartCallback: function( func )
		{
			this.loadStartCallbackFunc = func;
		},


		setLoadCompleteCallback: function( func )
		{
			this.loadCompleteCallbackFunc = func;
		},


		getPageLoadKey: function()
		{
			return this.pageLoadKey;
		},

		loadPage: function( pageUrl )
		{
			if( this.utfEncodeUrlNeeded( pageUrl ) )
			{
				pageUrl = this.utfEncodeUrl( pageUrl );
			}

			pageUrl = this.encodeUrl( pageUrl );

			if( pageUrl != this.currentHash )
			{
				// We first assign the location hash, and then store the value returned
				// from the location hash. The browser may modify the value in the process.
				location.hash = pageUrl;
				this.currentHash = location.hash.replace( this.hashTrim, '' );
				if (this.msie.iframe)
				{
					this.msie.setHash( "#" + pageUrl );
				}

				if( pageUrl == "" )
				{
					$("#divbody").html( this.initialPage );
				}
				else
				{
					var loadUrl = this.decodeUrl( pageUrl );
					this.loadStart();
					var curPageLoadKey = this.pageLoadKey;
					var self = this;
					$("#divbody").load( loadUrl, {}, function() { self.loadComplete( curPageLoadKey ); } );
				}
			}

			return false;
		},


		checkIframeLoad: function()
		{
	        if( !this.msie.iframe.contentWindow ||
	        	!this.msie.iframe.contentWindow.document )
	        {
	            // Check again in 100 msec
	        	var self = this;
	            setTimeout( function() { self.checkIframeLoad() }, 100 );
	            return;
	        }

            this.checkHashState();
		},


		init: function( emptyHtmlPageRef )
		{
			this.initialPage = $("#divbody").html();

	        if( $.browser.msie )
			{
				var pageHash = location.hash.replace(this.hashTrim, '');
	            this.msie.iframe = $("<iframe id='history-iframe' src='" + emptyHtmlPageRef + "#" + pageHash + "'></iframe>").prependTo('body')[0];
	            this.checkIframeLoad();
	        }
	        else
	        {
	        	this.checkHashState();
	        }
		}
	}

	window.state2 = {
		states: {},

		setState: function( key, value ) {
			if( this.states[key] )
			{
				var state = this.states[key];

				if( state.value != value )
				{
					var url = state.url;
					if( state.includeValue )
					{
						if( url.indexOf( "?" ) == -1 )
							url += "?" + key + "=" + escape(value);
						else
							url += "&" + key + "=" + escape(value);
					}

					// Add a dummy variable to IE to prevent cache problems
					if( $.browser.msie )
					{
						if( url.indexOf( "?" ) == -1 )
							url += "?no-ie-cache=" + new Date().getTime();
						else
							url += "&no-ie-cache=" + new Date().getTime();
					}

					$("#" + state.target).load( url );
					state.value = value;
				}
			}
		},

		setStateValue: function( key, value ) {
			if( this.states[key] )
			{
				var state = this.states[key];

				state.value = value;
			}
		},

		getStateValue: function( key ) {
			if( this.states[key] )
			{
				return this.states[key].value;
			}
		},

		addState: function( key, value, target, url, includeValue ) {
			if( !this.states[key] )
			{
				if( includeValue == undefined )
					includeValue = true;

				this.states[key] = {};
				this.states[key].value = value;
				this.states[key].target = target;
				this.states[key].url = url;
				this.states[key].includeValue = includeValue;
			}
		}
	}
})(jQuery);

