
He.Bootstrap("He.Framework.Nav");

He.RequireComponent('He.Application');
He.RequireComponent('He.Application.Back.clientside');
He.RequireComponent('He.Components.LinkSet.clientside');

He.Framework.Nav.ToLift = [];
He.Bootstrap("He.Styles");

He.Framework.Nav.IsSolid = function(_url)
{
	var hash = He.Framework.Nav.root + He.Framework.Nav.nodesep + '#';
	return _url.indexOf(hash) == -1;
};

He.Framework.Nav.MakeWeak = function(_url)
{
	return _url.replace(new RegExp(He.Framework.Nav.root),He.Framework.Nav.root + He.Framework.Nav.nodesep + '#');
};

He.Framework.Nav.MakeSolid = function(_url)
{
	return _url.replace(new RegExp('\/#\/'),'/');
};

He.Framework.Nav.Init = function(_root,_nodesep,_voidlist)
{
	He.Framework.Nav.hold = false;

	if(_root.substr(-1) == '/')
	{
		_root = _root.substr(0,_root.length-1);
	}

	He.Framework.Nav.root = _root;
	He.Framework.Nav.nodesep = _nodesep;
	He.Framework.Nav.voidlist = _voidlist;

	He.Framework.Nav.Wrap(document);

	if(!He.Framework.Nav.IsSolid(document.location.href))
	{
		He.Framework.Nav.prev = null; // force reload to unsolid (Ajaxified)
	}
	else
	{
		He.Framework.Nav.prev = document.location.href;
	}

	He.Framework.Nav.CheckLocation(); // Initiate polling :(

	return true;
};

He.Framework.Nav.Refresh = function()
{
	He.Framework.Nav.Reload(document.location.href);
};

He.Framework.Nav.Wrap = function(_parent)
{
	_parent = $(_parent);
	if(_parent != document)
	{
		He.Components.LinkSet.Activate(_parent);
	}

	var links = _parent.getElementsByTagName('a');
	for(var i = 0; i < links.length; ++i)
	{
		var link = $(links[i]);

		var href = He.Framework.Uri.MakeRelative(link.href);

		if(
			!href || // Test this first for early out
			href == (He.Framework.Nav.root + He.Framework.Nav.nodesep + '#') ||
			href.indexOf('javascript:') != -1 ||
			href.indexOf('void(0)') != -1 ||
			/^#$/.test(href)
		){
			continue;
		}

		if(He.IsArray(He.Framework.Nav.voidlist))
		{
			var cont = false;
			var n = He.Framework.Nav.voidlist.length;

			for(var t = 0; t < n; ++t)
			{
				var reg = new RegExp(He.Framework.Nav.voidlist[t]);
				if(reg.test(href))
				{
					cont = true;
					break;
				}
			}

			if(cont)
			{
				continue;
			}
		}

		var cb = link.onclick;

// 		link.onclick = function(evt)
		link.observe('click',function(evt)
		{
// 			He.Log($A(arguments));
			// Do some cleanup
			var link = evt.target;
			var tag = link.tagName;
			while(tag.toUpperCase() != 'A' && link.parentNode)
			{
				link = link.parentNode;
				tag = link.tagName;
			}
			var href = (He.IsObject(link) ? link.href : He.IsString(link) ? link : '');
			if(!href)
			{
				return true;
			}

			evt.stop(); // Prevent usual navigation

// 			He.Log(evt);
// 			return false;

			// TODO : try to catch default callback
// 			// Execute base callback
// 			if(cb)
// 			{
// 				if(He.IsFunction(cb))
// 				{
// 					ret = cb.apply($A(arguments));
// 				}
// 				else if(He.IsString(cb))
// 				{
// 					var js = cb.indexOf('javascript:');
// 					if(js > -1)
// 					{
// 						cb = cb.substr(js + 11);
// 					}
// 					ret = eval(cb);
// 				}
//
// 				He.Log(typeof(ret), ' : ', ret === false ? 'false' : ret);
//
// 				// Behave as expected
// 				if(ret === false)
// 				{
// 					return false;
// 				}
// 			}

			// Do some tracking but later
			He.Application.Back.Click.defer(evt,href);

			if(He.Framework.Nav.CheckExternal(link.href))
			{
				return false;
			}

			if(He.Framework.Nav.IsSolid(document.location.href))
			{
				href = He.Framework.Nav.MakeWeak(href);
				document.location.href = href;
			}
			else
			{
				// Follow and manage (ajaxify) actual click
				He.Framework.Nav.ClickLink(href);
			}
			return false;
		});
	}
};

He.Framework.Nav.CheckExternal = function(_href)
{
	var abs = He.Framework.Uri.IsAbsolute(_href);
	var nr = _href.indexOf(He.Framework.Nav.root);
	if(abs && nr != 0)
	{
		He.Log('External Link : ',_href);

		window.open(_href);
		return true;
	}
	return false;
};

