/**
 * Iddrinet 2009
 * 
 * archibald@picq.fr
 * 
 * http://www.picq.fr/
 */

/**
 * This allows for console.*() calls even if Firebug is not installed
 */
if (!window.console || !console.firebug) {
	window.console = {};
	for (var i in {log:1,debug:1,info:1,warn:1,error:1,assert:1,dir:1,dirxml:1,
		group:1,groupEnd:1,time:1,timeEnd:1,count:1,trace:1,profile:1,profileEnd:1})
		window.console[i] = function(){};
}

String.prototype.remove_scripts = function() {
	var p = this.indexOf('<script');
	
	var html = '';
	var tmp = ''+this;
	var scripts = [];
	while ((pos = tmp.indexOf('<script')) !== -1) {

		html += tmp.substr(0, pos);
		if ((pos2 = tmp.indexOf('</script>', pos)) !== -1) {
			var script = tmp.substr(pos+'<script'.length, pos2-(pos+'<script'.length));
			script = script.substr(script.indexOf('>')+1);
			if (script.indexOf('<!--') != -1)
				script = script.substr(script.indexOf('<!--')+4);
			if (script.lastIndexOf('-->') != -1)
				script = script.substr(0, script.lastIndexOf('-->'));
			scripts.push(script);
			tmp = tmp.substr(pos2+'</script>'.length);
		}
		else {
			html += tmp+'</script>';
			tmp = '';
		}
	}
	html += tmp;
	return [html, scripts];
};
function	ucfirst(t) {
	return t.charAt(0).toUpperCase()+t.substr(1);
};

/**
 * The replacement function that load scripts file using a <script> tag
 *  - script file are no longer loader using the _=875674548 param (force uncaching)
 *  - script file know their own source location (<script src="..." />)
 *  - script file are no longer shown in XHR tab in firebug
 *  - best thing off all of that: debugguers understand the script file as a script file
 *                                and are able to designate exception's lines
 */
