function NavigationManager()
{
	// CONSTRUCTOR
}
  
// DEFINE MANAGER CLASS
NavigationManager.prototype = 
{
	
	initComplete: false,
	childIFrame: null,
	updateStack: true,
	traceWin: null,
	delayQueue: null,
	componentQueue: null,
	timer: null,
	componentLocation: "",
	currentLocation: "",
	safariLoadedLocation: "",
	PREFIX: "sc",
	compCount: 0,
	stack_flag: false,
	isIE: false,
	isFirefox: false,
	isSafari: false,
	cancelLoad: false,
	checkInterval: null,
	ignoreCompChange: true, // start out true on load
	//stateList: [],
	
	init: function()
	{
		// init properties
		document.navigationInstance = this;
		var inst = this;
		try 
		{
			//document.onunload = inst.resetNavManager();
			
			inst.determineBrowser();
			inst.updateStack = false;
			inst.delayQueue = new Array();
			inst.componentQueue = new Array();

			if(inst.getSearch() != "") window.location.hash = inst.getHash();
			inst.currentLocation = inst.getHash();
			
			// alert(inst.currentLocation);
			// write iframe if IE or init for Safari if Safari
			if(inst.isIE) inst.buildIFrame();
			
			if(inst.isSafari) inst.initSafari();
			
			// let the player know we are ready to go
			inst.callSwf({type: "browserLoaded", url: inst.currentLocation});
			//alert("** called swf from js");
			window.setInterval(manager.verifyLocation, 100);
			
		} catch (err) {
			inst.trace("Error thrown: " + err.message);
		}
		
		inst.initComplete = true;
		inst.trace("app started now...");
	},
	
	buildIFrame: function()
	{
		var inst = document.navigationInstance;
		inst.currentLocation = (inst.currentLocation != "") ? inst.currentLocation : "home";
		document.location.hash = inst.currentLocation;
		
		var hmFrame = document.createElement('IFRAME');
		hmFrame.frameborder = 0;
		hmFrame.scrolling = "no";
		hmFrame.width = 1;
		hmFrame.height = 0;
		hmFrame.id = "hmFrame";
		hmFrame.name = "hmFrame";
		hmFrame.src = "hminstance.html?" + inst.currentLocation;			
		document.body.appendChild(hmFrame);
		
		var compFrame = document.createElement('IFRAME');
		compFrame.frameborder = 0;
		compFrame.scrolling = "no";
		compFrame.width = 1;
		compFrame.height = 0;
		compFrame.id = "_history";
		compFrame.name = "_history";
		compFrame.src = "componentpage.html";			
		document.body.appendChild(compFrame);
	},
	
	initSafari: function(inst)
	{
		
		document.location.SCION = document.location.SCION || {};
		document.location.SCION.managers = document.location.SCION.managers || {};
		document.location.SCION.managers.historyManager = document.location.SCION.managers.historyManager || {};
		
		var inst = document.navigationInstance;
		var loc = document.location.SCION.managers.historyManager;
		
		// Make sure the last state is loaded when you come back to
		// this page after navigating away.
		window.onunload = function()
		{
			loc.oldHistoryLength = -1;
		}

		if (loc.deepLink && loc.deepLink != 'home')
		{
			loc.oldHistoryLength = -1;
			loc.deepLink = null;                   	
		}
		
		 // Create a list of the states we click through.
		if (typeof loc.stateList == 'undefined')
		{
			loc.stateList = [inst.getStateID() || 'home'];
			loc.deepLink = loc.stateList[0];

			loc.offset = history.length - 1;
			while (loc.offset)
			{
				loc.stateList.unshift(null);
				loc.offset--;
			}
			delete loc.offset;

			loc.oldHistoryLength = document.location.hash ? -1 : history.length;
		}

		// Watch to see if the length of the history object changes.
		var checkForHistoryLengthChange = function()
		{
			
			var loc = document.location.SCION.managers.historyManager;
			var inst = document.navigationInstance;
			
			if(loc.oldHistoryLength == -1) 
			{
				// this is the first view so don't update
				loc.oldHistoryLength = history.length;
				return;
			}
			
			if (inst.cancelLoad)
			{
				// this is a regular view change, not a deep link or click on the browser forward/back buttons
				inst.cancelLoad = false;
				
				
				if(inst.currentLocation == inst.safariLoadedLocation)
				{
					// the previous click was a back button and the previous view was a stateful view, which causes
					// the history manager to be called twice.  Don't register this second click.
					inst.safariLoadedLocation = "";
					return;
				}
				
				// if the stateList length is greater than the history length, the user must have clicked the back button
				// before... now we need to pare off the extra stored states
				while(loc.stateList.length > history.length-1)
				{
					if( loc.stateList[loc.stateList.length-1] != inst.currentLocation)
					{
						loc.stateList.pop();
					} else {
						break;
					}
				}
				
				// the history has grown, so add the new view to the stateList array
				if(history.length > loc.oldHistoryLength && inst.currentLocation != loc.stateList[loc.stateList-1]) 
				{
					loc.stateList.push(inst.currentLocation);
				}
				
				loc.oldHistoryLength = history.length;
				return;
			}
			
			// this is not a regular view change, it is a deep link or a click on the browser forward/back buttons
			if (history.length != loc.oldHistoryLength)
			{
				var stateID = loc.stateList[history.length - 1];
				if(stateID == "" || stateID == undefined) 
				{
					stateID = loc.stateList[loc.stateList.length - 1];
				}
				inst.trace("checkForHistoryLengthChange new state: " + stateID);
				
				inst.safariLoadedLocation = stateID;
				inst.updateAppLocation(stateID);
				loc.oldHistoryLength = history.length;
			}
		}

		loc.checkInterval = setInterval(checkForHistoryLengthChange, 100);
	},
	
	// called by the component iframe onload
	componentHistoryChange: function(newLocation)
	{
		//alert('componentHistoryChange');
		var inst = document.navigationInstance;
		if(!inst.ignoreCompChange)
		{
			// we have the user navigating back
			if(newLocation == undefined) newLocation = "";
			inst.callSwf({type: "browserComponentNavigationChange", location: inst.parseMarker(newLocation, "|")});
			// swfInstance.jsComponentNavigationChange(inst.parseMarker(newLocation, "?"));
		}
		inst.ignoreCompChange = false;
	},
	
	// change the location of the component frame
	changeComponentLocation: function(newURL)
	{
		//alert('changeComponentLocation ' + newURL);
		var inst = document.navigationInstance;
		inst.ignoreCompChange = true;		
		switch(true)
		{
			case inst.isIE:
				window.document.getElementById("_history").src = "componentpage.html?" + newURL;
				break;
			default:
				inst.compCount++;
				var id = inst.PREFIX + inst.compCount;
				inst.componentQueue[id] = newURL;
				window.location.hash = inst.getHash() + "|" + id;
		}
			
	},
	
	changePageTitle: function(title) {
		var inst = document.navigationInstance;
		title = pageTitlePrefix + title;
		if(window.document.title != title) window.document.title = title;
		
		if(inst.isIE && inst.childIFrame) 
		{
			inst.childIFrame.changeTitle(title);
		}
	},
	
	// called to mange the stack
	updateHistroyStack: function(newLoc, type, storeData)
	{
		var inst = document.navigationInstance;
		// verify if we are going to home and are already there
		if(type != "called" && newLoc == "home" && (inst.currentLocation == "" || inst.currentLocation == "home"))
		{
			if(!titleArray["home"])
			{
				titleArray["home"] = "Home";
				inst.changePageTitle(title);
			}
			return;
		}
		
		// push on the new location
		inst.stack_flag = true;
		/*
		if(inst.isIE && newLoc.indexOf('?') == 0) {
			newLoc += '?' + newLoc;
		}
		*/
		inst.processChangeQueue(newLoc, type);
	},
	
	// get the hash
	getHash: function()
	{
		var inst = document.navigationInstance;
		var hash = null;
		if(inst.isIE)
		{
			var pos = window.location.toString().indexOf("#");
			if(pos > -1)
			{
				hash = window.location.toString().slice(pos);				
			} else {
				hash = window.location.hash;
			}
		} else {
			hash = window.location.hash;
		}
		
		// strip ?
		if(hash.indexOf("|") > -1)
		{
			// pull out the ?
			hash = hash.slice(0, hash.indexOf("|"));
		}
		
		/*
		 * Removing .html incase that the Akami process can not remove this extenstion
		 * when the # page is generated.  We also strip out index for the same purpose,
		 * this way that app sees index as home.
		 */
		// strip out .html
		hash = hash.replace(/.html/i, "");
		// strip out index
		hash = hash.replace(/index/i, "");
		
		return inst.parseMarker(hash, "#");
	},
	// Retrieves state ID.
	getStateID: function()
	{
		return document.location.href.split('#')[1] || 'home';
	},
	// get the search
	getSearch: function()
	{
		var inst = document.navigationInstance;
		var search = window.location.hash;
		if(search.indexOf("|") > -1)
		{
			// pull out the ?
			search = search.slice(search.indexOf("|"));
		} else {
			search = "";	
		}
		return inst.parseMarker(search, "|");
	},
	
	parseMarker: function(str, character)
	{
		var inst = document.navigationInstance;
		if(str.charAt(0) == character && str.length > 1)
		{
			str = str.substring(1);	
		} else if(str.charAt(0) == character ) {
			str = "";	
		}
		return str;
	},
	
	// called when the iFrame updates
	iframePageChange: function(newLocation)
	{
		var inst = document.navigationInstance;
		// ifame page change
		var loc = inst.parseMarker(newLocation, "?");
		// alert("iFrame changed: " + newLocation + "\rcurrentPosition:" + inst.currentLocation);
		// store iframe location
		inst.iframe = window.document.getElementById("hmFrame");
		if(inst.updateStack)
		{
			// process the location change
			window.document.location.hash = loc;
			inst.updateAppLocation(loc);
		}
		inst.currentLocation = loc;
		inst.updateStack = true;
	},
	
	callBack: function(childIFrame) 
	{
		var inst = document.navigationInstance;
		inst.childIFrame = childIFrame;
		window.setTimeout(inst.delayedTitleCallback, 500);
	},
	
	delayedTitleCallback: function()
	{
		var inst = document.navigationInstance;
		var title = inst.callSwf({type: "browserGetHTMLTitle"});
		inst.changePageTitle(title);
	},
	
	callSwf: function(event)
	{
		//alert('callSwf');
		return swfInstance.jsEvent(event);
	},
	
	updateAppLocation: function(newLocation)
	{
		var inst = document.navigationInstance;
		// If IE we remove beginning ?
		if(inst.isIE) {
			newLocation = newLocation.replace(/^\?/, '');
			if(newLocation == '') {
				newLocation = 'home';
			}
		}
		inst.trace("updateAppLocation: " + newLocation);
		inst.callSwf({type: "browserUrlChange", url: newLocation});
	},
	
	// queue used to store IE changes
	processChangeQueue: function(loc, passedtype)
	{
		var inst = document.navigationInstance;
		//if(loc == "") return;
		
		if(inst.stack_flag)
		{
			var queueItem = new Object();
			queueItem.location = loc;
			queueItem.type = passedtype;
			inst.delayQueue.push(queueItem);
			inst.stack_flag = false;
			if(inst.timer == null) inst.timer =  window.setTimeout(inst.processChangeQueue, 300);
			return; // this was not a system call, we are adding to the stack
		}
		
		if(inst.delayQueue.length > 0) 
		{
			// change the location
			inst.timer = null;
			var data = inst.delayQueue[0];
			inst.delayQueue = inst.delayQueue.slice(1);
			inst.updateStack = false;
			inst.currentLocation = data.location;
			
			
			// see if we update the iframe
			inst.changeUrlPage(data);
			
			// see if we have title
			var titlePosition = (inst.currentLocation == "") ? "home" : inst.currentLocation;
			inst.trace("processChangeQueue - title position: " + titlePosition);
			if(titleArray[titlePosition])
			{
				inst.changePageTitle(titleArray[titlePosition]);
				inst.trace("processChangeQueue - title: " + titleArray[titlePosition]);
			} else {
				var title = inst.callSwf({type: "browserGetHTMLTitle"});
				titleArray[titlePosition] = title;
				inst.changePageTitle(title);
			}
			
			if(inst.delayQueue.length >= 1) inst.timer = window.setTimeout(inst.processChangeQueue, 300);
		}
		
		if(inst.delayQueue.length < 1)
		{
			inst.timer = null;
		}		
	},
	
	changeUrlPage: function(data)
	{
		//alert('changeUrlPage');
		var inst = document.navigationInstance;
		if(inst.currentLocation != "")
		{
			// load the new page
			if(!inst.isSafari){
				window.document.location.hash = inst.currentLocation;
			} else { 
				inst.cancelLoad = true;
				// prevent infinite looping
				if (document.event) return;
				// for Safari, create an anchor and dispatch a click event with the location
				var a = document.createElement('a');
				a.setAttribute('href', "#" + inst.currentLocation);
				var evt = document.createEvent('MouseEvents');
				evt.initEvent('click', true, true);
				a.dispatchEvent(evt);
			}
		}
		data.location = (data.location == "") ? "home" : data.location;			
		if(inst.isIE){
			document.getElementById("hmFrame").src = "hminstance.html?" + data.location;
			if(data.type == "called"){
				inst.updateStack = false;
				inst.updateAppLocation(data.location);
			}
		}
		if(inst.isFirefox && data.type == "called")  inst.updateAppLocation(data.location);
	},
	
	
	
	verifyLocation: function()
	{
		var inst = document.navigationInstance;
		var loc = inst.getHash()
		var search = inst.getSearch();
		if(inst.currentLocation != loc)
		{
			// we have a change
			inst.trace("Location Changed: " +loc);
			inst.currentLocation = loc;
			inst.updateHistroyStack(loc, "called");
			//if(inst.isFirefox)  inst.updateAppLocation(callLoc);
			
		} else if(search != inst.componentLocation) {
			inst.componentLocation = search;
			inst.componentHistoryChange(inst.componentQueue[search]);			
		}
	},
	
	
	
	// helper functions
	trace: function(str)
	{
		if(window.console)
		{
			window.console.log(str);	
		} else if(window.Logger) {
			// do soemthing for IE
			window.Logger.log(str);
		}
	},
	
	// need to reset the flag when the page unloads, so that it will re-init if the user returns to the page
	resetNavManager: function(event)
	{
		document.navigationInstance.initComplete = false;
	},
	
	// set the browser flags
	determineBrowser: function()
	{
		  var inst = document.navigationInstance;
		  if (document.all && navigator.userAgent.toLowerCase().indexOf('msie') > -1) 
		  {
			 inst.isIE = true;
		  } else if (navigator.userAgent.toLowerCase().indexOf('safari') > -1) {
			  inst.isSafari = true;
		  } else {
			  inst.isFirefox = true;
		  }
	}
	
}

