//# -*- coding: utf-8 -*-
var jsFF =
{
	Version: '1.0',
	REQUIRED_PROTOTYPE: '1.6.0.3',
	locale: 'fr_UTF8',
	accessPath:'',
	debugging : false,
	_debugWindowWidth : 800,
	_debugWindowHeight : 200,
	windowsCss : 'default',
	alertCss : 'alphacube',
	infoCss: 'alphacube',
	validatorCss : 'default',
	datePickerCss : 'default',
	debugWindow: null,
	cryptoHexcase: 0,	// crypto hex output format : 0 - lowercase; 1 - uppercase
	cryptoB64pad:"",	// crypto base-64 pad character. "=" for strict RFC compliance 
	cryptoChrsz:8,	// bits per input character. 8 - ASCII; 16 - Unicode 
	_Validation: null,
	_swfu:null,
	_locales : new Array(),
	_loadedModules : new Array(),
	_iconDock : null,
	_3DButtons : null,
	_TafelTreeLoaded : false,
	_Paginators : new Array(),
	_datePickers: new Array(),
	_splitPanels: new Array(),
	_fadeSlides: new Array(),
	_contextMenuObj: null,
	_confirmVars : new Array(),
	_Spaner : null,
	_LastElemValidatedBeforeError: null,
	changeLocale : function(locale)
	{
		if (locale != '')
		{
			this.locale = locale;
			this._locales = new Array();
			var localeFile = jsFF.getAccessPath() + 'po/' + locale + '.js';
			new Ajax.Request(localeFile,  {
				asynchronous: true,
				parameters: {lib : localeFile},
				onFailure: function(response)
				{
					var lib = response.request.parameters.lib;
					jsFF.error(sprintf(jsFF._e('Can\'t load the locale file : <strong>%s</strong>.'), lib));
				},
				onComplete:function(response)
				{
					window.eval(response.transport.responseText);
					var lib = sprintf(jsFF._e('Locale file %s dynamically loaded.'), response.request.parameters.lib);
					window.setTimeout( function(msg) {jsFF.notice(msg);}, 100, lib);
				}
			});
		}
	},
	addLocale :  function (s,t)
	{
		this._locales[s.replace(/[ |\t]/g,'_')] = t;
	},
	_e : function (s)
	{
		var ss = s.replace(/[ |\t]/g,'_');
		if (this._locales[ss] != null)
			return this._locales[ss];
		else
			return s;
	},
	_moveDebugWindow: function()
	{
		if (! this.debugging)
			return;
		this.debugWindow.element.style.bottom = 42 - window.pageYOffset + 'px';
	},
	message : function (message)
	{
		if (this.debugging)
		{
			if (! this.debugWindow)
				showDebug(true, this._debugWindowWidth, this._debugWindowHeight);
			else
				this._moveDebugWindow();
			debug(message);
		}
	},
	notice : function (message)
	{
		if (this.debugging)
		{
			if (! this.debugWindow)
				showDebug(true, this._debugWindowWidth, this._debugWindowHeight);
			else
				this._moveDebugWindow();
			debug(sprintf('<span style="color:yellow"><strong>%s</strong> : %s</span>', this._e('Hint'), message));
		}
	},
	error : function (message)
	{
		if (! this.debugWindow)
				showDebug(true, this._debugWindowWidth, this._debugWindowHeight);
		else
			this._moveDebugWindow();
		debug(sprintf('<span style="color:red"><strong>%s</strong> : %s</span>', this._e('Error'), message));
	},
	alert : function (msg, params)
	{
		var windowParameters = params ||  {className: this.alertCss, options: ""};
		if (! windowParameters.options)
			windowParameters.options = '';
		windowParameters.windowParameters = {zIndex : 10001};	// Passer au dessus de ModalBox ...
		Dialog.alert(msg, windowParameters);
	},
	info : function (msg, delay, params)
	{
		var windowParameters = params ||  {className: this.infoCss, options: ""};
		if (! windowParameters.options)
			windowParameters.options = '';
		windowParameters.windowParameters = {zIndex : 10001};	// Passer au dessus de ModalBox ...
		Dialog.info(msg, windowParameters);
		window.setTimeout('Dialog.closeInfo()', delay);
	},
	confirm : function (msg, params)
	{
		var p = params || { className: this.alertCss, options: ""};
		if (! p.options)
			p.options = '';
		if (! p.className)
			p.className = this.alertCss;
		p.okSaved = params.ok || null;
		p.cancelSaved = params.cancel || null;
		var cVar = new Object();
		cVar.msg = msg;
		cVar.options = p;
		this._confirmVars.push(cVar);
		this._launchConfirm();
	},
	_launchConfirm : function ()
	{
		if  (this._confirmVars.length != 1)
			return;
		var msg = this._confirmVars[0].msg;
		var windowParameters = this._confirmVars[0].options;
		windowParameters.ok = jsFF._confirmOk;
		windowParameters.cancel = jsFF._confirmCancel;
		windowParameters.windowParameters = {zIndex : 10001};	// Passer au dessus de ModalBox ...
		Dialog.confirm(msg, windowParameters);
	},
	_confirmOk : function ()
	{
		if (jsFF._confirmVars.length < 1)
			return true;
		var res = true;
		if (jsFF._confirmVars[0].options.okSaved)
			var res = jsFF._confirmVars[0].options.okSaved();	
		jsFF._confirmVars.shift();
		window.setTimeout('jsFF._launchConfirm()', 50);
		return res;
	},
	_confirmCancel : function ()
	{
		if (jsFF._confirmVars.length < 1)
			return false;
		var res = false;
		if (jsFF._confirmVars[0].options.cancelSaved)
			var res = jsFF._confirmVars[0].options.cancelSaved();
		jsFF._confirmVars.shift();
		window.setTimeout('jsFF._launchConfirm()', 50);
		return res;
	},
	login : function (options)
	{
		if (! options.url)
		{
			this.error('The login dialog lacks the URL for authentication.');
			return;
		}
		options.title = options.title || '';
		options.msg = options.msg || this._e('You must identify:');
		options.msgErr = options.msgErr || this._e('Login or password incorrect.');
		options.libLogin = options.libLogin || this._e('login');
		options.libPassword = options.libPassword || this._e('password');
		options.crypt = options.crypt || 'none';
		options.className = options.className || 'greylighting';
		options.width = options.width || 400;
		options.okLabel = options.okLabel || this._e('Login');
		options.cancelLabel = options.cancelLabel || this._e('Cancel');
		var loginContent = '<div id="jsFF_login"><p>' + options.msg + '</p><p><span id="jsFF_login_error_msg" class="jsFF_login_error" style="display:none">&nbsp;</span></p><div style="clear:both"></div><p><span class="jsFF_login_label">' + options.libLogin + '</span><span class="jsFF_login_input"><input type="text" id="jsFF_login_login"/></span></p><div style="clear:both"></div><p><span class="jsFF_login_label">' + options.libPassword + '</span><span class="jsFF_login_input"><input id="jsFF_login_passwd" type="password"/></span></p><div style="clear:both"></div></div>';
		Dialog.confirm(loginContent, {title: options.title, className: options.className, width:options.width, okLabel: options.okLabel, cancelLabel: options.cancelLabel, onShow : function (win) {
				$('jsFF_login_login').focus();
				if (win.element.id)
				{
					$(win.element.id + '_row2').observe('keypress', function (event){
							if (event.keyCode == 13)
								Dialog.okCallback();
							else if (event.keyCode == 27)
								Dialog.cancelCallback();
						}.bind(win));
				}
			},
			onOk:function(options, win){ 
				var login = $F('jsFF_login_login');
				if (login == '')
				{
					$('jsFF_login_error_msg').innerHTML=this._e('You must, at least, provide a valid login identifier.'); 
					$('jsFF_login_error_msg').show(); 
					Windows.focusedWindow.updateHeight(); 
					new Effect.Shake(Windows.focusedWindow.getId());
					$('jsFF_login_login').focus();
					return false;
				}
				switch(options.crypt)
				{
					case 'md4' : var passwd = this.hex_md4($F('jsFF_login_passwd')); break;
					case 'md5' : var passwd = this.hex_md5($F('jsFF_login_passwd')); break;
					case 'sha1' : var passwd = this.hex_sha1($F('jsFF_login_passwd')); break;
					default : var passwd = $F('jsFF_login_passwd');
				}
				new Ajax.Request(options.url,  {
					asynchronous: false,
					parameters: {'login' : login, 'passwd' : passwd, 'crypt' : options.crypt},
					onFailure: function(response)
					{
						var lib = response.request.parameters.lib;
						jsFF.error(sprintf(jsFF._e('Dialog <b>jsFF.login(...)</b> can\'t access the authentication URL : %s.'), options.url));
					},
					onComplete:function(response)
					{
						this.loginVerify(win, options, response.transport.responseText);
					}.bind(this)
				});
			}.bind(this, options)
		});
	},
	loginVerify : function (win, options, response)
	{
		window.eval(response);
		if (! status)
		{
			$('jsFF_login_error_msg').innerHTML=options.msgErr; 
			$('jsFF_login_error_msg').show(); 
			Windows.focusedWindow.updateHeight(); 
			new Effect.Shake(Windows.focusedWindow.getId()); 
			return false;
		}
		else
		{
			if (redirectUrl)
				window.location.href=redirectUrl;
			else
				window.location.reload();
			return true;
		}
	},
	_notFoundCreateUI : function()
	{
		jsFF.notice(this._e('You can create a function called createUI(); which will be automatically launched for initialize all the widgets.'));
	},
	_debugMessage : function()
	{
		if (this.debugging)
			{
				showDebug(true, this._debugWindowWidth, this._debugWindowHeight);
				debug(sprintf('<span style="color:white"><bold><u>%s</u> ...</bold>', this._e('jsFF is now ready')));
			}
	},
	Browser : function()
	{
		var info = { Version : "1.0" };
		var is_major = parseInt( navigator.appVersion );
		info.nver = is_major;
		info.ver = navigator.appVersion;
		info.agent = navigator.userAgent;
		info.dom = document.getElementById ? 1 : 0;
		info.opera = window.opera ? 1 : 0;
		info.ie8 = ( info.ver.indexOf( "MSIE 8" ) > -1 && info.dom && !info.opera ) ? 1 : 0;
		info.ie7 = ( info.ver.indexOf( "MSIE 7" ) > -1 && info.dom && !info.opera ) ? 1 : 0;
		info.ie6 = ( info.ver.indexOf( "MSIE 6" ) > -1 && info.dom && !info.opera ) ? 1 : 0;
		info.ie5 = ( info.ver.indexOf( "MSIE 5" ) > -1 && info.dom && !info.opera ) ? 1 : 0;
		info.ie4 = ( document.all && !info.dom && !info.opera ) ? 1 : 0;
		info.ie3 = ( info.ver.indexOf( "MSIE" ) && ( is_major < 4 ) );
		info.ie = info.ie4 || info.ie5 || info.ie6 || info.ie7 || info.ie8;
		info.mac = info.agent.indexOf( "Mac" ) > -1;
		info.ns6 = ( info.dom && parseInt( info.ver ) >= 5 ) ? 1 : 0;
		info.hotjava = ( info.agent.toLowerCase().indexOf( 'hotjava' ) != -1 ) ? 1 : 0;
		info.ns4 = ( document.layers && !info.dom && !info.hotjava ) ? 1 : 0;
		info.bw = ( info.ie6 || info.ie5 || info.ie4 || info.ns4 || info.ns6 || info.opera );
		info.ver3 = ( info.hotjava || info.ie3 );
		info.opera7 = ( ( info.agent.toLowerCase().indexOf( 'opera 7' ) > -1 ) || ( info.agent.toLowerCase().indexOf( 'opera/7' ) > -1 ) );
		info.operaOld = info.opera && !info.opera7;
		info.safari = ( info.agent.toLowerCase().indexOf( 'safari' ) > -1 );
		info.webKit = ( info.agent.toLowerCase().indexOf( 'apple webkit' ) > -1 );
		return info;
	},
	ImportCss : function(doc, css_file)
	{
		if (jsFF.Browser().ie)
			var styleSheet = doc.createStyleSheet(css_file);
		else
		{
			var elm = doc.createElement("link");
			elm.rel = "stylesheet";
			elm.href = css_file;
			if (headArr = doc.getElementsByTagName("head"))
				headArr[0].appendChild(elm);
		}
	},
	_require: function(libraryName)
	{
		try{				// inserting via DOM fails in Safari 2.0, so brute force approach
			document.write('<script type="text/javascript" src="'+libraryName+'"><\/script>');
		} catch(e) {			// for xhtml+xml served content, fall back to DOM methods
			var script = document.createElement('script');
			script.type = 'text/javascript';
			script.src = libraryName;
			document.getElementsByTagName('head')[0].appendChild(script);
		}
	},
	_load: function() 	
	{	
		// This function includes all the files for script.ac.ulo.us, so including the scriptacolus.js is not necessary
		function convertVersionString(versionString) 
		{
			var v = versionString.replace(/_.*|\./g, '');
			v = parseInt(v + '0'.times(4-v.length));
			return versionString.indexOf('_') > -1 ? v-1 : v;
		}
		if((typeof Prototype=='undefined') ||
		    (typeof Element == 'undefined') ||
		    (typeof Element.Methods=='undefined') ||
		    (convertVersionString(Prototype.Version) < convertVersionString(jsFF.REQUIRED_PROTOTYPE)))
			throw("script.aculo.us requires the Prototype JavaScript framework >= " + jsFF.REQUIRED_PROTOTYPE);
		var js = /jsFF\.js(\?.*)?$/;
		$$('head script[src]').findAll(
			function(s) 
			{
				return s.src.match(js);
			}).each(function(s) 
			{
				var path = s.src.replace(js, '');
				if (path != jsFF.getAccessPath())
					jsFF.setAccessPath(path);
				includes = s.src.match(/\?.*load=([a-z,]*)/);
				// list of scripts to load on initialization (don't put any space character between files !!!)
				(includes ? includes[1] : 'lib/sprintf,lib/FFextenders,lib/builder,lib/effects,lib/dragdrop,lib/controls,lib/slider,lib/sound,lib/validate,windows/window,windows/debug,lib/datepicker').split(',').each(
					function(include) { jsFF._require(path+include+'.js') });
			});
		// Load the traduction file in correspondance with this.locale
		if (window.JSFF_LOCALE)
				jsFF._require(jsFF.getAccessPath() + 'po/' + window.JSFF_LOCALE + '.js');
		else
		if (this.locale)
			jsFF._require(jsFF.getAccessPath() + 'po/' + this.locale + '.js');
		// Import the CSS files needed by the includes
		this.ImportCss(document,  jsFF.getAccessPath() + 'css/themes/' + (this.windowsCss || 'default') + '.css');
		this.ImportCss(document, jsFF.getAccessPath() + 'css/themes/debug.css');
		this.ImportCss(document, jsFF.getAccessPath() + 'css/themes/alphacube.css');
		this.ImportCss(document, jsFF.getAccessPath() + 'css/themes/darkX.css');
		this.ImportCss(document, jsFF.getAccessPath() + 'css/themes/lighting.css');
		this.ImportCss(document, jsFF.getAccessPath() + 'css/themes/mac_os_x.css');
			this.ImportCss(document, jsFF.getAccessPath() + 'css/themes/mac_os_x_dialog.css');
		this.ImportCss(document, jsFF.getAccessPath() + 'css/themes/nuncio.css');
		this.ImportCss(document, jsFF.getAccessPath() + 'css/themes/spread.css');
		this.ImportCss(document, jsFF.getAccessPath() + 'css/themes/login.css');
		this.ImportCss(document, jsFF.getAccessPath() + 'css/validation/' + this.validatorCss + '.css');
		this.ImportCss(document, jsFF.getAccessPath() + 'css/datepicker/' + this.datePickerCss + '.css');
		// Try to execute a global function named createUI()
		Event.observe(window, 'load', function() {
			window.setTimeout('jsFF._debugMessage();', 100);
			if (window.createUI)
				window.setTimeout('window.createUI();', 200);
			else
				window.setTimeout('jsFF._notFoundCreateUI();', 200);
		});
	},
	_requireModule: function(libraryName)
	{
		new Ajax.Request(libraryName,  {
			asynchronous: false,
			parameters: {lib : libraryName},
			onFailure: function(response)
			{
				var lib = response.request.parameters.lib;
				jsFF.error(sprintf(jsFF._e('Can\'t load the library : <strong>%s</strong>.'), lib));
			},
			onComplete:function(response)
			{
				window.eval(response.transport.responseText);
				var lib = sprintf(jsFF._e('Library %s dynamically loaded.'), response.request.parameters.lib);
				window.setTimeout( function(msg) {jsFF.notice(msg);}, 100, lib);
			}
		});
	},
	loadModule : function (module, theme)
	{
		if (this.isModuleLoaded(module))
			return;
		var path = this.getAccessPath();
		var loadTheme = theme || 'default';
		switch(module)
		{
			case 'CryptoCommon':
				if (typeof(jsFF_cryptoCommonLoaded) == 'undefined')
					this._requireModule(path + 'lib/crypto/common.js');
				this._loadedModules.push('CryptoCommon');
				break;
			case 'CryptoMD4':
				if (typeof(jsFF_cryptoCommonLoaded) == 'undefined')
					this._requireModule(path + 'lib/crypto/common.js');
				if (typeof(jsFF_cryptoMd4Loaded) == 'undefined')
					this._requireModule(path + 'lib/crypto/md4.js');
				this._loadedModules.push('CryptoMD4');
				break;
			case 'CryptoMD5':
				if (typeof(jsFF_cryptoCommonLoaded) == 'undefined')
					this._requireModule(path + 'lib/crypto/common.js');
				if (typeof(jsFF_cryptoMd5Loaded) == 'undefined')
					this._requireModule(path + 'lib/crypto/md5.js');
				this._loadedModules.push('CryptoMD5');
				break;
			case 'CryptoSHA1':
				if (typeof(jsFF_cryptoCommonLoaded) == 'undefined')
					this._requireModule(path + 'lib/crypto/common.js');
				if (typeof(jsFF_cryptoSha1Loaded) == 'undefined')
					this._requireModule(path + 'lib/crypto/sha1.js');
				this._loadedModules.push('CryptoSHA1');
				break;
			case 'SWFUpload':
				if (typeof(SWFUpload) == 'undefined')
				{
					this._requireModule(path + 'SWFUpload/swfupload.js');
					this._requireModule(path + 'SWFUpload/handlers.js');
					this._requireModule(path + 'SWFUpload/swfupload.queue.js');
					this._requireModule(path + 'SWFUpload/fileprogress.js');
				}
				this.ImportCss(document, path + 'css/SWFUpload/' + loadTheme + '.css');
				this._loadedModules.push('SWFUpload');
				break;
			case 'SplitPanel':
				if (typeof(SplitPane) == 'undefined')
					this._requireModule(path + 'lib/splitpanel.js');
				this.ImportCss(document, path + 'css/splitPanel-' + loadTheme + '.css');
				this._loadedModules.push('SplitPanel');
				break;
			case 'IconDock':
				if (typeof(IconDock) == 'undefined')
					this._requireModule(path + 'lib/icondock.js');
				this._loadedModules.push('IconDock');
				break;
			case '3dButtons':
				if (typeof(Button3D) == 'undefined')
					this._requireModule(path + 'lib/3dButtons.js');
				this._loadedModules.push('3dButtons');
				break;
			case 'Paginator':
				if (typeof(jsFF.Paginator) == 'undefined')
					this._requireModule(path + 'lib/Paginator.js');
				this._loadedModules.push('Paginator');
				this.ImportCss(document, path + 'css/Paginator/' + loadTheme + '.css');
				break;
			case 'FadeSlideShow':
				if (typeof(jsFF.FadeSlideShow) == 'undefined')
					this._requireModule(path + 'lib/fadeslideshow.js');
				this._loadedModules.push('FadeSlideShow');
				break;
			case 'ModalBox':
				if (typeof(ModalBox) == 'undefined')
					this._requireModule(path + 'lib/modalbox.js');
				this._loadedModules.push('ModalBox');
				this.ImportCss(document, path + 'css/modalbox.css');
				break;
			case 'Accordion':
				if (typeof(jsFF._Accordion) == 'undefined')
					this._requireModule(path + 'lib/accordeon.js');
				this._loadedModules.push('Accordion');
				this.ImportCss(document, path + 'css/accordeon/' + loadTheme + '.css');
				break;
			case 'CssTabs':
				if (typeof(jsFF._cssTab) == 'undefined')
					this._requireModule(path + 'lib/css_tabs.js');
				this._loadedModules.push('CssTabs');
				this.ImportCss(document, path + 'css/css_tabs/'+loadTheme+'.css');
				break;
			case 'WheelScroll':
				if (typeof(jsFF._wheelScroll) == 'undefined')
					this._requireModule(path + 'lib/wheelScroll.js');
				this._loadedModules.push('WheelScroll');
				break;
			case 'Tree' :
				if (typeof(TafelTree) == 'undefined')
					this._requireModule(path + 'lib/Tree.js');
				this.ImportCss(document, path + 'css/Tree/tree.css');
				this._loadedModules.push('Tree');
				jsFF.initTree();
				break;
			case 'contextMenu' :
				if (typeof(jsFF.contextMenu) == 'undefined')
					this._requireModule(path + 'lib/contextMenu.js');
				this.ImportCss(document, path + 'css/contextMenu/contextMenu.css');
				this._loadedModules.push('contextMenu');
				break;
			case 'FluidSpaner' :
				if (typeof(jsFF_transitions) == 'undefined')
					this._requireModule(path + 'lib/transitions.js');
				if (typeof(jsFF_Spaner) == 'undefined')
					this._requireModule(path + 'lib/fluidspaner.js');
				this.ImportCss(document, path + 'css/fluidspaner/'+ loadTheme + '.css');
				this._loadedModules.push('FluidSpaner');
				break;
			case 'TableKit' :
				if (typeof(TableKit) == 'undefined')
					this._requireModule(path + 'lib/tablekit.js');
				this.ImportCss(document, path + 'css/tablekit/'+ loadTheme + '.css');
				this._loadedModules.push('TableKit');
				break;
			default:
				this.error(sprintf(this._e('Try loading an unknown module : <strong>%s</strong>.<br/>Available modules to date are : <ul>%s</ul>'), module, '<li>SWFUpload</li><li>SplitPanel</li><li>IconDock</li>'));
		}
	},
	isModuleLoaded : function(module)
	{
		for (var i=0; i < this._loadedModules.length; i++)
			if (this._loadedModules[i] == module)
				return true;
		return false;
	},
	setValidation : function(idForm, action)
	{
		if (! idForm || (idForm == ''))
		{
			jsFF.error(sprintf(this._e('jsFF.%s(%s) called with a %s parameter which is null or empty !'), 'setValidation', 'idForm', 'idForm'));
			return;
		}
		var f=$(idForm);
		if (f)
			Event.observe(idForm, 'submit', function(ev) {
				try {
					if (! $(idForm).validate(action))
						Event.stop(ev);
				} catch (e) {
					var form = ev.target.id || '???';
					var last = jsFF._LastElemValidatedBeforeError || '???';
					var msg = e.message || jsFF._e('unknown error');
					var stack = e.stack.replace(/\n/g, '<br />') || jsFF._e('No stack context...');
					stack = '<span style="color:white;">' + stack + '</span><br />';
					jsFF.error(sprintf(jsFF._e("jsFF.validate : Error encountered while validating the form <b>'%s'</b>.<br />Last input valiated is : <b>%s</b><br />Error : <b>'%s'</b><br/>%s"), form, last, msg, stack), 5000);
					Event.stop(ev);
				}
			});
		else
			this.error(sprintf(this._e("sFF.%s(...) called with a non existent element : '%s'."),'setValidation', idForm));
	},
	setAccessPath: function(val)
	{
		this.accessPath = val;
	},
	getAccessPath: function()
	{
		return this.accessPath;
	},
	getClientSize: function()
	{
		var dim = document.viewport.getDimensions();		// I prefer using the Prototype method ...
		if (dim)
			return Array(dim.width, dim.height);
		else
			return Array((document.documentElement && document.documentElement.clientWidth) || window.innerWidth || self.innerWidth || document.body.clientWidth,(document.documentElement && document.documentElement.clientHeight) || window.innerHeight || self.innerHeight || document.body.clientHeight);
	},
	addDatePicker: function(idControl, options)
	{
		if (! idControl || (idControl == ''))
			jsFF.error('jsFF.datePicker() : the parameter idControl is null or empty !');
		var c = $(idControl);
		var existe = true;
		if (!c)
		{
			existe = false;
			var year = idControl + '_year'; 
			var month = idControl + '_month';
			var day = idControl + '_day';
			if ( $(year) && $(month) && (month) )
				existe = true;
		}
		if (! existe)
		{
			jsFF.error('jsFF.datePicker() : the parameter idControl (' + idControl + ') doesn\'t exists in DOM !');
			return;
		}
		if (! options)
			options = {ID : idControl};
		else
			options.ID = idControl;
		options.locale = options.locale || this.locale;						// Locale for the calendar
		if(options.locale == 'en_UTF8')
			options.locale = 'en' ;
		if(options.locale == 'es_UTF8')
			options.locale = 'es' ;
		options.InputMode = options.InputMode || 'TextBox';				// Type of control
		options.FromYear = options.FromYear || 2000;						// Min year to display
		options.UpToYear = options.UpToYear || 2019;						// Max year to display
		options.PositionMode = options.PositionMode || 'Bottom'	;	// Position of control (Top or Bottom)
		if (! options.cssPath)
			options.cssPath = this.getAccessPath() + 'css/datepicker/';
		// Cherche et detruit un precedent datePicker base sur ce meme element ...
		for (var i=0; i<this._datePickers.length; i++)
			if (this._datePickers[i] && this._datePickers[i].options.ID == idControl)
			{
				this._datePickers[i].remove();
				this._datePickers[i] = null;
			}
		this._datePickers = this._datePickers.compact();
		this._datePickers.push(new TDatePicker(options));
	},
	addUploader : function (id_span_bouton, upload_url, upload_complete, post_params, file_types, file_description, file_upload_limit)
	{
		if (this._swfu != null)
		{
			this.error(this._e('jsFF.addUploader(...) : Only one Uploader can be create within a same page.'));
			return;
		}
		if (! this.isModuleLoaded('SWFUpload'))
			this.loadModule('SWFUpload');
		var settings = {
			flash_url : this.getAccessPath() + "SWFUpload/Flash/swfupload.swf",
			upload_url: upload_url || "upload.php" ,
			post_params: post_params || "" ,
			file_types : file_types || "*.*",
			file_types_description : file_description || "All Files",
			file_upload_limit : file_upload_limit || 100,
			file_size_limit : (file_upload_limit>0)? file_upload_limit + " MB" : "100 MB",
			file_queue_limit : 0,
			custom_settings : {
				progressTarget : "jsFFUploadProgress",
				cancelButtonId : "jsFFUploadCancel"
			},
			debug: false,

			// Button settings
			button_image_url: this.getAccessPath() + "SWFUpload/images/jsFFButtonUpload.png",
			button_width: "65",
			button_height: "29",
			button_placeholder_id: id_span_bouton || "spanButtonPlaceHolder",
			button_text: '<span class="theFont">Upload</span>',
			button_text_style: ".theFont { font-size: 16; }",
			button_text_left_padding: 12,
			button_text_top_padding: 3,
			
			// The event handler functions are defined in handlers.js
			file_queued_handler : fileQueued,
			file_queue_error_handler : fileQueueError,
			file_dialog_complete_handler : fileDialogComplete,
			upload_start_handler : uploadStart,
			upload_progress_handler : uploadProgress,
			upload_error_handler : uploadError,
			upload_success_handler : uploadSuccess,
			upload_complete_handler : upload_complete || uploadComplete,
			queue_complete_handler : queueComplete	// Queue plugin event
		};
		this.message("post_params="+settings.post_params.PHPSESSID),
		this._swfu = new SWFUpload(settings);
	},
	addSplitPanel : function (id1, id1_width, id2, id2_left, id2_width, options)
	{
		if (! this.isModuleLoaded('SplitPanel'))
			this.loadModule('SplitPanel');
		var opt = options || { active: true };
		new SplitPane(id1, id1_width, id2, id2_left, id2_width, opt);
	},
	activatePanels : function ()
	{
		for(i=0; i<this._splitPanels.length; i++)
			this._splitPanels[i].set();
	},
	addDock: function (id, options)
	{
		if (! id || (id == ''))
		{
			jsFF.error('jsFF.%s(%s) called with a %s parameter which is null or empty !', 'addDock', 'id', 'id');
			return;
		}
		if (! this.isModuleLoaded('IconDock'))
			this.loadModule('IconDock');
		if (! $(id))
			jsFF.error(sprintf(this._e("jsFF.addDock(...) called with a non existent element : '%s'."),id));
		else
			this._iconDock.addDock(id, options);
	},
	showDocks: function ()
	{
		if ( ! this._iconDock || ! this._iconDock.showDocks() )
			jsFF.error(this._e("You must add a dock object with the jsFF.addDock(...) function before calling jsFF.showDocks()."));
		else
			this._iconDock.showDocks();
	},
	add3dButtons: function (id, options)
	{
		if (! id || (id == ''))
		{
			jsFF.error('jsFF.%s(%s) called with a %s parameter which is null or empty !', 'add3dButtons', 'id', 'id');
			return;
		}
		if (! this.isModuleLoaded('3dButtons'))
			this.loadModule('3dButtons');
		if (! $(id))
			jsFF.error(sprintf(this._e("jsFF.%s(...) called with a non existent element : '%s'."),'add3dButtons', id));
		else
			this._3DButtons.make3dButtons(id, options);
	},
	addPaginator: function (id, options)
	{
		if (! id || (id == ''))
		{
			jsFF.error('jsFF.%s(%s) called with a %s parameter which is null or empty !', 'addPaginator', 'id', 'id');
			return;
		}
		if (! this.isModuleLoaded('Paginator'))
			this.loadModule('Paginator');
		if (! $(id))
			jsFF.error(sprintf(this._e("jsFF.%s(...) called with a non existent element : '%s'."),'addPaginator', id));
		else
			this._Paginators.push(new jsFF.Paginator(id, options));
	},
	getPaginator: function(n)
	{
		if (n >= 0 && n < this._Paginators.length)
			return this._Paginators[n];
		else
			jsFF.error(sprintf(this._e("jsFF.%s(...) called with a non existent indice : '%d'."),'getPaginator', n));
	},
	removePagination: function (n)
	{
		if (n >= 0 && n < this._Paginators.length)
			this._Paginators[n].removePagination();
		else if (n== -1)
			for (i=0; i<this._Paginators.length; i++)
				this._Paginators[i].removePagination();
		else
			jsFF.error(sprintf(this._e("jsFF.%s(...) called with a non existent indice : '%d'."),'removePagination', n));
			
	},
	addFadeSlideShow:function(id, images, options)
	{
		if (! id || (id == ''))
		{
			jsFF.error('jsFF.%s(%s) called with a %s parameter which is null or empty !', 'addFadeSlideShow', 'id', 'id');
			return;
		}
		if (! images || (images == ''))
		{
			jsFF.error('jsFF.%s(%s) called with a %s parameter which is null or empty !', 'addFadeSlideShow', 'images', 'images');
			return;
		}
		if (! images.length)
		{
			jsFF.error('jsFF.%.addFadeSlideShow(...) called with an empty images array !');
			return;
		}
		if (! this.isModuleLoaded('FadeSlideShow'))
			this.loadModule('FadeSlideShow');
		if (! $(id))
			jsFF.error(sprintf(this._e("jsFF.%s(...) called with a non existent element : '%s'."),'addFadeSlideShow', id));
		else
			this._fadeSlides.push( new jsFF.FadeSlideShow(id, images, options));
	},
	showMB: function (content, options)
	{
		if (! content || (content == ''))
		{
			jsFF.error('jsFF.%s(%s) called with a %s parameter which is null or empty !', 'showMB', 'id', 'id');
			return;
		}
		if (! this.isModuleLoaded('ModalBox'))
			this.loadModule('ModalBox');
		var opt = options || {};
		Modalbox.show(content, opt);
	},
	hideMB: function()
	{
		if (! this.isModuleLoaded('ModalBox'))
			return;
		else
			Modalbox.hide();
	},
	alertMB: function (message)
	{
		if (! this.isModuleLoaded('ModalBox'))
			this.loadModule('ModalBox');
		Modalbox.alert(message);
	},
	resizeMB: function (width, height, options)
	{
		if (! this.isModuleLoaded('ModalBox'))
			return;
		else
			Modalbox.resize(width, height, options);
	},
	activateMB: function()
	{
		if (! this.isModuleLoaded('ModalBox'))
			return;
		else
			Modalbox.activate();
	},
	deactivateMB: function ()
	{
		if (! this.isModuleLoaded('ModalBox'))
			return;
		else
			Modalbox.deactivate();
	},
	addAccordion: function(id, toSee, theme)
	{
		if (! id || (id == ''))
		{
			jsFF.error('jsFF.%s(%s) called with a %s parameter which is null or empty !', 'addAccordion', 'id', 'id');
			return;
		}
		if (! this.isModuleLoaded('Accordion'))
			this.loadModule('Accordion', theme || 'default');
		if (! $(id))
			jsFF.error(sprintf(this._e("jsFF.%s(...) called with a non existent element : '%s'."),'addAccordion', id));
		else
			new jsFF._Accordion(id, toSee || 1);
	},
	addCssTab: function(id, options)
	{
		if (! id || (id == ''))
		{
			jsFF.error('jsFF.%s(%s) called with a %s parameter which is null or empty !', 'addCssTab', 'id', 'id');
			return;
		}
		if (! $(id))
			jsFF.error(sprintf(this._e("jsFF.%s(...) called with a non existent element : '%s'."),'addCssTab', id));
		else
		{
			if (! this.isModuleLoaded('CssTabs'))
			{
				if(options && options.theme && options.theme != '' && (options.theme == 'default' || options.theme == 'green'))
					this.loadModule('CssTabs', options.theme);
				else
					this.loadModule('CssTabs');
			}
			return new jsFF._cssTab($(id), options);
		}
	},
	addFluidSpaner: function(id, options, theme)
	{
		var th = theme || 'default';
		if (this._Spaner != null)
		{
			jsFF.error('jsFF.%s(%s) called but a FluidSpaner component has yet created (it only can be ONE FluidSpaner component on a page !).', 'addFluidSpaner', id);
			return;
		}
		if (! id || (id == ''))
		{
			jsFF.error('jsFF.%s(%s) called with a %s parameter which is null or empty !', 'addFluidSpaner', 'id', 'id');
			return;
		}
		if (! $(id))
			jsFF.error(sprintf(this._e("jsFF.%s(...) called with a non existent element : '%s'."),'addFluidSpaner', id));
		else
		{
			if (! this.isModuleLoaded('FluidSpaner'))
				this.loadModule('FluidSpaner', th);
			this._Spaner = new jsFF_Spaner(id, options);
		} 
	},
	setSpanTransition : function (id, trans)
	{
		this._Spaner.setTransition(id, trans);
	},
	spanTo : function (id, dest)
	{
		if (! this._Spaner)
			return;
		this._Spaner.slide(id, dest);
	},
	getCurrentSpan : function (id)
	{
		if (! this._Spaner || ! this._Spaner.collection[id])
			return '';
		return this._Spaner.collection[id].current;
	},
	getNextSpan : function (id)
	{
		if (! this._Spaner || ! this._Spaner.collection[id])
			return '';
		var pos = -1;
		for (i=0; i < this._Spaner.collection[id].list.length; i++)
			if (this._Spaner.collection[id].list[i] == this._Spaner.collection[id].current)
			{
				pos = i;
				break;
			}
		if (pos >= 0)
		{
			pos++;
			if (pos < this._Spaner.collection[id].list.length)
				return this._Spaner.collection[id].list[pos];
			else
				return '';
		}
		else
			return '';
	},
	getPrevSpan : function (id)
	{
		if (! this._Spaner || ! this._Spaner.collection[id])
			return '';
		var pos = -1;
		for (i=0; i < this._Spaner.collection[id].list.length; i++)
			if (this._Spaner.collection[id].list[i] == this._Spaner.collection[id].current)
			{
				pos = i-1;
				break;
			}
		if (pos >= 0)
			return this._Spaner.collection[id].list[pos];
		else
			return '';
	},
	isFirstSpan : function (id, span)
	{
		if (! this._Spaner || ! this._Spaner.collection[id])
			return false;
		return (this._Spaner.collection[id].list[0] == span);
	},
	isLastSpan : function (id, span)
	{
		if (! this._Spaner || ! this._Spaner.collection[id])
			return false;
		return (this._Spaner.collection[id].list[(this._Spaner.collection[id].list.length-1)] == span);
	},
	addWheelScroll: function (id, options)
	{
		if (! id || (id == ''))
		{
			jsFF.error('jsFF.%s(%s) called with a %s parameter which is null or empty !', 'addWheelScroll', 'id', 'id');
			return;
		}
		if (! $(id))
			jsFF.error(sprintf(this._e("jsFF.%s(...) called with a non existent element : '%s'."),'addWheelScroll', id));
		else
		{
			if (! this.isModuleLoaded('WheelScroll'))
				this.loadModule('WheelScroll');
			new jsFF._wheelScroll(id, options);
		} 
	},
	initTree : function ()
	{
		if (this._TafelTreeLoaded)
			TafelTreeInitBase();
	},
	addTree: function (id, struct, options)
	{					// Creation d'un arbre depuis une structure JavaScript
		if (! id || (id == ''))
		{
			jsFF.error('jsFF.%s(%s) called with a %s parameter which is null or empty !', 'addTree', 'id', 'id');
			return;
		}
		if (! this.isModuleLoaded('Tree'))
			this.loadModule('Tree');
		return new TafelTree (id, struct, options);
	},
	addTreeFromUL: function (id, imgBase, width, height, options)
	{					// Creation d'un arbre depuis un element UL de la page
		if (! this.isModuleLoaded('Tree'))
			this.loadModule('Tree');		
		return TafelTree.loadFromUL(id, imgBase, width, height, options, this.debugging);
	},
	addContextMenu : function (sel, classe, items, zInd)
	{
		if (! this.isModuleLoaded('contextMenu'))
			this.loadModule('contextMenu');
		zindex = zInd || 100;
		new jsFF.contextMenu({selector: sel, className: 'context-menu ' + classe, menuItems: items, zIndex: zindex});
	},
	addTableKit : function(id, options)
	{
		if (! id || (id == ''))
		{
			jsFF.error('jsFF.%s(%s) called with a %s parameter which is null or empty !', 'addTableKit', 'id', 'id');
			return;
		}
		var theme = options.theme | 'default';
		if (! this.isModuleLoaded('TableKit'))
			this.loadModule('TableKit', theme);
		
		return new TableKit(id, options);
	},
	hex_md4: function(s)		 	// Crypto MD4 functions
	{
		if (! this.isModuleLoaded('CryptoMD4'))
			this.loadModule('CryptoMD4');
		return binl2hex(core_md4(str2binl(s), s.length * this.cryptoChrsz));
	},
	b64_md4: function(s)
	{
		if (! this.isModuleLoaded('CryptoMD4'))
			this.loadModule('CryptoMD4');
		return binl2b64(core_md4(str2binl(s), s.length * this.cryptoChrsz));
	},
	str_md4: function(s)
	{
		if (! this.isModuleLoaded('CryptoMD4'))
			this.loadModule('CryptoMD4');
		return binl2str(core_md4(str2binl(s), s.length * this.cryptoChrsz));
	},
	hex_hmac_md4: function(key, data)
	{
		if (! this.isModuleLoaded('CryptoMD4'))
			this.loadModule('CryptoMD4');
		return binl2hex(core_hmac_md4(key, data)); 
	},
	b64_hmac_md4: function(key, data)
	{
		if (! this.isModuleLoaded('CryptoMD4'))
			this.loadModule('CryptoMD4');
		return binl2b64(core_hmac_md4(key, data)); 
	},
	str_hmac_md4: function(key, data)
	{
		if (! this.isModuleLoaded('CryptoMD4'))
			this.loadModule('CryptoMD4');
		return binl2str(core_hmac_md4(key, data)); 
	},
	hex_md5: function(s)		 	// Crypto MD5 functions
	{ 
		if (! this.isModuleLoaded('CryptoMD5'))
			this.loadModule('CryptoMD5');
		return binl2hex(core_md5(str2binl(s), s.length * jsFF.cryptoChrsz));
	},
	b64_md5: function(s)
	{
		if (! this.isModuleLoaded('CryptoMD5'))
			this.loadModule('CryptoMD5');
		return binl2b64(core_md5(str2binl(s), s.length * jsFF.cryptoChrsz));
	},
	str_md5: function(s)
	{
		if (! this.isModuleLoaded('CryptoMD5'))
			this.loadModule('CryptoMD5');
		return binl2str(core_md5(str2binl(s), s.length * jsFF.cryptoChrsz));
	},
	hex_hmac_md5: function(key, data)
	{
		if (! this.isModuleLoaded('CryptoMD5'))
			this.loadModule('CryptoMD5');
		return binl2hex(core_hmac_md5(key, data)); 
	},
	b64_hmac_md5: function(key, data)
	{
		if (! this.isModuleLoaded('CryptoMD5'))
			this.loadModule('CryptoMD5');
		return binl2b64(core_hmac_md5(key, data));
	},
	str_hmac_md5: function(key, data)
	{
		if (! this.isModuleLoaded('CryptoMD5'))
			this.loadModule('CryptoMD5');
		return binl2str(core_hmac_md5(key, data));
	},
	hex_sha1: function(s)		 	// Crypto SHA1 functions
	{
		if (! this.isModuleLoaded('CryptoSHA1'))
			this.loadModule('CryptoSHA1');
		return binb2hex(core_sha1(str2binb(s),s.length * jsFF.cryptoChrsz));
	},
	b64_sha1: function(s)
	{
		if (! this.isModuleLoaded('CryptoSHA1'))
			this.loadModule('CryptoSHA1');
		return binb2b64(core_sha1(str2binb(s),s.length * jsFF.cryptoChrsz));
	},
	str_sha1: function(s)
	{
		if (! this.isModuleLoaded('CryptoSHA1'))
			this.loadModule('CryptoSHA1');
		return binb2str(core_sha1(str2binb(s),s.length * jsFF.cryptoChrsz));
	},
	hex_hmac_sha1: function(key, data)
	{
		if (! this.isModuleLoaded('CryptoSHA1'))
			this.loadModule('CryptoSHA1');
		return binb2hex(core_hmac_sha1(key, data));
	},
	b64_hmac_sha1: function(key, data)
	{
		if (! this.isModuleLoaded('CryptoSHA1'))
			this.loadModule('CryptoSHA1');
		return binb2b64(core_hmac_sha1(key, data));
	},
	str_hmac_sha1: function(key, data)
	{
		if (! this.isModuleLoaded('CryptoSHA1'))
			this.loadModule('CryptoSHA1');
		return binb2str(core_hmac_sha1(key, data));
	}
};
jsFF._load();