(function(){
var jAjax = jQuery.ajax;
var jXhr = jQuery.ajaxSettings.xhr;
jQuery.ajaxSettings.xhr = function() {
	try {return jXhr();}catch(e){}
	try  {return new XMLHttpRequest();}catch(e){}
	alert("Impossible de communiquer avec le serveur.\n\n" +
			"Veuillez activer l'ActiveX permettant les requêtes XML ou\n" +
			"approuver le domaine « "+document.domain+" » dans votre zone de confiance");
	return null;
};

jQuery.ajaxSubmitSettings = {
	error: function(json, form, ondone) {
//		console.info('NForm');
		jQuery.errorAlert({
			className: 'error '+this.errorClassName,
			title: this.errorTitle || 'Erreur de validation',
			text: json.error,
			ok: ondone
		});
		return false;
	}
};

jQuery.ajaxSetup({
	error: function(info, status) {
		if (status == 'notmodified')
			return ;
		if ((!this.oldError || this.oldError(info) !== false) && this.dataType === 'json') {
			jQuery.errorAlert({
				className: 'error '+this.errorClassName,
				title: this.errorTitle || 'Erreur de communication',
				text: info
			});
		}
	}
});

function	dispatchException(e, ajax, ondone) {
	if (e == 'NotLoggued') {
		Application.authenticated(function() {
			delete jQuery.lastModified[ajax.url];
			jQuery.ajax(ajax);
		});
		return true;
	}
	return false;
};

var iframe = {};
function	loadIframeProxy(host, loaded) {
	var dom = getdomain(host);
	try {window.document.domain = dom;}
	catch(e) {console.warn('failed to set the domain');}
	if (iframe[dom])
		return loaded(iframe[dom][0].contentWindow.xhr);
	iframe[dom] = jQuery('<iframe src="http://'+host+'/library/iframeproxy.html" style="display:none"></iframe>');
	iframe[dom].load(function() {
		iframe[dom][0].contentWindow.eval((jQuery.cookie('auth')? 'window.document.cookie="auth='+jQuery.cookie('auth')+'; expires=; path=/";': '')+'window.xhr='+jXhr);
		loaded(iframe[dom][0].contentWindow.xhr);
	}).error(function(){
		console.info('error while loading iframe proxy');
	}).appendTo(document.body);
};
window.commonDomain = function(d1, d2) {
	if (d1 == d2)
		return d1;
	for (var i=1, d1 = d1.split('.'), d2 = d2.split('.'); (i<d1.length || i<d2.length) && d1[d1.length-i] == d2[d2.length-i]; i++)
		;
	return d1.slice(d1.length-i+1).join('.');
};
var selfdomain = window.document.domain;
function	diffDomain(url) {
	var host = gethost(url);
	if (host == selfdomain)
		return false;
	if (('.'+host).indexOf('.'+dom) == ('.'+host).length - ('.'+dom).length)
		return false;

	var dom = window.document.domain;
	if (host != dom && ('.'+host).indexOf('.'+dom) == ('.'+host).length - ('.'+dom).length)
		return host;
	for (var p; (p=dom.indexOf('.')) >= 0 && p < dom.length-4;)
		dom = dom.substr(p+1);
	if (dom == window.document.domain)
		return false;
	if (host != dom && ('.'+host).indexOf('.'+dom) == ('.'+host).length - ('.'+dom).length)
		return host;
	return false;
};
function	gethost(url) {
	var m = url.match(/^https?\:\/\/([^\/]*)\/.*$/);
	return (m? m[1]: m) || gethost(location.href);
};
window.getdomain = function() {
	var dom = window.document.domain;
	for (var p; (p=dom.indexOf('.')) >= 0 && p < dom.length-4;)
		dom = dom.substr(p+1);
	return dom;
};
function	cdAjax(s) {
	var host = diffDomain(s.url);
	return !host? myAjax(s): loadIframeProxy(host, function(func) {
		s.xhr = func;
		var success = s.success;
		var dom = getdomain(host);
		s.success = function() {
			var cookie = iframe[dom][0].contentWindow.eval('window.document.cookie');
			var cookies = cookie.split('; ');
			for (var i = 0; i<cookies.length; i++) {
				var tab = cookies[i].split('=');
				jQuery.cookie(tab[0], tab[1]);
			}
			success.apply(s, arguments);
		};
		myAjax(s);
	});
};

function	myAjax(s) {
	if (s.url && s.url.charAt(0) == '?') {
		var prefix = (''+window.location.href).match(/http[s]?\:\/\/[\-.\w]+([^#.]*)/);
		if (prefix)
			s.url = prefix[1]+s.url;
	}
	s.oldError = s.error;
	s = jQuery.extend({}, jQuery.ajaxSettings, s);

	var oldSuccess = s.success;
	s.error = jQuery.ajaxSettings.error;
	s.success = function(json) {
		if (typeof json['exception'] == 'string' && dispatchException(json['exception'], s))
			return ;
		if (json.response !== true && typeof json.length != 'number')
			return this.error(json);

		if (jQuery.cookie('dexc')=='1') {
			if (oldSuccess)
				oldSuccess.apply(this, [json]);
		}
		else {
			try {
				if (oldSuccess)
					oldSuccess.apply(this, [json]);
			}catch(e){
				warnException(e, function() {});
				throw e;
			}
		}
	};
	
	if (s.dataType != 'script' || !s.async)
		return jAjax(s);
	s.global && !jQuery.active++ && jQuery.event.trigger('ajaxStart');
	var xml = jQuery.extend(document.createElement('script'), {
		type: 'text/javascript',
		src: s.url,
		onload: function(e) {
			onreadystatechange('success');
		},
		onreadystatechange: function(e) {
			if (typeof(this.readyState)=='string' && this.readyState!='loaded' && this.readyState!='complete')return ;
			onreadystatechange('success');
		},
		onerror: function(e) {
			onreadystatechange('failed');
		}
	});
	s.beforeSend && s.beforeSend(xml);
	s.global && jQuery.event.trigger('ajaxSend', [xml, s]);
	var ival = null, requestDone = false, onreadystatechange = function(status) {
		if (requestDone)
			return ;
		requestDone = true;
		ival && clearInterval(ival) && (ival = null);
		if (status == 'success') {
			s.ifModified && modRes && (jQuery.lastModified[s.url] = modRes);
			s.success && s.success('', status);
			s.global && jQuery.event.trigger('ajaxSuccess', [xml, s] );
		} else
			jQuery.handleError(s, xml, status);
		s.global && jQuery.event.trigger('ajaxComplete', [xml, s]);
		s.global && ! --jQuery.active && jQuery.event.trigger('ajaxStop');
		s.complete && s.complete(xml, status);
		xml.parentNode.removeChild(xml);
		xml = null;
	};
	s.timeout > 0 && setTimeout(onreadystatechange, s.timeout);
	return document.getElementsByTagName('head')[0].appendChild(xml);
};

jQuery.extend({
	ajax: cdAjax
});
})();

jQuery.extend({
	unparam: function(str) {
		str = str.split('&');
		var opts = {};
		for (var i = 0; i < str.length; i++) {
			var spt = str[i].indexOf('=');
			var name = spt >= 0? str[i].substr(0, spt): str[i];
			if (!name)
				continue ;
			var value = spt >= 0? str[i].substr(spt+1): undefined;
			opts[name] = decodeURIComponent(value? value.replace(/\+/g, ' '): '');
		}
		return opts;
	},
	params: function(obj) {
		var t = '';
		for (var i in obj)
			if (obj[i])
				t += (t? '&': '')+i+'='+encodeURIComponent(obj[i]);
		return t.replace(/\'/g, '%27').replace(/%40/g, '@');
	}
});

(function() {
	var basetitle = (''+document.title).replace(/\s+\(svn-rev:\s[0-9]+\)$/, ''),
		svnrev = (''+document.title).substr(basetitle.length),
		saveIval = null,
		ivRfrsh = null;
	if (!window.server)
		window.server = '';

	var previous = '';
	jQuery.extend(window, {
		serverTimeOffset: (new Date()).getTimezoneOffset() * 60,
		UserConfig: null,
		CommonConfig: null,
		LocalConfig: null,
		setTitle: function(title) {
			document.title = basetitle+' : '+title+(jQuery.dm? svnrev: '');
		},
		callApp: function(child, action, params) {
			var app = child.length? (child.is('.app')? child: child.parents('.app:first')): jQuery('.ui-active:last');
			for (; app && app.length; app=app.parents('.app:first'))
				if (app.data('app') && app.data('app')[action])
					return typeof app.data('app')[action]=='function'? app.data('app')[action](params): app.data('app')[action].click(params);
			jQuery.message("Aucune action à effectuer");
		},
		launchApp: function(path, options) {
			var prev = previous;
//			console.info('launchApp('+path+') from '+prev);
			options = options || {};
			path = path.replace(/\-/g, '.').split('.');
			var loadfailed = false;
			var currentInto = null;
			var currentRest = null;
			function	execAppli(into, rest) {
				var ret = null;
				var name = rest[0];
				var rest = rest.slice(1);
				currentRest = rest;
				currentInto = into[name];
				if (!into[name])
					return false;	// application not declared or not previously loaded
				else if (rest.length)
					return execAppli(into[name], rest);
//				console.group('launched('+name+'): ');
				previous = '';
				ret = into[name](options);
				previous = prev;
//				console.info('ret: '+ret+' (dispatching: '+launchApp.dispatching+', current: '+window.location+')');
				if (ret !== true && ret !== false) {
					if (launchApp.dispatching)
						window.location = launchApp.dispatching;
					else {
						console.warn('no previous url');
						return true;
					}
					return false;
				}
				else if (ret === true) {
					previous = launchApp.dispatching = ''+window.location;
				}
				else if (previous) {
//					console.info('on return false from "'+path+'" rollback to previous: '+previous);
					window.location = previous;
					previous = '';
				}
//				console.groupEnd();
				return true;
			}
			function	actionFailed(faileds, depth, file) {
				var depth = depth || 0;
				var wantlocation = '';
				for (var i in options)
					if (typeof options[i] == 'string' || typeof options[i] == 'number')
						wantlocation += (wantlocation? '&': '')+i+(options[i]!==''?'=':'')+options[i];
				
				wantlocation = '#'+path.join('-')+(wantlocation? '?':'')+wantlocation;//''+window.location;
				
	
				var err = '';
				var title = '';
				if (faileds.length)
					err += (faileds.length==1? "Le fichier « "+faileds[0]+" » n'a pu être chargé.":
						"Les fichiers suivants n'ont pu être chargés :<ul><li>"+faileds.join("</li><li>")+"</li></ul>");
				if (!err) {
					var parsed = [];
					var into = window.Application;
					
					for (var i=0; i<path.length; i++) {
						if (typeof into[path[i]] === 'function') {
							parsed.push(path[i]);
							into = into[path[i]];
							continue ;
						}
						else if (into[path[i]])
							err += 'la variable définie à « Application['+path.slice(0, i+1).join('][')+'] » n\'est pas une fonction.';
						else
							err += 'la variable définie à « Application['+path.slice(0, i+1).join('][')+'] » n\'est pas définie.';
						break ;
					}
					if (!err)
						err += 'l\'application « Application['+path.join('][')+'] » a retournée un code incorrect.';
					if (file)
						err = 'Après chargement du script « '+file+' », '+err;
					
				}
	
				jQuery.customAlert({
					className: 'error notfound',
					title: faileds.length? 'Page introuvable': 'Fonction introuvable',
					text: ucfirst('La page que vous avez demandé n\'a pu être chargée :<ul><li>'+wantlocation+'</li></ul>'),
					details: ucfirst(err),
					buttons: {
						'Aller à la page d\'accueil': function() {
							updateLocation('#home');
						},
						'Annuler': function() {
//							window.location = launchApp.previous;
						}
					}
				});
				if (previous)
					window.location = previous;
				return false;
			}
			function	trySubExec(depth, file) {
				depth < path.length? tryExecAction(depth+1): actionFailed([], depth, file);
			}
			/**
			 * Starts to dispatch the url by trying successive server loading in the hope of finding
			 * the best function for executing the action
			 * recursively try to load javascript until window.Application is fulfilled with the requested action
			 * or, if finaly not found, display an error to the user (actionFailed)
			 */
			function	tryExecAction(depth) {
				if (execAppli(window.Application, path))
					return ;
				jQuery.loadComponent(['view/'+path.slice(0, depth).join('/')+'.js'], function() {
					if (!execAppli(window.Application, path))
						trySubExec(depth, 'view/'+path.slice(0, depth).join('/')+'.js');
				}, false, function(f, retry, cancel) {
					console.dir(f);
					actionFailed(f, depth, 'view/'+path.slice(0, depth).join('/')+'.js');
				});
			}
			/** Start at level 1 */ 
			tryExecAction(1);
		},
		refreshLocation: function() {
			jQuery(document).hashchange();
		},
		updateLocation: function(newurl) {
			if (typeof newurl == 'string')
				window.location = newurl;
			jQuery(document).hashchange(newurl);
		},
		saveUserConfigKey: function(key, saveData) {
			if (!UserConfig)
				return false;
			UserConfig[key] = saveData;
//			saveLocalConfig('UserConfig', UserConfig);
			return saveUserConfig();
		},
 		saveCommonConfigKey: function(key, saveData) {
 			CommonConfig[key] = saveData;
//			saveLocalConfig('CommonConfig', CommonConfig);
			return saveUserConfig();
		},
 		saveUserConfig: function() {
			if (saveIval)
				clearTimeout(saveIval);
			saveIval = setTimeout(function() {
				saveIval = null;
				saveConfigNow(UserConfig, 'user');
				if (jQuery('body').is('.es'))
					saveConfigNow(CommonConfig, 'common');
			}, 1000);
		},
		saveConfigNow: function(config, name) {
			var configstr = JSON.stringify(config);
			if (configstr == backupConfig[name])
				return ;
			backupConfig[name] = configstr;
//			saveLocalConfig('UserConfig', UserConfig);
//			saveLocalConfig('CommonConfig', CommonConfig);
			jQuery.ajax({
				url: window.server+'?ctrl='+name+'&action=saveinfo',
				dataType: 'json',
				type: 'post',
				data: 'config='+encodeURIComponent(configstr),
				success: function(json) {
				},
				error: function(info) {
					console.warn('saveCommonConfig: '+info.error);
					return false;
				}
			});
		},
		isFavorite: function(id) {
			if (!UserConfig || !UserConfig.links)
				return false;
			return !!UserConfig.links[id];	
		},
		addFavorite: function(id, title) {
			if (isFavorite(id))
				return ;
			if (!UserConfig.links)
				UserConfig.links = {};
			UserConfig.links[id] = title;

			var ul = jQuery('#my-favorites .data ul');
			var lii = ul.find('li').filter(function() {return !!jQuery('i', this).length;});
			if (lii.length)
				lii.slideUp(function() {
					lii.remove();
					addLink();
				});
			else
				addLink();
			function	addLink() {
				jQuery('<li class="link search">' +
						'<span class="icon"></span>' +
						'<a href="#'+id+'">'+title+'</a>' +
						'<br/>' +
					'</li>').hide().appendTo(ul).slideDown();
			};
		},
		removeFavorite: function(id) {
			if (!isFavorite(id))
				return ;
			delete UserConfig.links[id];
			var ul = jQuery('#my-favorites .data ul');
			jQuery('#my-favorites .data a').filter(function() {return (this.href.split('#')[1] || '') == id;})
				.parents('li:first')
				.slideUp(function() {
					jQuery(this).remove();
					if (!jQuery('#my-favorites .data a').length)
						jQuery('<li class="link search"><span class="icon"/><i>Aucun favoris</i></li>').hide().appendTo(ul).slideDown();
				});
		},
		applyRights: function() {
			var b = jQuery('body');
			for (var i in LocalConfig.rights)
				b[LocalConfig.rights[i]? 'addClass': 'removeClass'](i);
		},
		applyLogin: function(json) {
			UserConfig = json.UserConfig || {};
			CommonConfig = json.CommonConfig;
			LocalConfig = {};
			for (var i in {name:1,prenom:1,nom:1,email:1,rights:1,advanced_search:1})
				LocalConfig[i] = json[i];
			jQuery('#identification').html('Utilisateur: '+concat_ws(' ', LocalConfig.prenom, LocalConfig.nom, concat('&lt;',LocalConfig.email,'&gt;')));
			applyRights();
			
			/** calcul de la différence entre le serveur et le client */
			serverTimeOffset = Math.floor(((new Date()).getTime()/1000) - parseInt(json.now));

			applySidebarConfig();
			startUserInfoSaver();
//			saveLocalConfig('LocalConfig', LocalConfig);
//			saveLocalConfig('UserConfig', UserConfig);
//			saveLocalConfig('CommonConfig', CommonConfig);
		},
		Application: {
			authenticated: function(onload) {
				if (UserConfig)
					return onload();
				/**
				 * Try to get user config using authentication from previous php session
				 * or using the permanent 'auth' cookie else, display the login dialog box
				 */
				if (!jQuery.cookie('auth') && !jQuery.cookie('PHPSESSID'))
					return launchApp('auth', {success: onload});
				jQuery.ajax({
					url: window.server+'?ctrl=auth&action=login',
					dataType: 'json',
					success: function(json) {
						applyLogin(json);
						onload();
					},
					error: function(info) {
//						console.warn('Query server failed at url '+this.url+(info && info.error? ' '+info.error: ''));
						jQuery.cookie('auth', undefined);
						jQuery.cookie('PHPSESSID', undefined);
						launchApp('auth', {success: onload});
						return false;
					}
				});
			},
			tabbedview: function(onload) {
				/** tabbedview require the sidebarview */
				Application.sidebarview(function() {
					/** Load the left panel and tabulation  components */
					jQuery.loadComponent(['library/js/jquery.tabulation.js'], function(tpl) {
						if (!jQuery('#main-tab').length)
							jQuery('<div id="main-tab">' +
									'<div class="scroller"><span class="right">&nbsp;</span><span class="left">&nbsp;</span></div>' +
									'<div class="scrollable tabs"><ul><li class="home">Home</li></ul></div>' +
									'<div class="data home" id="home"></div>' +
								'</div>').prependTo(jQuery('#main').empty()).tabulation();
						onload();
					});
				});
				return true;
			},
			sidebarview: function(onload) {
				if (jQuery('#sidebar').length)
					return onload();
				jQuery('#content').html(
					'<div id="sidebar" class="zone"></div>' +
					'<div id="main" class="zone"></div>');
				jQuery.loadComponent(['view/sidebar/sidebar.css', 'view/sidebar.html', 'library/js/jquery.taskpanel.js'], function(tpl) {
					var sidebar = jQuery('#sidebar');
					sidebar.html(tpl);
					sidebar.find('li').prepend('<span class="icon"></span>').append('<br />');
					
					sidebar.taskPanel({
						change: function() {
							var newExpanded = {};
							var blocs = [];
							sidebar.find('fieldset').each(function() {
								var self = jQuery(this);
								newExpanded[this.id] = !self.is('.closed');
								var o = {
									libelle: self.find('.title').html(),
									titre: self.attr('title'),
									id: self.attr('id'),
									className: self.attr('class'),
									items: []
								};
								self.find('li').each(function() {
									var li = jQuery(this);
									o.items.push({
										libelle: li.find('a').html(),
										destination: li.find('a').attr('href'),
										titre: li.attr('title'),
										id: li.attr('id'),
										className: li.attr('class')
									});
								});
								blocs.push(o);
							});
							if (CommonConfig) {
								CommonConfig.panel = blocs;
//								saveCommonConfig();
							}
							if (UserConfig) {
								UserConfig.panel = newExpanded;
								saveUserConfig();
							}
						}
					});
					/** dispatch popups and actions links (dont update the url for them, they are interactive actions) */
					sidebar.find('> fieldset .data li.pop a, > fieldset .data li.action a').click(function() {
						var anchor = jQuery(this).attr('href').split('#')[1] || '';
						launchApp(anchor.split('?')[0], jQuery.unparam(anchor.split('?')[1] || ''));
						return false;
					});
			
					applySidebarConfig();
					onload();
				});
				return true;
			},
			layout: function(onload) {
				/** General layout */
				jQuery('body').empty();
				var title = jQuery('head > title').html() || '';
				jQuery.loadComponent(['view/layout.html'], function(tpl) {
					jQuery('body').html(tpl);
					jQuery('body .title').html(title);
		
					/** Resize the content so the footer is at the good height */
					var jwindow = jQuery(window),
						header = jQuery('#header'),
						footer = jQuery('#footer'),
						content = jQuery('#content'),
						sidebar = jQuery('#sidebar'),
						main = jQuery('#main');
					window.winResize = function() {
						var height = jwindow.height()-header.height()-footer.height();
						content.height(height);
						var dataheight = height - 42;
						jQuery('#main-tab > .data').height(dataheight);
						if (jQuery.browser.msie && jQuery.browser.version <= 6) {
							if (!main[0])
								main = jQuery('#main');
							if (!sidebar[0])
								sidebar = jQuery('#sidebar');
							if (sidebar[0] && main[0]) {
								var w = jwindow.width()-sidebar.width()-50;
								main.width(w);
								main.find('> #main-tab > .data').width(w);
							}
								
						}
						
						
						jQuery('#main-tab > .data .rest').each(function() {
							var rest = jQuery(this);
							var data = rest.parents('.data');
							rest.height((dataheight - (rest.offset().top-data.offset().top))-8);
						});
						jQuery('*').filter(':visible').filter(function(){return !!this.winresize;}).each(function(){this.winresize();});
					};
					jQuery(window).resize(winResize).resize();
					
					if (jQuery.browser.msie) {
						if (jQuery.browser.version <= 6.0 && !jQuery.cookie('bypass')) {
							jQuery.loadComponent(['view/ie6banner.html', 'view/ie6banner.css'], function(tpl) {
								content.html(tpl);
								(content[0].winresize = function() {
									var h = content.height();
		//							content.find('> .bloc').height(h - 60);
									content.find('> .bloc > .data').height(h - (content.find('> .bloc > .data').offset().top - content.find('> .bloc').offset().top) - 60);
									console.info(h);
								})();
								content.find('.bypass').click(function() {
									jQuery.cookie('bypass', 1);
								});
							});
							return ;
						}
						jQuery('#header').prepend('<a id="tooCool" href="http://www.w3junkies.com/toocool/" title="Ce site est optimisé pour Firefox, Chrome et Safari">Too Cool for Internet Explorer</a>');
					}
					onload && onload();
				});
			},
			/**
			 * Application.logout action
			 *  asks the user if he realy want to quit his session
			 */
			logout: function() {
				jQuery.warnConfirm({
					title: 'Confirmation de deconnection',
					text: 'Souhaitez vous réelement mettre fin à votre session ?',
					className: 'logout',
					ok: function() {
						jQuery.cookie('auth', '');
						jQuery.cookie('PHPSESSID', '');
						window.location = '';
					}
				});
				return false;
			}
		}
	});
//	function	saveLocalConfig(name, config) {
//		globalStorage[document.domain][name] = JSON.stringify(config);
//	};
//	function	readLocalConfig(name) {
//		eval('var data = ('+globalStorage[document.domain][name]+')') || null;
//		for (var i in data)
//			if (data.prototype && data[i] != data.prototype[i])
//				return data;
//		return null;
//	}
//	var user = readLocalConfig('UserConfig');
//	console.info('user: '+user);
//	if (user) {
//		var common = readLocalConfig('CommonConfig');
//		var local = readLocalConfig('LocalConfig');
//		applyLogin(jQuery.extend(local, {UserConfig:user, CommonConfig: common}));
//	}
	function	applySidebarConfig() {
		if (!UserConfig)
			return ;
		if (UserConfig.panel)
			jQuery('#sidebar .panel').each(function() {
				jQuery(this)[!UserConfig.panel[jQuery(this).attr('id')]? 'addClass': 'removeClass']('closed');
			});
		if (UserConfig.links) {
			var ul = jQuery('#my-favorites .data ul');
			var first = true;
			for (var i in UserConfig.links) {
				if (first) {
					ul.find('li:contains(i)').remove();
					first = false;
				}
				jQuery('<li class="link search">' +
					'<span class="icon"></span>' +
					'<a href="#'+i+'">'+UserConfig.links[i]+'</a>' +
					'<br/>' +
				'</li>').appendTo(ul);
			}
		}
	};
	var timer = null;
	var backupConfig = {};
	function	startUserInfoSaver() {
		if (timer)
			return ;
		backupConfig.user = JSON.stringify(UserConfig);
		backupConfig.common = JSON.stringify(CommonConfig);
		timer = setInterval(saveUserConfig, 10000);
	};
})();

/**
 * Some extension to jQuery
 */
jQuery.extend({
	/** Create a css from a raw text
	 */
	createCss: function(t) {
		var css = null;
		if (document.createStyleSheet)
			css = jQuery.extend(document.createStyleSheet(""), {cssText: t});
		else {
			css = jQuery.extend(document.createElement('style'), {type: 'text/css'});
			css.appendChild(document.createTextNode(t));
			document.getElementsByTagName('head')[0].appendChild(css);
		}
		return jQuery(css);
	},
	/** jQuery COOKIE extension
	 */
	defaultCookiePath: '/',
	deleteCookie: function(name) {
		document.cookie = name + "=;path=/;expires=Thu, 01-Jan-1970 00:00:01 GMT";
	},
	cookie: function(name, value, options) {
		if (typeof value != 'undefined') { // name and value given, set cookie
			options = options || {};
			var expires = '';
			if (options.expires && (typeof options.expires == 'number' || options.expires.toGMTString)) {
				var date;
				if (typeof options.expires == 'number') {
					date = new Date();
					date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
				} else
					date = options.expires;
				expires = '; expires=' + date.toGMTString(); // use expires attribute, max-age is not supported by IE
			}
			var path = '; path='+(options.path || jQuery.defaultCookiePath);
			var domain = options.domain ? '; domain=' + options.domain : '';
			var secure = options.secure ? '; secure' : '';
//			console.warn("Set-Cookie: "+[name, '=', encodeURIComponent(value), expires, path, domain, secure].join(''));
			document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
		} else { // only name given, get cookie
			var cookieValue = null;
			if (document.cookie && document.cookie != '') {
				var cookies = document.cookie.split(';');
				for (var i = 0; i < cookies.length; i++) {
					var cookie = jQuery.trim(cookies[i]);
					// Does this cookie string begin with the name we want?
					if (cookie.substring(0, name.length + 1) == (name + '=')) {
						cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
						break;
					}
				}
			}
			return cookieValue;
		}
	}
});

(function() {
	var unloading = false;
	jQuery(window).unload(function() {
		unloading = true;
	});
	var loaded = {};
	var datas = {};
	var waiting = [];
	var src = jQuery('head > script').filter(function() {return this.src.match(/\/jquery\.addons\.js/);});
	if (!src.length) {
		src = jQuery('script').filter(function() {return this.src.match(/\/jquery\.addons\.js/);});
		if (src.length)
			document.getElementsByTagName('head')[0].appendChild(src[0]);
	}
	src = src.attr('src') || '';
	jQuery.libroot = (src.match(/(.*library[0-9]*\/js\/|.*js[0-9]*\/library\/)jquery\.addons\.js/)||[])[1];
	jQuery.svnrev = ((jQuery.libroot || '').match(/library([0-9]+)\/js\//)||[])[1] || ((jQuery.libroot || '').match(/js([0-9]+)\/library\//)||[])[1];
	if (jQuery.svnrev)
		jQuery.libroot = jQuery.libroot.replace('library'+jQuery.svnrev+'/js/', 'library/js/').replace('js'+jQuery.svnrev+'/library/', 'js/library/');
	console.info('libroot: '+jQuery.libroot);
	console.info('svnrev: '+jQuery.svnrev);
	if (jQuery.cookie('dm')=='1')
		jQuery.svnrev = Math.round(Math.random() * 10000)+10000;
	function	makePath(item) {
		if (!jQuery.svnrev)
			return item;
		for (var i in {js:1, style:1, library:1, view:1})
			if (item.indexOf('/'+i+'/')===0)
				item = '/'+i+jQuery.svnrev+'/'+item.substr(i.length+2);
		return item;
	};
	var host = ''+window.location;
	host = host.substr(host.indexOf('://')+3);
	window.hostname = host.substr(0, host.indexOf('/'));
	
	window.ordered = [];
	var tm = null;
	jQuery.extend({
		defaultLoadError: function(f, onok, oncancel) {
			if (unloading)
				return oncancel();
			setTimeout(function() {
				var question = f.length==1?
					"Le script "+f[0]+" n'a pu être chargé.\n\nVoulez vous réessayer ou continuer sans ce script ?":
					"Les scripts suivants n'ont pu être chargés:\n - "+f.join("\n - ")+"\n\nVoulez vous réessayer ou continuer sans ces scripts ?";
				if (confirm(question))
					onok();
				else
					oncancel();
			}, 1);
		},
		/** Load a css file and call the callback
		 */
		loadCss: function(file, cb) {
//			span.appendTo('#footer');

//			span.html('debug');
			var app = '';
			if (!jQuery.browser.msie) {
				app = '<script type="text/javascript">ordered['+ordered.length+']();ordered['+ordered.length+']=null;</script>';
				ordered.push(cb);
			}
			var css = jQuery('<link type="text/css" rel="stylesheet" />'+app).appendTo('head:first');
			css.attr({href:file});
			if (!jQuery.browser.msie) {
				if (tm)
					clearTimeout(tm);
				tm = setTimeout(function() {
					tm = null;
					jQuery(window).trigger('resize');
				}, 2000);
				return ;//(!cb || cb());
			}
			var t1 = new Date();
			
			function	readyState() {
				var t2 = new Date();
				if (css[0].readyState == 'complete' || t2 - t1 > 2000) {
					clearInterval(ival);
					if (cb)cb();
				}
			}
			var ival = setInterval(readyState, 20);
		},
		/** Load a template from the server (usually HTML) then call the callback function with the content
		 */
		loadTemplate: function(file, cb) {
			return jQuery.ajax({
				url: file,
				type: 'get',
				dataType: 'html',
				success: function(text) {
					return !cb || cb(text);
				}
			});
		},
		/** Load a JavaScript multiple components if not loaded, then call the callback,
		 * if retry is not provided, do not retry to download a script if first time failed
		 */
		loadComponent: function() {
			var args = jQuery.loadComponent.arguments;
//			console.info(args);
			var cmpts = args[0];
			if (args[1] && typeof args[1] != 'function')
				return jQuery.loadComponent(cmpts, function() {
					var newparams = [];
					for (var i = 1; i<args.length; i++)
						newparams.push(args[i]);
					jQuery.loadComponent.apply(this, newparams);
				});
			var cb = args[1] || function(){};
			var retry = args[2] || false;
			var error = args[3];
			
			if (typeof cmpts == 'string')
				cmpts = [cmpts];
			for (var i=0; i<cmpts.length; i++) {
				var cmpt = cmpts[i];
				if (cmpt && cmpt.charAt(0) != '/' && cmpt.indexOf('://') === -1) {
					var url = (''+window.location).split('#')[0];
					url = url.substr(url.indexOf('/', 8));
					url = url.lastIndexOf('/') != -1? url.substr(0, url.lastIndexOf('/')+1): url;
					cmpts[i] = url+cmpt;
				}
			}
//			console.info('loadComponent for '+cmpts.join(', '));
			var data = '';
			waiting.push({components: cmpts, cb: cb});
			function	load_missing(toload) {
				var loading = false;
				jQuery(toload).each(function(i, cmpt) {
					if (!cmpt || loaded[cmpt] == 'loaded')
						return ;
					else if (loaded[cmpt] == 'loading') {
						loading = true;
						return ;
					}
					else if (!loaded[cmpt] || (loaded[cmpt] == 'failed' && retry)) {
						loaded[cmpt] = 'loading';
						loading = true;
						if (cmpt.match(/\.css$/)) {
							jQuery.loadCss(makePath(cmpt), function() {
								loaded[cmpt] = 'loaded';
								componentLoaded();
							});
						}
						else if (cmpt.match(/\.html|\.php|\.tpl$/)) {
							jQuery.loadTemplate(makePath(cmpt), function(tpl) {
								data += tpl;
								datas[cmpt] = tpl;
								loaded[cmpt] = 'loaded';
								componentLoaded();
							});
						}
						else if (cmpt.match(/\.js$/)) {
							jQuery.ajax({
								url: makePath(cmpt),
								dataType: 'script',
								success: function() {
									loaded[cmpt] = 'loaded';
									componentLoaded();
								},
								error: function() {
									loaded[cmpt] = 'failed';
									componentLoaded();
								}
							});
						}
						else
							loading = false;
					}
				});
				retry = false;
				return loading;
			};
			function	componentLoaded() {
//				console.info('pending cb: '+waiting.length);
				for (var i=0; i<waiting.length; ) {
					var miss = load_missing(waiting[i].components);
					if (!miss) {
						var wait = waiting[i];
//						console.info('callback is ready: '+wait.components.join(', '));
//						console.dir(loaded);
						waiting.splice(i, 1);
						execOrRetry(wait.components, wait.cb);
					}
					else
						i++;
				}
			};
			function	execOrRetry(require, cb) {
				var data = '';
				for (var i=0; i<require.length; i++)
					if (require[i] && require[i].match(/\.html|\.php|\.tpl$/))
						data += datas[require[i]];
				var a=true,
					f = [];
				for (var i = 0, l=require.length; i<l; i++)
					if (!require[i])
						continue ;
					else if (loaded[require[i]] == 'failed')
						f.push(require[i]);
					else if (loaded[require[i]] != 'loaded')
						a = false;
				if (a && !f.length)
					return cb(data);
				else if (!a)
					return ;
				else if (f.length) {
					(error || jQuery.defaultLoadError)(f, function() {
						retry = true;
						waiting.push({components: require, cb: cb});
						load_missing(require);
					}, function() {
						cb(data);
					});
					return ;
				}
				cb(data);
			};
			componentLoaded();
		}
	});
	var docs = [];
	jQuery.fn.hashchange = function(func, prev) {
		var self = this;
		this.each(function() {
			if (typeof func == 'function') {
				var doc = this;
				var data = jQuery.data(doc, 'hashchange');
				if (!data)
					jQuery.data(doc, 'hashchange', (data = {callbacks:[]}));
				data.callbacks.push(func);
				if (!data.ival)
					data.ival = setInterval(function() {
						if (data.prev == doc.location.href)
							return ;
						self.hashchange((''+doc.location.href), data.prev);
					}, 200);
			}
			else if (typeof func == 'string') {
				var anchor = (func || ''+this.location.href).split('#')[1] || '';
				var data = jQuery.data(this, 'hashchange');
				if (!data)
					return ;
				for (var i=0; i<data.callbacks.length; i++)
					if (data.callbacks[i](anchor, prev) === false)
						return false;
				data.prev = ((''+this.location.href).split('#')[0])+(anchor? '#'+anchor: '');
			}
			return this;
		});
		return this;
	};
})();
jQuery.fn.extend({
	disable: function(){this.each(function(){this.disabled=true;jQuery(this).addClass('disabled');});return this;},
	enable: function(){this.each(function(){this.disabled=false;jQuery(this).removeClass('disabled');});return this;}
});


/**	Loading progress bar
 *	display a progress bar in the upper right corner while doing
 *	asynchronous request
 * 		use:
 * 			Loading.start();
 * 			Loading.stop();
 */

if (!window.Loading)
(function(){
	/**	Private variables */
	var blocs = 3,	//!< contiguous highlighted blocs
		speed = 65,//!< refreshing speed
		ival = null,//!< pointer to interval timer
		count = 0,	//!< start/stop depth
		row = null,	//!< pointer to the row (TR) owning blocs
		clip = null,
		color = {
			border: 'black',
			background: 'white',
			strong: '#0a246a',
			fade: '#4364bd'
		};
	/**	Private functions */
	function	dc(a){return document.createElement(a);}
	function	draw(w, h) {
		var t=dc('table');row=t.appendChild(dc('tbody')).appendChild(dc('tr'));with(t.style){border='1px solid';borderCollapse='separate';
		emptyCells='show';margin='1px';}t.style.backgroundColor=color.background;t.style.borderColor=color.border;while(w>0){
		var c=row.appendChild(dc('td'));c.style.width=(w>10?10:w)+'px';c.style.height=(h-4)+'px';w-=10;}
		row.firstChild.style.backgroundColor=color.strong;row.firstChild.nextSibling.style.backgroundColor=color.fade;return t;
	};
	function	ist(t){return t.style.backgroundColor==''||t.style.backgroundColor=='transparent';};
	function	gb(t){for(var i=0,l=t.length;i<l;i++)if(!ist(t[i]))return(i);return -1;};
	function	ge(t,f){for(var i=f,l=t.length;i<f+l;i++)if(ist(t[(i+1)%t.length]))return(i+t.length)%t.length;return f;};
	function	start_view() {
		if(ival||clip)return;
		if (!document.body)return setTimeout(start_view, 10);
		!pv.parentNode && document.body.appendChild(pv);
		!row && pv.appendChild(draw(pv.clientWidth-2,pv.clientHeight-4));
		for(var td=row.firstChild;td;td=td.nextSibling)td.style.background='';
		ival=setInterval(function() {
			var tds=row.getElementsByTagName('td');var f=gb(tds);if(f==-1){tds[0].style.backgroundColor=color.fade;return;}
			var end=ge(tds,f),l=tds.length;tds[(end+1)%l].style.backgroundColor=color.fade;for(var i=end;i>=end-blocs;i--){if(ist(tds[(i+l)%l]))break;
			tds[(i+l)%l].style.backgroundColor=(i==end-blocs+1?color.fade:color.strong);}tds[(end-blocs+l)%l].style.backgroundColor='';
		},speed);
	};
	function	stop_view() {clip=setTimeout(function(){if(clip){if(ival){clearInterval(ival);ival=null;if(pv.parentNode)try{document.body.removeChild(pv);}catch(e){}};clip=null;}}, 200);};
	
	/**	Construct */
	var pv = dc('div');
	with (pv.style){position='absolute';zIndex=10000000;top='0px';right='0px';backgroundColor='#777777';width='100px';height='18px';border='0px';}
	
	/** Map the start and stop of loading to jQuery global events */
	jQuery(document).ajaxStart(function(txt) {
		if (!count++)start_view();
	});
	jQuery(document).ajaxStop(function(txt) {
		if (!count)throw ("No more task to stop for "+txt);
		if (!--count)stop_view();
	});
})();

/**
 * conversion to json
 */
if(!this.JSON){JSON={};}
(function(){function f(n){return n<10?'0'+n:n;}
if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(key){return this.getUTCFullYear()+'-'+f(this.getUTCMonth()+1)+'-'+f(this.getUTCDate())+'T'+f(this.getUTCHours())+':'+f(this.getUTCMinutes())+':'+f(this.getUTCSeconds())+'Z';};
String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf();};}
var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==='string'?c:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4);})+'"':'"'+string+'"';}
function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==='object'&&typeof value.toJSON==='function'){value=value.toJSON(key);}
if(typeof rep==='function'){value=rep.call(holder,key,value);}
switch(typeof value){case'string':return quote(value);case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}
gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==='[object Array]'){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||'null';}
v=partial.length===0?'[]':gap?'[\n'+gap+
partial.join(',\n'+gap)+'\n'+
mind+']':'['+partial.join(',')+']';gap=mind;return v;}
if(rep&&typeof rep==='object'){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==='string'){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}
v=partial.length===0?'{}':gap?'{\n'+gap+partial.join(',\n'+gap)+'\n'+
mind+'}':'{'+partial.join(',')+'}';gap=mind;return v;}}
if(typeof JSON.stringify!=='function'){JSON.stringify=function(value,replacer,space){var i;gap='';indent='';if(typeof space==='number'){for(i=0;i<space;i+=1){indent+=' ';}}else if(typeof space==='string'){indent=space;}
rep=replacer;if(replacer&&typeof replacer!=='function'&&(typeof replacer!=='object'||typeof replacer.length!=='number')){throw new Error('JSON.stringify');}
return str('',{'':value});};}
if(typeof JSON.parse!=='function'){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==='object'){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v;}else{delete value[k];}}}}
return reviver.call(holder,key,value);}
cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return'\\u'+
('0000'+a.charCodeAt(0).toString(16)).slice(-4);});}
if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof reviver==='function'?walk({'':j},''):j;}
throw new SyntaxError('JSON.parse');};}})();