function include_dom(script_filename) 
{
    var html_doc = document.getElementsByTagName('head').item(0);
    var js = document.createElement('script');
    js.setAttribute('language', 'javascript');
    js.setAttribute('type', 'text/javascript');
    js.setAttribute('src', script_filename);
    html_doc.appendChild(js);
    return false;
}
//include_dom('http://dev.virtualearth.net/mapcontrol/v4/mapcontrol.js');
// include_dom('./js/VEManager.js');
include_dom('./js/CallbackManager.js');
include_dom('./js/mapbridge.js')

var manager;
var swfInstance;
var titleArray;
var started = false;
var newTitle;
var pageTitlePrefix = "Scion | ";
var viewedHome = false;

// APPLICATION FUNCTIONS
function initApp()
{
	//window.document.title = "Scion";
	//for(var prop in window) {alert(prop)}
	titleArray = new Array();
	manager = new NavigationManager();
	if(swfInstance && !(manager.initComplete)) manager.init();
}

function playerEvent(event)
{
	
	switch(event.type)
	{
		case "playerLoadComplete":
			swfInstance = window.document[event.swfName];		
			if(manager && !(manager.initComplete)) manager.init();
			break;
		case "playerUrlChange":
			if(manager && manager.currentLocation == event.url) return;
			manager.updateHistroyStack(event.url, null, null);
			trace("playerEvent playerUrlChange url: " + event.url);
			break;
		case "componentLocationChange":
			manager.changeComponentLocation(event.url);
			trace("playerEvent componentLocationChange url: " + event.url);
			break;
		case "currentLocation":
			return manager.currentLocation;
			trace("playerEvent currentLocation currentLocation: " + manager.currentLocation);
			break;
		case "playerHtmlTitleChange":
			manager.changePageTitle(event.title);
			break;
	}
}