He.Framework.Nav.Reload = function(_href,_prev)
{
	if(!_href)
	{
		// Have the 'solidified' current url
		_href = He.Framework.Nav.MakeSolid(document.location.href);
	}
	if(!_prev)
	{
		// force to site's root
		_prev = He.Framework.Nav.root + He.Framework.Nav.nodesep;
	}

	// If url is not 'solid'
	if(!He.Framework.Nav.IsSolid(_href))
	{
		// Replace _Root node with complete render of 'solid' url
		_href = He.Framework.Nav.MakeSolid(_href);

		var target = $(He.Application.GetName() + '_Root');
		if(!target)
		{
			He.Error('Target : ' + He.Application.GetName() + '_Root NOT found.');
		}

		He.Framework.Nav.LiftStylesheets(_prev,decodeURIComponent(document.location.href)); // Actually disabled
		var diff = He.Framework.Nav.UrlDiff(_prev,decodeURIComponent(document.location.href));

		document.loaded = false; //
		He.Framework.Ajax.Update(target,_href,{forceall:true},function()
		{
			document.fire('clickedlink:loaded',_href);

			He.Framework.Nav.Wrap(target);
			var hash = He.Framework.Uri.MakeRelative(decodeURIComponent(document.location.href));
			if(hash.indexOf('#') != -1)
			{
				hash = hash.split('#')[1];
				He.Framework.Nav.ScrollToElement(hash);
			}

			document.loaded = true;
			document.fire("dom:loaded");	// This wasn't necessary some times ago but eventually stopped
																		// working as it did.. So fire dom:loaded explicitely
		});

		He.Log('Updating : ',_href);
	}
	else
	{
		// Replace 'solid' location with 'unsolid' url
		// CheckLocation will call this function again and cause the above
		_href = He.Framework.Nav.MakeWeak(_href);

		document.location.href = _href;
		He.Log('Reloading : ',_href);
	}
};

He.Framework.Nav.CheckLocation = function()
{
	var location = document.location.href;
	if(location != He.Framework.Nav.prev)
	{
		var prev = He.Framework.Nav.prev;
		He.Framework.Nav.prev = location;
		if(He.Framework.Nav.hold != true)
		{
			He.Framework.Nav.Reload(location,prev);
		}
		He.Framework.Nav.hold = false;
	}

	if(He.Framework.Nav.stop_poll)
	{
		He.Framework.Nav.CheckLocation.pe.stop();
		delete(He.Framework.Nav.CheckLocation.pe);

		return;
	}

	if(!He.Framework.Nav.CheckLocation.pe)
	{
		He.Framework.Nav.CheckLocation.pe = new PeriodicalExecuter(He.Framework.Nav.CheckLocation,0.2);
	}
};

He.Framework.Nav.RefreshArea = function(_href, _tl, _target)
{
	if(_href.charAt(0) == '#')
	{
		_href = _href.substr(1);
	}

	if(_href.substr(0,11) == 'javascript:')
	{
		return eval(_href.substr(11));
	}

	var path = He.Framework.Uri.MakeRelative(_href);

	if(document.location.hash != '#' + path)
	{
		var e = document.fire('clickedlink:before',_href);
		if(e.stopped === true)
		{
			return false;
		}

		He.Framework.Nav.LiftStylesheets(decodeURIComponent(document.location.href),path); // Actually disabled

		_target = $(_target)
		_target.fire('node:unloading');

		He.LogClear();

		document.loaded = false;

		He.Framework.Ajax.Update(_target,_href,{tl:_tl},function()
		{
			document.fire('clickedlink:loaded',_href);

			He.Framework.Nav.Wrap(_target);

			document.loaded = true;
			document.fire("dom:loaded");	// This wasn't necessary some times ago but eventually stopped
																		// working as it did.. So fire dom:loaded explicitely
		});

		document.fire('clickedlink:after',_href);

		He.Framework.Nav.hold = true; // Prevent He.Framework.Nav.Reload
		document.location.hash = path;
	}

	return false;
};