jQuery.message = function(msg, done) {
	var d = jQuery('<div class="message" />').fadeIn(function() {
		setTimeout(function(){d.fadeOut(function(){d.remove();done && done();});},(msg.length/20)*1000);
	}).html(''+msg);
	return d.appendTo(document.body);
};
jQuery.message.close = function() {
	jQuery(document.body).find('> div.message').fadeOut(function() {jQuery(this).remove();});
};

/**
 * advanced alert printer
 */
jQuery.extend(jQuery, {
	customAlert: function(options) {
		var div = jQuery('<div></div>');
		div.addClass('generic '+(options.type? ' '+options.type:'')+(options.className? ' '+options.className: ''));
		options.title = options.title || "Erreur inconnue";
		var details = options.details || '';
		var text = '';
		if (options.text && options.text.error) {
			if (options.text.details)
				details = options.text.details;
			text = options.text.error;
		}
		else if (options.text && options.text.responseText) {
			details = options.text.responseText;
			text = 'Des erreurs se sont produites durant l\'enregistrement.';
		}
		else
			text = options.text;
//			console.dir(options);
		div.html('<h1>'+options.title+'</h1>' +
			(options.help? '<h2 class="help">'+options.help+'</h2>': '')+
			'<div class="data">' +
			'<div class="messages"><span class="icon"></span><div class="text">'+text+'</div><br /></div>' +
			(details? '<div class="expand"><span class="icon"></span><span class="label">Détails</span><br /></div><div class="details"><span class="text">'+details+'</span></div></fieldset>': '') +
			'</div>');
		function	overloadButtons(oldAction) {
			return function() {
				div.find('.expand .label, .expand .icon').unbind('click', toggle);
				div.close();
				oldAction && oldAction();
				return false;
			};
		}
		var empty = true;
		for (var i in options.buttons) {
			options.buttons[i] = overloadButtons(options.buttons[i]);
			empty = false;
		}
		if (empty)
			options.buttons = {'OK': overloadButtons()};

		/** TODO: faire en sorte que seule la popup soit focusable() */
//			erralrt.find('input,select,textarea').blur(function(e) {
//				var el = jQuery(this);
//				var win = el.parents('.popup:first');
//				if (!el.is('input'))
//				jQuery('.popup');
//				erralt.find('input:first').focus();
//			});
		function	toggle() {
			var dt = div.find('.details');
			if (dt.is(':visible')) {
				div.find('.expand').removeClass('expanded');
				dt.slideUp();
			}
			else {
				div.find('.expand').addClass('expanded');
				dt.slideDown();
			}
		}
		if (details)
			div.find('.expand .label, .expand .icon').click(toggle);
		jQuery.loadComponent([jQuery.libroot+'jquery.nmodal.js', jQuery.libroot+'window.css'], function() {
			div.alert(options).find('input:first').focus();
		});
		return div;
	},
	errorAlert: function(options) {
		return this.customAlert(jQuery.extend(options, {type:'error'}));
	},
	warnAlert: function(options) {
		return this.customAlert(jQuery.extend(options, {type:'warn'}));
	},
	infoAlert: function(options) {
		return this.customAlert(jQuery.extend(options, {type:'info'}));
	},
	warnConfirm: function(options) {
		return this.customAlert(jQuery.extend(options, {type:'warn', buttons: {'OK': function() {options.ok && options.ok();}, 'Annuler': function() {}}}));
	},
	infoConfirm: function(options) {
		return this.customAlert(jQuery.extend(options, {type:'info', buttons: {'OK': function() {options.ok && options.ok();}, 'Annuler': function() {}}}));
	},
	queryConfirm: function(options) {
		return this.customAlert(jQuery.extend(options, {type:'query', buttons: {'OK': function() {options.ok && options.ok();}, 'Annuler': function() {}}}));
	}
});

