function Navigator(param_sitemap, param_locale , param_showlocale  , param_ignore404  ) {
	Navigator.instance = this;
	this._sitemap = param_sitemap;	
	this._currentLocale = param_locale;
	this._showLocaleInURL  = param_showlocale != undefined ? param_showlocale : true;
	this._ignore404 = param_ignore404 != undefined? param_ignore404 : true;
	this._currentMap;
	this._currentChunks;
	this._urlBuffer = [];
	this._lastURL = '';
	this._active = true;
	this._bridge;
	this._autoFreezeCanvas;
	this._autoFreeze;
};


Navigator.getInstance = function(){
	if(Navigator.instance != undefined)
		return Navigator.instance;
};

Navigator.prototype = {

	FREEZE:'freeze',
	UNFREEZE:'unfreeze',

	init:function() {
		this.parseAddress();
		SWFAddress.addEventListener(SWFAddressEvent.EXTERNAL_CHANGE  , $.proxy(this.handleUrlChange, this) );
		SWFAddress.addEventListener(SWFAddressEvent.INTERNAL_CHANGE  , $.proxy(this.handleUrlChange, this));
	},
	
	
	toggleActive:function(param_to) {
		this._active = param_to;
	},
	
	
	getCurrentMap:function() {
		return this._currentMap.concat();
	},
	
	getCurrentChunks:function() {
		return this._currentChunks.concat();
	},
	
	
	makeURL:function(path ,  param_locale){
		var url = '/';
		if(this._showLocaleInURL)
			url += (param_locale == undefined ? this._currentLocale  : param_locale ) + '/';
		url += path.join('/');
		return url;
	},
	
	
	makeURLFromIdList:function(){
		if(arguments.length  == 0){
			console.error('Navigator.makeURLFromIdList() : need at least 1 parameter');
			return '';
		}
		
		var tabUrl = [];
		var len = args.length;
		var obj = this._sitemap.getSectionById(arguments[0]);
		tabUrl.push(obj.url);
		for(var i = 1; i < len ; i++){
			obj = this._sitemap.getChildNodeById(obj , args[i]);
			if(obj)
				tabUrl.push(obj.url);
			else{
				console.error('Navigator.makeURLFromIdList() failed');
				break;
			}
		} 
		return this.makeURL(tabUrl);
	},
	
	
	handleUrlChange:function(e) {
		if(e.type == SWFAddressEvent.INTERNAL_CHANGE || (e.type == SWFAddressEvent.EXTERNAL_CHANGE && this._active))
			this.parseAddress();
		else
			SWFAddress.setValue(this._lastURL)	
	},
	
	
	parseAddress:function() {
		if (this._lastURL == SWFAddress.getValue()) {
			console.log('Navigator : current url identical to last url : no action to be taken');
			return;
		}
		
		var tabUrl = StringUtils.removeEmptyValues(SWFAddress.getValue().split("/"));
		var baseIndex = this._showLocaleInURL ? 1 : 0;
		var pageTitle = [this._sitemap.tree()['default_title']];
		var map = [];
		var testNode;
		var remote;
		var truncatedURL;
		
		this._currentChunks = tabUrl.concat();
		if(this._showLocaleInURL)
			this._currentChunks.shift();
		
		// Pas d'url définie -> redirection vers l'url par défaut
		if (!tabUrl[baseIndex] ||  tabUrl[baseIndex] == ''  ) {
			var current = this;
			setTimeout(
				function(){
					var url = current.makeURL([current._sitemap.tree()['sections'][current._sitemap.tree()['defaultSectionId']].url]);
					SWFAddress.setValue(url);
				} , 
				
				200  );
			return;
		}
		
		// Itération sur les tronçons de l'url 
		var urlLength = tabUrl.length;
		for (var i = baseIndex ; i < urlLength ; ++i) {
			

			if (remote) {
				SWFAddress.setTitle(pageTitle.join(' - '));
				truncatedURL = tabUrl.concat();
				truncatedURL.splice(0 , i );
				return;
			}
			
			testNode = this._sitemap.isNode(tabUrl[i] , map);
			if (testNode == -1) {
				// le  noeud n'existe pas
				if (!this._ignore404){
					//dispatchEvent(new NavigationEvent(NavigationEvent.PAGE_NOT_FOUND , _lastURL , map)) ;
				}
				else 
					this.silent404(map);
				return;
			}
			else {
				map.push(testNode);
				var nodeInfo = this._sitemap.getNode(map)
				var title = nodeInfo.title;
				if (nodeInfo.hasOwnProperty('force_title') && nodeInfo.force_title)
					pageTitle = [];
				if(title != '')
					pageTitle.push(title);
				
				remote = nodeInfo.remote == true;
				if (remote && nodeInfo.remoteauthority == '') 
					break;
			}
		}
	
		this._lastURL = SWFAddress.getValue();
		SWFAddress.setTitle(pageTitle.join(' - '));
		this._currentMap = map;
		$(document).trigger('URL_CHANGE' , [this._lastURL ,this.getCurrentMap()]);
	},
	

	silent404:function(param_map) {
		console.log('Navigator : current map ' + param_map + 'is 404');
		var chunks = [];
		var slice;
		var tabLength = param_map.length;
		for (var i = 0; i < tabLength ; ++i) {
			slice = param_map.slice(0 , i + 1);
			chunks.push(_sitemap.getNode(slice).url)
		}
		this._active = true;
		this.gotoURL(this.makeURL(chunks));
	},
		
	
	getLevelUp:function() {
		var tabUrl = StringUtils.removeEmptyValues(SWFAddress.getValue().split("/"));
		tabUrl.splice(tabUrl.length - 1 , 1);
		return tabUrl.join('/');
	},
	
	
	getLevelDown:function(param_append)  {
		var tabUrl = StringUtils.removeEmptyValues(SWFAddress.getValue().split("/"));
		tabUrl.push(param_append);
		return tabUrl.join('/');
	},
	
	
	getSameLevel:function(param_append) {
		var tabUrl = StringUtils.removeEmptyValues(SWFAddress.getValue().split("/"));
		tabUrl.splice(tabUrl.length - 1 , 1);
		tabUrl.push(param_append);
		return tabUrl.join('/');
	},
	
	
	gotoURL:function(param_url ,  param_freeze_canvas, param_freeze_navigation) {
		if (param_url == SWFAddress.getValue() || !this._active)
			return false;
		if (param_freeze_navigation == undefined) 
			this.toggleActive(!this._autoFreeze);
		else
			this.toggleActive(param_freeze_navigation == Navigator.prototype.FREEZE ? false : true);
	
	console.log('goto' + param_url);
		SWFAddress.setValue(param_url);
	},
	
	
	gotoMap:function(param_map , param_freeze_canvas, param_freeze_navigation) {
		var chunks = this._sitemap.mapToChunks(param_map);
		var url = this.makeURL(chunks);
		this.gotoURL(url, param_freeze_canvas, param_freeze_navigation);
	},
	
	
	gotoSectionId:function(param_id , param_freeze_canvas, param_freeze_navigation) {
		var sectionURL = this._sitemap.getSectionById(param_id).url;
		var url = this.makeURL([sectionURL]);
		this.gotoURL(url, param_freeze_canvas, param_freeze_navigation);
	},
	
	
};