He.Framework.Nav.ClickLink = function(_href)
{
	if(_href.charAt(0) == '#')
	{
		_href = _href.substr(1);
	}

	if(_href.substr(0,11) == 'javascript:')
	{
		return eval(_href.substr(11));
	}

	if(He.Framework.Nav.CheckExternal(_href))
	{
		return false;
	}

	var nupath = He.Framework.Uri.MakeRelative(_href);
	var nuhash = nupath.indexOf('#');
	if(nuhash >= 0)
	{
		nuhash = nupath.split('#');
		nupath = nuhash[0];
		nuhash = nuhash[1];
		if(nupath.substr(-1) == '/')
		{
			nupath = nupath.substring(0,nupath.length - 1)
		}
	}

	var olpath = decodeURIComponent(document.location.hash).substr(1);
	var olhash = olpath.indexOf('#');
	if(olhash >= 0)
	{
		olhash = olpath.split('#');
		olpath = olhash[0];
		olhash = olhash[1];
		if(olpath.substr(-1) == '/')
		{
			olpath = olpath.substring(0,olpath.length - 1)
		}
	}

	if(olpath != nupath)
	{
		if(nuhash != -1)
		{
			nupath = nupath+'#'+nuhash;
		}
		var e = document.fire('clickedlink:before',_href);
		if(e.stopped === true)
		{
			return false;
		}

		He.Framework.Nav.LiftStylesheets(decodeURIComponent(document.location.href),nupath); // Actually disabled
		var diff = He.Framework.Nav.UrlDiff(decodeURIComponent(document.location.href),nupath);

		var target = $$('.node_cnt_' + diff.level)[0];

		target.fire('node:unloading');

		He.LogClear();

		document.loaded = false; //
		He.Framework.Ajax.Update(target,_href,{tl:diff.level},function()
		{
			document.fire('clickedlink:loaded',_href);

			He.Framework.Nav.Wrap(target);

			document.loaded = true;
			document.fire("dom:loaded");	// This wasn't necessary some times ago but eventually stopped
																		// working as it did.. So fire dom:loaded explicitely
		});

		document.fire('clickedlink:after',_href);

		He.Framework.Nav.hold = true; // Prevent He.Framework.Nav.Reload
		document.location.hash = nupath;
	}
	else if(olhash != nuhash)
	{
		if(nuhash != -1)
		{
			nupath = nupath+'#'+nuhash;
		}
		He.Framework.Nav.hold = true; // Prevent He.Framework.Nav.Reload
		document.location.hash = nupath;
		He.Framework.Nav.ScrollToElement(nuhash);
	}

	return false;
};

He.Framework.Nav.UrlDiff = function(_src,_dst,_params)
{
	var i,n;

	_src = He.Framework.Uri.MakeRelative(_src);
	if(_src.charAt(0) == '/')
	{
		_src = _src.substr(1);
	}
	var u1 = _src.split('/');
	if(_params)
	{
		n = u1.length;
		for(i = 0; i < n; ++i)
		{
			u1[i] = u1[i].split(':')[0];
		}
	}

	_dst = He.Framework.Uri.MakeRelative(_dst);
	if(_dst.charAt(0) == '/')
	{
		_dst = _dst.substr(1);
	}
	var u2 = _dst.split('/');
	if(_params)
	{
		n = u2.length;
		for(i = 0; i < n; ++i)
		{
			u2[i] = u2[i].split(':')[0];
		}
	}

	var level = 0;

	var max = Math.min(u1.length,u2.length);

	while(u1[level] == u2[level] && (level < max))
	{
		++level;
	}

	return {level:level,u1:u1,u2:u2};
};

He.Framework.Nav.LiftStylesheets = function(_from,_to)
{
	return;
	// Functionnality is disabled
	var diff = He.Framework.Nav.UrlDiff(_from,_to,true);

	if(!He.IsArray(diff.u1) || diff.level >= diff.u1.length)
	{
		// Do not remove pure ancestors
		return;
	}

	var from = '';
	var n = diff.u1.length;

	for(var i = 0; i<n && i<=diff.level; ++i)
	{
		from += '/' + diff.u1[i].split(':')[0];
	}

	from = He.Framework.Uri.MakeAbsolute(from);

	var static = He.Framework.Uri.MakeAbsolute('/Static'); // Only remove
	var component = He.Framework.Uri.MakeAbsolute('/He');  // css from trunk

	var sheets = document.getElementsByTagName('link');//$$("link.[rel=stylesheet]");
	var n = sheets.length;
	for(var i = 0; i<n; ++i)
	{
		var sheet = sheets[i];
		if(sheet.rel=='stylesheet')
		{
			var href = sheet.href;
			if(
				href.indexOf(from) == 0 &&
				href.indexOf(static) == -1 &&
				href.indexOf(component) == -1
			){
				// defer removal
				He.Framework.Nav.ToLift.push(sheet);
			}
		}
	}
}

He.Framework.Nav.PurgeStylesheets = function(_element)
{
	while(He.Framework.Nav.ToLift.length)
	{
		var sheet = He.Framework.Nav.ToLift.shift();

		He.Styles[sheet.href] = null;
		sheet.parentNode.removeChild(sheet);
	}
}

He.Framework.Nav.ScrollToElement = function(_element)
{
	_element = $(_element);
	if(_element)
	{
		$(_element).scrollTo();
		new Effect.Highlight(_element, { duration: 3.0, startcolor: '#dcddde', restorecolor: 'transparent' });
	}
};