(function() {
jQuery.each( ("refresh,contextmenu,reset").split(","), function(i,o) {
	// Handle event binding
	jQuery.fn[o] = function(f){
		return f ? this.bind(o, f) : this.trigger(o);
	};
});



/**	Number formatting function (same as in PHP) */
window.number_format = function(n, d, dp, tsep) {
var e='';var nstr=''+n;var ei=nstr.indexOf("e");if(ei>-1){e=nstr.substr(ei);n=parseFloat(nstr.substr(0, ei));}if(d!=null){var temp=Math.pow(10,d);
n=Math.round(n*temp)/temp;}var sign=n<0?'-':'';var ig=(n>0?Math.floor(n):Math.abs(Math.ceil(n))).toString();var fc=(''+n).substr(ig.length+sign.length);
dp=dp!=null?dp:'.';fc=d!=null&&d>0||fc.length>1?(dp+fc.substr(1)):"";if(d!=null&&d>0){for(var i=fc.length-1,z=d;i<z;++i)fc+='0';}
tsep=(tsep!=dp||fc.length==0)?tsep:null;if(tsep!=null&&tsep!=""){for(var i=ig.length-3;i>0;i-=3)ig=ig.substr(0,i)+tsep+ig.substr(i);}
return sign+ig+fc+e;};

jQuery.currentLanguage = 'french';
jQuery.languages = jQuery.extend(jQuery.languages || {}, {
	french: {
		days: {
			'full': ['Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi', 'Dimanche'],
			'short': ['Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam', 'Dim'],
			'init': ['L', 'M', 'M', 'J', 'V', 'S', 'D']
		},
		months: {
			'full': ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'],
			'short': ['Jan', 'Fev', 'Mar', 'Avr', 'Mai', 'Juin', 'Jui', 'Aout', 'Sept', 'Oct', 'Nov', 'Déc'],
			'init': ['J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O', 'N', 'D']
		}
	},
	english: {
		days: {
			'full': ['Monday', 'Tuesday', 'Wednsday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
			'short': ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
			'init': ['M', 'T', 'W', 'T', 'F', 'S', 'S']
		},
		months: {
			'full': ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
			'short': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
			'init': ['J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O', 'N', 'D']
		}
	}
});
/**
 * converters
 */
window.Converter = {
	date: function(val) {
		function	importDate(d) {
			var now = d.replace(/\ |\-/g, ':').split(':');
			return new Date(now[2]+' '+jQuery.languages.english.months['short'][parseInt(now[1], 10)-1]+' '+now[0]+' '+now[3]+':'+now[4]+':'+now[5]+' GMT+0000');
		};
		if (!val)
			return null;
		if (val instanceof Date)
			return val;
		var t = new Date();
		if (parseInt(val) == val)
			//! date as timestamp
			t.setTime(parseInt(val)*1000);
		else {
			//! date as ISO format
			t = val.indexOf('GMT') == -1? importDate(val): new Date(val);
			t.setTime(t.getTime()+serverTimeOffset*1000);
		}
		if (isNaN(t))
			return null;
		return t;
	},
	number: function(val) {
		val = parseInt(val);
		if (isNaN(val))
			return 'n/a';
		return val;
	}
};
jQuery.extend(window.Converter, {
	reldate: Converter.date,
	weight: Converter.number,
	volume: Converter.number,
	filesize: Converter.number,
	price: Converter.number
});

window.Renderer = {
	civilite: function(val){
		var map_civilite = {
			mr: 'Mr.',
			mme: 'Mme.',
			mlle: 'Mlle.'
		};
		return map_civilite[val] || val || '';
	},
	reldate: function(t) {
		val = Converter.date(t);
		if (val === null || typeof val == 'undefined' || isNaN(val))
			return 'Jamais';
		val = Math.round(((new Date()).getTime()-val.getTime())/1000);
		
		var nn = val<0;
		var s = [];
		val = Math.abs(val);
		if ((val = parseInt(val / 60))) {
			if (val%60)
				s.splice(0, 0, (val % 60)+' minute'+(val % 60>1? 's':''));
			if ((val = parseInt(val / 60))) {
				if (val % 24)
					s.splice(0, 0, (val % 24)+' heure'+(val % 24>1? 's':''));
				if ((val = parseInt(val / 24))) {
					if (val > 365) {
						s.splice(0, 0, parseInt(val % 365)+' jour'+(val % 365>1? 's':''));
						s.splice(0, 0, parseInt(val / 365)+' an'+(parseInt(val / 365)>1? 's':''));
					}
					else
						s.splice(0, 0, val+' jour'+(val>1? 's':''));
				}
			}
		}
		s = s.slice(0, 2);
		return (nn? 'Dans ': 'Il y a ')+(s.length? s.join(' et '): 'moins d\'une minute');
	},
	number: Converter.number,
	filesize: function(val) {
		var p = ['&nbsp;o', 'Ko', 'Mo', 'Go'];
		for (; val > 10240 && p.length; p.splice(0, 1))
			val /= 1024;
		return number_format(val, 2, ',', ' ')+' '+p[0];
	},
	date: function(t) {
		t = Converter.date(t);
		if (t === null || typeof t == 'undefined' || isNaN(t))
			return 'Jamais';
		return ucfirst(jQuery.languages[jQuery.currentLanguage].days.full[(t.getDay()+6)%7].toLowerCase()+' '+(t.getDate())+' '+jQuery.languages[jQuery.currentLanguage].months.full[t.getMonth()].toLowerCase()+' '+t.getFullYear());
	},
	datehm: function(t) {
		t = Converter.date(t);
		if (t === null || typeof t == 'undefined' || isNaN(t))
			return 'Jamais';
		return ucfirst(
			jQuery.languages[jQuery.currentLanguage].days.full[t.getDay()].toLowerCase()+' '+
			(t.getDate()+1)+' '+jQuery.languages[jQuery.currentLanguage].months.full[t.getMonth()].toLowerCase()+' '+
			t.getFullYear()+', '+
			(t.getHours()<10?'0':'')+t.getHours()+'h'+
			(t.getMinutes()<10?'0':'')+t.getMinutes()+''
		);
	},
	datetime: function(t) {
		t = Converter.date(t);
		if (t === null || typeof t == 'undefined' || isNaN(t))
			return 'Jamais';
		return ucfirst(
			jQuery.languages[jQuery.currentLanguage].days.full[t.getDay()].toLowerCase()+' '+
			(t.getDate()+1)+' '+jQuery.languages[jQuery.currentLanguage].months.full[t.getMonth()].toLowerCase()+' '+
			t.getFullYear()+', '+
			(t.getHours()<10?'0':'')+t.getHours()+'h'+
			(t.getMinutes()<10?'0':'')+t.getMinutes()+'m '+
			(t.getSeconds()<10?'0':'')+t.getSeconds()+'s'
		);
	},
	weight: function(val) {
		val = Converter.number(val);
		if (isNaN(val))
			return 'n/a Kg';
		if (Math.abs(val) >= 1000)
			return number_format(val / 1000, (val / 1000) == Math.round(val / 1000)? 0: 2, ',', ' ')+' Kg';
		return number_format(val, 0, ',', ' ')+' g';
	},
	volume: function(val) {
		val = Converter.number(val);
		if (isNaN(val))
			return 'n/a l';
		if (val >= 1000)
			return number_format(val / 1000, (val / 1000) == Math.round(val / 1000)? 0: 2, ',', ' ')+' l';
		return number_format(val, 0, ',', ' ')+' ml';
	},
	price: function(val) {
		val = Converter.number(val);
		if (isNaN(val))
			return 'n/a €';
		return number_format(val / 100, 2, ',', ' ')+' €';
	}
};

/**
 * Les fonctions de la base de registre
 */

var GlobalRegistry = {};

window.registry = {
	create: function(key, value, ondone) {
		var path = key.split('/');
		var file = path.slice(-1)[0];
		path = path.slice(1, path.length-1);
		var exists_key = GlobalRegistry;
		var exists_path = [];
		while (path.length && exists_key[path[i]]) {
			exists_path.push(path[i]);
			exists_key = exists_key[path[i]];
			path = path.slice(1);
		}
		jQuery.ajax({
			url: '?ctrl=registry&action=create',
			type: 'post',
			data: {key: key, value: value},
			dataType: 'json',
			success: function(json) {
//				exists_key[path[i]] = json.values;
				while (!path.length && !exists_key[path[i]]) {
					exists_path.push(path[i]);
					exists_key[path[i]] = {};
				}
				exists_key[file] = json.values;
				if (!path.length)
					ondone(exists_key[file]);
				else
					console.warn('can\'t load '+path+' found '+exists_path);
			}
		});
	},
	read: function(key, ondone) {
		var path = key.split('/');
		var file = path.slice(-1)[0];
		path = path.slice(1, path.length-1);
//		console.info(path);
		var exists_key = GlobalRegistry;
		var exists_path = [];
		while (path.length && exists_key[path[i]]) {
			exists_path.push(path[i]);
			exists_key = exists_key[path[i]];
			path = path.slice(1);
		}
		if (!path.length)
			return ondone(exists_key[file]);
		jQuery.ajax({
			url: '?ctrl=registry&action=read',
			data: {key: '/'+path.join('/')+'/'},
			dataType: 'json',
			success: function(json) {
				exists_key[path[i]] = json.values;
				while (path.length && exists_key[path[i]]) {
					exists_path.push(path[i]);
					exists_key = exists_key[path[i]];
					path = path.slice(1);
				}
				if (!path.length)
					ondone(exists_key[file]);
				else
					console.warn('can\'t load '+path+' found '+exists_path);
			}
		});
	},
	update: function(key, ondone) {
		
	},
	'delete': function(key, ondone) {
		
	}
};
})();

function	empty(obj) {
	for (var i in obj)
		if (obj[i] !== obj.constructor.prototype[i])
			return false;
	return true;
};
function	concat() {
	var t = [];
	var a = concat.arguments;
	for (var i=0; i<a.length; i++)
		if (typeof a[i] == 'undefined' && a[i] === null)
			return null;
		else
			t.push(a[i]);
	return t.length? t.join(''): null;
};
function	concat_ws() {
	var t = [];
	var a = concat_ws.arguments;
	for (var i=1; i<a.length; i++)
		if (typeof a[i] != 'undefined' && a[i] !== null)
			t.push(a[i]);
	return t.length? t.join(a[0]): null;
};
function	fileext(name) {
	var p = name.lastIndexOf('.');
	return p > 0? name.substr(p+1): '';
};
function	filenoext(name) {
	var p = name.lastIndexOf('.');
	return p > 0? name.substr(0, p): name;
};
function	dirname(path) {
	var last = path.lastIndexOf('/');
	return last == -1? './':
		(last == path.length-1? dirname(path.substr(0, path.length-1)):
			path.substr(0, last));
};
function	basename(path) {
	var last = path.lastIndexOf('/');
	return last == -1? path:
		(last == path.length-1? basename(path.substr(path.length-1)):
			path.substr(last+1));
};
function	ltrim(v, c) {
	if (typeof c == 'undefined')
		c = " \n\r\t";
	while (v.length && c.indexOf(v.charAt(0)) != -1)
		v = v.substr(1);
	return v;
};
function	lpad(i, v, c) {
	if (typeof c == 'undefined')
		c = ' ';
	while (i.length < v)
		i = c+i;
	return i;
};
function	rpad(i, v, c) {
	if (typeof c == 'undefined')
		c = ' ';
	while (i.length < v)
		i += c;
	return i;
};
function	rtrim(v, c) {
	if (typeof c == 'undefined')
		c = " \n\r\t";
	while (v.length && c.indexOf(v.charAt(v.length-1)) != -1)
		v = v.substr(0, v.length-1);
	return v;
};
function	trim(v, c) {
	return ltrim(rtrim(v, c));
};

function	warnException(e, disable) {
	jQuery.errorAlert({
		title: "Erreur d'éxécution JavaScript",
		text: "<p>Une erreur d'éxécution s'est produite et les informations affichées sur la page ne sont peut-être plus correctes.</p>" +
				"<p>Vous devriez actualiser la page en appuyant sur F5 afin de ré-initialiser l'environement avec les données de base.</p>",
		details: e.message,
		buttons: {
			'Désactiver les messages d\'erreur': function() {
				disable && disable();
				jQuery.cookie('dexc', 1);
			},
			'Envoyer un rapport': function() {
				jQuery.ajax({
					url: window.server+'?ctrl=dev&action=exception',
					dataType: 'json',
					type: 'post',
					data: e,
					success: function(json) {
						jQuery.infoAlert({
							title: "Erreur d'éxécution JavaScript",
							text: "Un rapport d'erreur a été envoyé.<br />Nous vous remercions pour votre soutient. Ce rapport sera analysé " +
									"et les corrections nécessaires seront apportées au plus vite."
						});
					},
					error: function() {
						return false;
					}
				});
			},
			'OK': function() {}
		}
	});
};

(function() {
if (jQuery.cookie('dexc')=='1')
	return ;
var oldHandle = jQuery.event.handle;

jQuery.event.handle = function() {
	try {
		var ret = oldHandle.apply(this, arguments);
	}catch(e){
		warnException(e, function() {
			jQuery.event.handle = oldHandle;
		});
//		console.dir(e);
//		console.info(e.stack);
		throw e;
	}
	return ret;
};
})();
