// ======================================================================================================================================================
//
//
//  Ekinoxe CMS Javascript Framework, <http://ekinoxe.fr>. Copyright (c) 2008-2009 Ekinoxe Origin, <http://ekinoxe.fr>, Tous droits réservés.
//  La copie, la redistribution ainsi que l'utilisation d'une ou plusieurs parties de ce composant n'est en aucun cas autorisé.
//
//
// ======================================================================================================================================================
// 
// TODO:
//   - Verifier la class Widget.radio
// 
// ======================================================================================================================================================


 // ------------------------------------------------------------------------------------------
 // Patch MooTools pour le problème du scroll qui pose probleme pour Sortables
 
 Drag.implement({
  start: function(event){
    if (this.options.preventDefault) event.preventDefault();
    this.mouse.start = event.page;
    this.fireEvent('beforeStart', this.element);
    var limit = this.options.limit;
    this.limit = {x: [], y: []};
    // get scroll from offset parent
    sc = this.element.getOffsetParent().getScroll();
    for (var z in this.options.modifiers){
      if (!this.options.modifiers[z]) continue;
      if (this.options.style) 
        this.value.now[z] = this.element.getStyle(this.options.modifiers[z]).toInt() + sc[z];
      else 
        this.value.now[z] = this.element[this.options.modifiers[z]] + sc[z];
      if (this.options.invert) this.value.now[z] *= -1;
      this.mouse.pos[z] = event.page[z] - this.value.now[z];
      if (limit && limit[z]){
        for (var i = 2; i--; i){
          if ($chk(limit[z][i])) 
            this.limit[z][i] = $lambda(limit[z][i])();
        }
      }
    }
    if ($type(this.options.grid) == 'number') 
      this.options.grid = {x: this.options.grid, y: this.options.grid};
    this.document.addEvents({mousemove: this.bound.check, mouseup: this.bound.cancel});
    this.document.addEvent(this.selection, this.bound.eventStop);
  }
 });

 // ------------------------------------------------------------------------------------------
 // Patch MooTools pour le problème du scroll qui pose probleme pour Sortables
 
 Drag.Move.implement({    
  checkAgainst: function(el, i){
    po = (this.positions) ? this.positions[i] : el.getCoordinates();
    // get scroll from offset parent
    sc = el.getOffsetParent().getScroll();
    if (sc.y) {
      po.top += sc.y;
      po.bottom += sc.y;
    }
    if (sc.x) {
      po.left += sc.x;
      po.right += sc.x;
    }
    var now = this.mouse.now;
    return (now.x > po.left && now.x < po.right && now.y < po.bottom && now.y > po.top);
  }
 }); 

var Framework = {};

// ---------------------------------------------------------------------------------------------------

/*****************************************************************************************************
 *************************** DOMParser pour Internet Explorer et Safari ******************************
 *****************************************************************************************************/
 
/**
 * Bien que Firefox et Opera possèdent cette classe, Safari et Internet Explorer ne proposent aucun
 * support pour celle-ci. Il faut donc réimplémenter la classe lorsque l'on se trouve sur l'un de ces
 * navigateurs, et la solution proposée est malheureusement différente entre ces deux navigateurs.
 */ 
if (typeof DOMParser == "undefined") { // On teste que DOMParser n'existe pas
   DOMParser = function () {}

   DOMParser.prototype.parseFromString = function (str, contentType) {
      if (typeof ActiveXObject != "undefined") { // Dans le cas d'IE, on peut utiliser la classe ActiveXObject, propre à IE
         var d = new ActiveXObject("MSXML.DomDocument");
         d.loadXML(str);
         return d;
      } else if (typeof XMLHttpRequest != "undefined") { // Dans le cas de Safari, il faut recréer un en-tête XML à partir de la chaîne XML récupérée
         var req = new XMLHttpRequest;
         // Ouverture en GET avec un en-tête XML ou un en-tête précisé dans contentType
         req.open("GET", "data:" + (contentType || "application/xml") +
                         ";charset=utf-8," + encodeURIComponent(str), false);
         if (req.overrideMimeType) {
            req.overrideMimeType(contentType);
         }
         req.send(null);
         return req.responseXML;
      }
   }
}
  
// ---------------------------------------------------------------------------------------------------

if(typeof console == 'undefined') {
  var console = { 
    log :function(){} 
   ,error : function() {}
   ,warn : function() {}
   ,info : function() {}
   ,debug : function() {}
  }
}
 
// ---------------------------------------------------------------------------------------------------

var D = function(){
  if(typeof console != "undefined") {
    var iMax = arguments.length;
    for(i=0; i<iMax; i++) {
      console.debug(arguments[i]);
    }
  }
}

var ER = function(){
  if(typeof console != "undefined") {
    var iMax = arguments.length;
    for(i=0; i<iMax; i++) {
      console.error(arguments[i]);
    }
  }
}

var EX = function(){
  if(typeof console != "undefined") {
    var iMax = arguments.length;
    for(i=0; i<iMax; i++) {
      console.error(arguments[i]);
    }
  }
}

var I = function(){
  if(typeof console != "undefined") {
    var iMax = arguments.length;
    for(i=0; i<iMax; i++) {
      console.info(arguments[i]);
    }
  }
}

var W = function(){
  if(typeof console != "undefined") {
    var iMax = arguments.length;
    for(i=0; i<iMax; i++) {
      console.warn(arguments[i]);
    }
  }
}

// ---------------------------------------------------------------------------------------------------

/*
xml2json v 1.1
copyright 2005-2007 Thomas Frank

This program is free software under the terms of the 
GNU General Public License version 2 as published by the Free 
Software Foundation. It is distributed without any warranty.
*/

xml2json={
	parser:function(xmlcode,ignoretags,debug){
		if(!ignoretags){ignoretags=""};
		xmlcode=xmlcode.replace(/\s*\/>/g,'/>');
		xmlcode=xmlcode.replace(/<\?[^>]*>/g,"").replace(/<\![^>]*>/g,"");
		if (!ignoretags.sort){ignoretags=ignoretags.split(",")};
		var x=this.no_fast_endings(xmlcode);
		x=this.attris_to_tags(x);
		x=escape(x);
		x=x.split("%3C").join("<").split("%3E").join(">").split("%3D").join("=").split("%22").join("\"");
		for (var i=0;i<ignoretags.length;i++){
			x=x.replace(new RegExp("<"+ignoretags[i]+">","g"),"*$**"+ignoretags[i]+"**$*");
			x=x.replace(new RegExp("</"+ignoretags[i]+">","g"),"*$***"+ignoretags[i]+"**$*")
		};
		x='<JSONTAGWRAPPER>'+x+'</JSONTAGWRAPPER>';
		this.xmlobject={};
		var y=this.xml_to_object(x).jsontagwrapper;
		if(debug){y=this.show_json_structure(y,debug)};
		return y
	},
	xml_to_object:function(xmlcode){
		var x=xmlcode.replace(/<\//g,"§");
		x=x.split("<");
		var y=[];
		var level=0;
		var opentags=[];
		for (var i=1;i<x.length;i++){
			var tagname=x[i].split(">")[0];
			opentags.push(tagname);
			level++
			y.push(level+"<"+x[i].split("§")[0]);
			while(x[i].indexOf("§"+opentags[opentags.length-1]+">")>=0){level--;opentags.pop()}
		};
		var oldniva=-1;
		var objname="this.xmlobject";
		for (var i=0;i<y.length;i++){
			var preeval="";
			var niva=y[i].split("<")[0];
			var tagnamn=y[i].split("<")[1].split(">")[0];
			tagnamn=tagnamn.toLowerCase();
			var rest=y[i].split(">")[1];
			if(niva<=oldniva){
				var tabort=oldniva-niva+1;
				for (var j=0;j<tabort;j++){objname=objname.substring(0,objname.lastIndexOf("."))}
			};
			objname+="."+tagnamn;
			var pobject=objname.substring(0,objname.lastIndexOf("."));
			if (eval("typeof "+pobject) != "object"){preeval+=pobject+"={value:"+pobject+"};\n"};
			var objlast=objname.substring(objname.lastIndexOf(".")+1);
			var already=false;
			for (k in eval(pobject)){if(k==objlast){already=true}};
			var onlywhites=true;
			for(var s=0;s<rest.length;s+=3){
				if(rest.charAt(s)!="%"){onlywhites=false}
			};
			if (rest!="" && !onlywhites){
				if(rest/1!=rest){
					rest="'"+rest.replace(/\'/g,"\\'")+"'";
					rest=rest.replace(/\*\$\*\*\*/g,"</");
					rest=rest.replace(/\*\$\*\*/g,"<");
					rest=rest.replace(/\*\*\$\*/g,">")
				}
			} 
			else {rest="{}"};
			if(rest.charAt(0)=="'"){rest='unescape('+rest+')'};
			if (already && !eval(objname+".sort")){preeval+=objname+"=["+objname+"];\n"};
			var before="=";after="";
			if (already){before=".push(";after=")"};
			var toeval=preeval+objname+before+rest+after;
			eval(toeval);
			if(eval(objname+".sort")){objname+="["+eval(objname+".length-1")+"]"};
			oldniva=niva
		};
		return this.xmlobject
	},
	show_json_structure:function(obj,debug,l){
		var x='';
		if (obj.sort){x+="[\n"} else {x+="{\n"};
		for (var i in obj){
			if (!obj.sort){x+=i+":"};
			if (typeof obj[i] == "object"){
				x+=this.show_json_structure(obj[i],false,1)
			}
			else {
				if(typeof obj[i]=="function"){
					var v=obj[i]+"";
					//v=v.replace(/\t/g,"");
					x+=v
				}
				else if(typeof obj[i]!="string"){x+=obj[i]+",\n"}
				else {x+="'"+obj[i].replace(/\'/g,"\\'").replace(/\n/g,"\\n").replace(/\t/g,"\\t").replace(/\r/g,"\\r")+"',\n"}
			}
		};
		if (obj.sort){x+="],\n"} else {x+="},\n"};
		if (!l){
			x=x.substring(0,x.lastIndexOf(","));
			x=x.replace(new RegExp(",\n}","g"),"\n}");
			x=x.replace(new RegExp(",\n]","g"),"\n]");
			var y=x.split("\n");x="";
			var lvl=0;
			for (var i=0;i<y.length;i++){
				if(y[i].indexOf("}")>=0 || y[i].indexOf("]")>=0){lvl--};
				tabs="";for(var j=0;j<lvl;j++){tabs+="\t"};
				x+=tabs+y[i]+"\n";
				if(y[i].indexOf("{")>=0 || y[i].indexOf("[")>=0){lvl++}
			};
			if(debug=="html"){
				x=x.replace(/</g,"&lt;").replace(/>/g,"&gt;");
				x=x.replace(/\n/g,"<BR>").replace(/\t/g,"&nbsp;&nbsp;&nbsp;&nbsp;")
			};
			if (debug=="compact"){x=x.replace(/\n/g,"").replace(/\t/g,"")}
		};
		return x
	},
	no_fast_endings:function(x){
		x=x.split("/>");
		for (var i=1;i<x.length;i++){
			var t=x[i-1].substring(x[i-1].lastIndexOf("<")+1).split(" ")[0];
			x[i]="></"+t+">"+x[i]
		}	;
		x=x.join("");
		return x
	},
	attris_to_tags: function(x){
		var d=' ="\''.split("");
		x=x.split(">");
		for (var i=0;i<x.length;i++){
			var temp=x[i].split("<");
			for (var r=0;r<4;r++){temp[0]=temp[0].replace(new RegExp(d[r],"g"),"_jsonconvtemp"+r+"_")};
			if(temp[1]){
				temp[1]=temp[1].replace(/'/g,'"');
				temp[1]=temp[1].split('"');
				for (var j=1;j<temp[1].length;j+=2){
					for (var r=0;r<4;r++){temp[1][j]=temp[1][j].replace(new RegExp(d[r],"g"),"_jsonconvtemp"+r+"_")}
				};
				temp[1]=temp[1].join('"')
			};
			x[i]=temp.join("<")
		};
		x=x.join(">");
		x=x.replace(/ ([^=]*)=([^ |>]*)/g,"><$1>$2</$1");
		x=x.replace(/>"/g,">").replace(/"</g,"<");
		for (var r=0;r<4;r++){x=x.replace(new RegExp("_jsonconvtemp"+r+"_","g"),d[r])}	;
		return x
	}
};


if(!Array.prototype.push){
	Array.prototype.push=function(x){
		this[this.length]=x;
		return true
	}
};

if (!Array.prototype.pop){
	Array.prototype.pop=function(){
  		var response = this[this.length-1];
  		this.length--;
  		return response
	}
};

// ---------------------------------------------------------------------------------------------------

var convertSize = function(size) {
   
  var file_size = 0;
		
  if(size >= 1073741824) { 
			
    file_size = (Math.round(size / 1073741824 * 100) / 100) + " Go"; 
			
  } else if(size >= 1048576) { 
			
    file_size = (Math.round(size / 1048576 * 100) / 100) + " Mo"; 
			
  } else if(size >= 1024) { 
			
    file_size = (Math.round(size / 1024 * 100) / 100) + " Ko"; 
			
  } else { 
			
    file_size = size +" octets"; 
			
  }
		
  return file_size;
	 
}

// ---------------------------------------------------------------------------------------------------

var time = function() {

  return (new Date).getTime();

}

// ---------------------------------------------------------------------------------------------------

var cloneObject = function(obj) {

  var clonedObject = function(){};
  clonedObject.prototype = obj;
  return new clonedObject;
    
}

// ---------------------------------------------------------------------------------------------------

var toXML = function() {

  return (new DOMParser()).parseFromString(arguments[0].toString(), "text/xml");
  
}

// ---------------------------------------------------------------------------------------------------

var toJSON = function() {

  return xml2json.parser(arguments[0].toString(),'b,i'); 
  
}

// ---------------------------------------------------------------------------------------------------

var toText = function() {

  return (new XMLSerializer()).serializeToString(arguments[0]);

}

// ---------------------------------------------------------------------------------------------------

var isEmail = function() {

  return this.test(/^[a-zA-Z0-9._-]+@[a-zA-Z0-9._-]{3,}\.[a-zA-Z]{2,4}$/);
  
}

function verifMail(email) { // vérif validité email par REGEXP 
   var reg = /^[a-z0-9._-]+@[a-z0-9.-]{2,}[.][a-z]{2,3}$/
   return (reg.exec(email)!=null)
}

// ---------------------------------------------------------------------------------------------------

String.implement({

   toXML   : toXML
 , isEmail : isEmail
  
});

// ---------------------------------------------------------------------------------------------------

var ReadCookie = function(cookieName) {

  var theCookie=""+document.cookie;
  var ind=theCookie.indexOf(cookieName);
  if (ind==-1 || cookieName=="") return ""; 
  var ind1=theCookie.indexOf(';',ind);
  if (ind1==-1) ind1=theCookie.length; 
  return unescape(theCookie.substring(ind+cookieName.length+1,ind1));
  
}

// ---------------------------------------------------------------------------------------------------

var microtime = function(get_as_float) {

  var now = new Date().getTime() / 1000;
  var s = parseInt(now);
  return (get_as_float) ? now : (Math.round((now - s) * 1000) / 1000) + ' ' + s;
 
}

function UniqueID() { 

  str = base64_encode((microtime(true)+Math.random()).toString());
  while(str.test(/\=/)) { str = str.replace('=',''); }
  return str;
  
}

function preg_quote( str ) {

  return (str+'').replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!<>\|\:])/g, "\\$1");
    
}

// ---------------------------------------------------------------------------------------------------

var basename = function (path, suffix) {

    // http://kevin.vanzonneveld.net
    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: Ash Searle (http://hexmen.com/blog/)
    // +   improved by: Lincoln Ramsay
    // +   improved by: djmix
    // *     example 1: basename('/www/site/home.htm', '.htm');
    // *     returns 1: 'home'
 
    var b = path.replace(/^.*[\/\\]/g, '');
    
    if (typeof(suffix) == 'string' && b.substr(b.length-suffix.length) == suffix) {
        b = b.substr(0, b.length-suffix.length);
    }
    
    return b;
}

// ---------------------------------------------------------------------------------------------------

var length = function(object) {
  
  if(typeof object == 'object') {
    var i = 0;
    $each(object, function(){
      i++;
    });
    
    return i;
  } else
    return false;
  
}

// ---------------------------------------------------------------------------------------------------


Number.prototype.toFixed=function(x) {
   var temp=this;
   temp=Math.round(temp*Math.pow(10,x))/Math.pow(10,x);
   return temp;
}


// ---------------------------------------------------------------------------------------------------

/**
*
*  Base64 encode / decode
*  http://www.webtoolkit.info/
*
**/
 
var Base64 = {
 
	// private property
	_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
 
	// public method for encoding
	encode : function (input) {
		var output = "";
		var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
		var i = 0;
 
		input = Base64._utf8_encode(input);
 
		while (i < input.length) {
 
			chr1 = input.charCodeAt(i++);
			chr2 = input.charCodeAt(i++);
			chr3 = input.charCodeAt(i++);
 
			enc1 = chr1 >> 2;
			enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
			enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
			enc4 = chr3 & 63;
 
			if (isNaN(chr2)) {
				enc3 = enc4 = 64;
			} else if (isNaN(chr3)) {
				enc4 = 64;
			}
 
			output = output +
			this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
			this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
 
		}
 
		return output;
	},
 
	// public method for decoding
	decode : function (input) {
		var output = "";
		var chr1, chr2, chr3;
		var enc1, enc2, enc3, enc4;
		var i = 0;
 
		input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
 
		while (i < input.length) {
 
			enc1 = this._keyStr.indexOf(input.charAt(i++));
			enc2 = this._keyStr.indexOf(input.charAt(i++));
			enc3 = this._keyStr.indexOf(input.charAt(i++));
			enc4 = this._keyStr.indexOf(input.charAt(i++));
 
			chr1 = (enc1 << 2) | (enc2 >> 4);
			chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
			chr3 = ((enc3 & 3) << 6) | enc4;
 
			output = output + String.fromCharCode(chr1);
 
			if (enc3 != 64) {
				output = output + String.fromCharCode(chr2);
			}
			if (enc4 != 64) {
				output = output + String.fromCharCode(chr3);
			}
 
		}
 
		output = Base64._utf8_decode(output);
 
		return output;
 
	},
 
	// private method for UTF-8 encoding
	_utf8_encode : function (string) {
		string = string.replace(/\r\n/g,"\n");
		var utftext = "";
 
		for (var n = 0; n < string.length; n++) {
 
			var c = string.charCodeAt(n);
 
			if (c < 128) {
				utftext += String.fromCharCode(c);
			}
			else if((c > 127) && (c < 2048)) {
				utftext += String.fromCharCode((c >> 6) | 192);
				utftext += String.fromCharCode((c & 63) | 128);
			}
			else {
				utftext += String.fromCharCode((c >> 12) | 224);
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
				utftext += String.fromCharCode((c & 63) | 128);
			}
 
		}
 
		return utftext;
	},
 
	// private method for UTF-8 decoding
	_utf8_decode : function (utftext) {
		var string = "";
		var i = 0;
		var c = c1 = c2 = 0;
 
		while ( i < utftext.length ) {
 
			c = utftext.charCodeAt(i);
 
			if (c < 128) {
				string += String.fromCharCode(c);
				i++;
			}
			else if((c > 191) && (c < 224)) {
				c2 = utftext.charCodeAt(i+1);
				string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
				i += 2;
			}
			else {
				c2 = utftext.charCodeAt(i+1);
				c3 = utftext.charCodeAt(i+2);
				string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
				i += 3;
			}
 
		}
 
		return string;
	}
 
}

// ---------------------------------------------------------------------------------------------------

var base64_encode = Base64.encode.bind(Base64);
var base64_decode = Base64.decode.bind(Base64);
var $B64 = Base64;

// ---------------------------------------------------------------------------------------------------

var Remote = new Class({
 
   Implements : [Events, Options]
   
  ,options : {
     name : ''
    ,command : ''
    ,getData : ''
    ,params : {}
    ,format : 'xml'
    ,async : true
   }
   
  ,response : {
     code: null
    ,data: null
    ,text: null
    ,type: null
   }
 
  ,xhr : null
  ,time : 0
  
  ,statistics : {
     start: 0
    ,download: 0
    ,events: 0
    ,parse: 0
  }
   
  ,nativeEvents : {
  
    onComplete : function() {
    
      this.statistics.download = (new Date()).getTime();
 
      if(this.xhr.response.text==null || this.xhr.response.text=='') {
        W('Remote error : Response is null');
        this.fireEvent('error', this);
        return false;
      }
 
      parts = this.xhr.response.text.split(/\<\/response\>/g);
      if(parts[1] != '') {
        this.xhr.response.xml = toXML(parts[0]+'</response>');
        delete parts;      
      }

      if(!this.xhr.response.xml) {
        this.fireEvent('error', this);
        return false; 
      }  
      
      switch(this.options.format) {
      
        case 'xml':

          /* Même si nous avons défini la classe DOMParser pour IE et Safari, ce premier ne supporte pas les XMLDocument.
           * De ce fait les méthodes getElement et get ne fonctionnent pas. Une surcharge est de surcroît impossible ;
           * il faut traiter les cas indépendamment
           */
          if (typeof XMLDocument == 'undefined') { // Cas IE
            response = this.xhr.response.xml.getElementsByTagName('response')[0];
  
            if (response.getElementsByTagName('code')[0].childNodes.length > 0)
              this.response.code = parseInt(response.getElementsByTagName('code')[0].childNodes[0].nodeValue);
            else
              this.response.code = parseInt(''); // On parse du vide, on obtiendra NaN
            
            if (response.getElementsByTagName('text')[0].childNodes.length > 0)
              this.response.text = response.getElementsByTagName('text')[0].childNodes[0].nodeValue;
            else
              this.response.text = '';
              
            if (response.getElementsByTagName('type')[0].childNodes.length > 0)
              this.response.type = response.getElementsByTagName('type')[0].childNodes[0].nodeValue.toLowerCase();
            else
              this.response.type = '';            
    
            if(this.response.type == 'xml') 
              this.response.data = response.getElementsByTagName('data')[0];
            else if(this.response.type == 'json')
              this.response.data = JSON.decode(response.getElementsByTagName('data')[0].childNodes[0].nodeValue.trim());
            else {
              if (response.getElementsByTagName('data')[0].childNodes.length > 0)
                this.response.data = response.getElementsByTagName('data')[0].childNodes[0].nodeValue;
              else
                this.response.data = '';
            }
          } else { // Cas classique
            response = this.xhr.response.xml.getElement('response');
            this.response.code = parseInt(response.getElement('code').get('text'));
            this.response.text = response.getElement('text').get('text');
            this.response.type = response.getElement('type').get('text').toLowerCase();

            if(this.response.type == 'xml')
              this.response.data = response.getElement('data');
            else if(this.response.type == 'json')
              this.response.data = JSON.decode(response.getElement('data').get('text').trim());
            else
              this.response.data = response.getElement('data').get('text');
          }

        break;
        
        case 'json':
        
          response = JSON.decode(this.xhr.response.text);
          this.response.code = parseInt(response.code);
          this.response.text = response.text;
          this.response.type = response.type.toLowerCase();
          
          if(this.response.type == 'xml')
            this.response.data = toXML('<?xml version="1.0" encoding="UTF-8"?>'+response.data.trim());
          else if(this.response.type == 'json')
            this.response.data = JSON.decode(response.data.trim());
          else
            this.response.data = response.data;

        break;
        
      }

      switch(this.getResponseType()) {
      
        case 'array':
        
          this.response.data = JSON.decode(this.response.data);
        
        break;
      
      }
      
      this.statistics.parse = (new Date()).getTime(); 
      this.fireEvent( (this.response.code==1 || this.response.code<1000) ? 'complete' : 'error', this);
      this.statistics.events = (new Date()).getTime();
      
      /*
      I('Remote - Statistiques: '
       +'load/'+(this.statistics.download - this.statistics.start)+'ms. '
       +'parse/'+(this.statistics.parse - this.statistics.download)+'ms. '
       +'events/'+(this.statistics.events - this.statistics.parse)+'ms. '
       );
      */
      
    }
    
   ,onError : function() {
      this.fireEvent('error', this);
    }
  
  }
  
  ,initialize : function(options) {
  
     this.setOptions(options);
     this.xhr = new Request({
        method: 'post'
       ,encoding : 'utf-8'
       ,url: wwwroot+'/system/remote/'+this.options.name+'/'+this.options.command+'.html'
       ,async: this.options.async
     });
     this.xhr.addEvent('complete', this.nativeEvents.onComplete.bind(this));
     this.xhr.addEvent('error', this.nativeEvents.onError.bind(this));
     
  }

  ,call : function(options) {
  
     if(options)
       this.setOptions(options);
   
     this.statistics.start = (new Date()).getTime();
     this.fireEvent('call');
     
     data = 'format='+this.options.format+'&params='+base64_encode(JSON.encode(this.options.params));
     
     try{
       if(this.options.getData != "") {
         data = data+"&"+this.options.getData.toString().trim();
       }
     } catch(e) {
       ER(e);
     }
     
     return this.xhr.send(data);
     
  }
  
  ,getStatistics : function() {
  
    return this.statistics;
  
  }
  
 ,getResponseData : function() {
 
   return this.response.data;
 
  }
  
 ,getResponseCode : function() {
 
   return this.response.code;
 
  }
  
 ,getResponseText : function() {
 
   return this.response.text;
 
  }
  
 ,getResponseType : function() {
 
   return this.response.type;
 
  }
  
}); 

// ---------------------------------------------------------------------------------------------------

Remote.Group = new Class({
 
   Implements : [Events, Options]
 
   ,remotes : []
   
   ,options : {
     
   }
   
   ,response : ''
   ,tick : 0
   
   ,initialize : function() {
   }
   
   ,add : function(options) {
   
     remote = new Remote(options);
     this.remotes.push(remote);
   
   }

   ,call : function() {
   
     for(i=0; i<this.remotes.length; i++) {
       fn = (i == this.remotes.length-1) ? this.nativeEvents.onComplete.bind(this) : this.nativeEvents.onTick.bind(this)
       this.remotes[i].addEvent('complete', fn);
       this.remotes[i].addEvent('error', this.nativeEvents.onError.bind(this));
     }
     
     this.remotes[0].call();
   
   }
   
   ,getResponses : function() {
   }
   
   ,nativeEvents : {
   
     onTick : function(){
     
       this.response = this.remotes[this.tick].response;
       this.fireEvent('tick', this.remotes[this.tick]);
       this.remotes[++this.tick].call();
       
     }
     
     ,onComplete : function() {
     
       this.response = this.remotes[this.tick].response;
       this.fireEvent('complete', this.remotes[this.tick]);
     
     }
     
     ,onError : function() {
     
       this.fireEvent('error');
     
     }
   
   }
 
}); 

// ---------------------------------------------------------------------------------------------------

var ProgressBar = new Class({
 
   Implements : [Events, Options]
   
   ,options : {
      time : 20 
     ,size : 300
     ,autostop : true
   }
   
   ,interval : 0
   ,tick : 0
   ,uniqueid : 0
   ,fx : null
   ,currentValue : 2
   
   ,elements : {
      progressContainer : null
     ,progressBar : null
     ,progressLabel : null
   }
   
   ,initialize : function(options) {
   
     this.setOptions(options);
     
     this.elements.progressContainer = new Element('div',{ id:'ek-progress-container-'+UniqueID() });
     this.elements.progressContainer.addClass('ek-progress-container');
     this.elements.progressContainer.setStyle('width',this.options.size+'px');
     
     this.elements.progressBar = new Element('div',{ id:'ek-progress-bar-'+UniqueID() });
     this.elements.progressBar.addClass('ek-progress-bar');
     this.elements.progressBar.setStyle('width','10px');
     
     this.elements.progressLabel = new Element('div',{ id:'ek-progress-label-'+UniqueID() });
     this.elements.progressLabel.addClass('ek-progress-label');
     this.elements.progressLabel.setStyle('width',this.options.size+'px');
     
     this.elements.progressContainer.adopt(this.elements.progressLabel.set('html','&nbsp;'));
     this.elements.progressContainer.adopt(this.elements.progressBar.set('html','&nbsp;'));
     
     this.fx = new Fx.Morph(this.elements.progressBar, { duration: 400 , transition:Fx.Transitions.Cubic.easeOut });
     this.fx.addEvent('complete', this.nativeEvents.onEffectComplete.bind(this));
     
     this.interval = setInterval(this.nativeEvents.onUpdate.bind(this), this.options.time);
     
     return this;
   
   }
   
   ,inject : function(el) {
   
     if($(el)) {
       $(el).adopt(this.elements.progressContainer);
       return this;
     }
     
     return this;
  
   }
   
   ,setLabel : function(text) {
   
     this.elements.progressLabel.set('text',text);
     return this;
   
   }
   
   ,setValue : function(percent) {
   
     percent = (percent<0) ? 0 : ( (percent<0) ? 100 : percent ); 

     current = parseInt(this.elements.progressBar.getStyle('width'));
     max = parseInt(this.elements.progressContainer.getStyle('width'));
     next = max * percent / 100;
     
     // Valeurs max / min
     next = (next<6) ? 6 : next;
     next = (next>max) ? max : next;
     
     this.currentValue = percent;
     this.fx.cancel().start({width:[ current , next ]});
     
     if(this.interval==0 && this.options.autostop==true) {
       this.interval = setInterval(this.nativeEvents.onUpdate.bind(this), this.options.time);
     }
         
     return this;
   
   }
   
   ,setSize : function(size) {
   
     size = parseInt(size);
     size = (size<=20) ? 20 : size;

     this.options.size = size;
     next = size * this.currentValue / 100;
     
     this.elements.progressContainer.setStyle('width',this.options.size+'px');
     this.elements.progressBar.setStyle('width', next+'px');
     this.elements.progressLabel.setStyle('width', this.options.size+'px');
     
     return this;
   
   }
   
   ,setTime : function(time) {
   
     this.options.time = parseInt(time);
   
   }
   
   ,destroy : function() {
   
     this.fireEvent('destroy');
   
     if(this.interval>0) {
       clearInterval(this.interval);
     }
     
     this.fx.cancel();
     this.fx = null;
   
     this.elements.progressBar.destroy();
     this.elements.progressContainer.destroy();
     this.elements.progressContainer = null;
     this.elements.progressBar = null;
     
     return this;
   
   }
     
   ,nativeEvents : {
   
     onUpdate : function() {
       this.tick = (this.tick >= 18) ? 0 : this.tick+1;
       this.elements.progressBar.setStyles({ 'background-position':'-'+this.tick+'px 0px'});
     }
     
    ,onEffectComplete : function() {
       if(this.currentValue==100) {
         if(this.interval>0 && this.options.autostop==true) {
           clearInterval(this.interval);
           this.interval = 0; 
         }
       }
       this.fireEvent('progress');
     }
     
   }
   
});

// ---------------------------------------------------------------------------------------------------

var Widget = new Class({

  isWidget : true

  ,options : {
    type : 'unknown'
   ,element : null
   ,id : UniqueID()
   ,name : UniqueID()
   ,defaultValue : null
  }
  
  ,Implements : [Options]
  
  ,initialize : function(options) { 
     
     this.setOptions(options);

  }
  
  ,eventListener : new Events()
 
  ,addEvent : function(name, func) {
    
    switch(this.getType()) {
    
      case 'radio':
        $$('span.ek-radio-'+this.getName()+'').each(function(el){
          inst = el.getParent().getParent().retrieve('widget');
          if(inst!=null) { inst.eventListener.addEvent(name, func); }
        }.bind(this));
      break;
      case 'checkbox': //W('addEvent', this.getName(), $$('span.ek-checkbox-'+this.getName()+''));
        $$('span.ek-checkbox-'+this.getName()+'').each(function(el){
          inst = el.getParent().getParent().retrieve('widget');
          if(inst!=null) { 
            if(name=='change') {
              inst.eventListener.addEvent('check', func);
              inst.eventListener.addEvent('uncheck', func);
            } else {
              inst.eventListener.addEvent(name, func);
            }
          }
        }.bind(this));
      break;
    
      default:
        this.eventListener.addEvent(name,func);
      break;
    
    }
    
    return this;
    
  }	
  
  ,resetEvents : function(name) {
  
    this.eventListener.$events = {};
    return this;
  
  }
  
  ,fireEvent : function(name, bind) {
 
    switch(this.getType()) {
    
      case 'radio':
        /*
        $$('span.ek-radio-'+this.getName()+'').each(function(el){
          inst = el.getParent().getParent().retrieve('widget');
          if(inst) { inst.eventListener.fireEvent(name, bind); }
        }.bind(this));
        */
        this.eventListener.fireEvent(name, bind);
      break;
      case 'checkbox':  //W('fireEvent', this.getName(), $$('span.ek-checkbox-'+this.getName()+''));
        /*
        $$('span.ek-checkbox-'+this.getName()+'').each(function(el){
          inst = el.getParent().getParent().retrieve('widget');
          if(inst && inst!=this) { inst.eventListener.fireEvent(name, bind); }
        }.bind(this));
        */
        //D(this.getElement(),this.eventListener.fireEvent,name, bind);
        this.eventListener.fireEvent(name, bind);
      break;
    
      default:
        this.eventListener.fireEvent(name,bind);
      break;
    
    }
    
    return this;
    
  }
  
  ,getType : function() {
  
    return this.options.type;
    
  }
  
  ,getName : function() {
  
    return this.options.name;
    
  }
  
  ,getID : function() {
  
    return this.options.id;
    
  }
  
  ,getElement : function() {
  
    return this.options.element;
    
  }
  
  ,check : function(state) {
  
    state = (state===true);
  
    switch(this.getType()) {
    
      case 'checkbox':
        input = this.getElement().getElement('input');
        input.checked = state;
        input.fireEvent('change');
        return true;
      break;
      
      case 'radio':
        input = this.getElement().getElement('input');
        input.checked = state;
        input.fireEvent('change');
        return true;
      break;
      
      default:
        return false;
      break;
      
    }
  
  }
  
  ,checked : function() {
  
    switch(this.getType()) {
    
      case 'checkbox':
        return this.getElement().getElement('input').checked ? true : false; 
        
      default:
        return false;
      break;
    
    }
  
  }

  ,checkAll : function() {
  
    switch(this.getType()) {
    
      case 'checkbox':
        $$('input[name='+this.getName()+']').each(function(input){ 
          input.checked = true;
          input.fireEvent('change');
        });
        return true;
      break;
      
      default:
        return false;
      break;
    
    }
    
  }

  ,uncheckAll : function() {
  
    switch(this.getType()) {
    
      case 'checkbox':
        $$('input[name='+this.getName()+']').each(function(input){ 
          input.checked = false;
          input.fireEvent('change');
        });
        return true;
      break;
      
      default:
        return false;
      break;
    
    }
    
  }
  
  ,getValue : function() {
  
    switch(this.getType()) {
    
      case 'text':
      case 'password':
      case 'textarea': 
        return this.getElement().value;
      break;
      
      case 'radio':
        var all = Widgets.getAll();
        radios = [];
        // Récupération des cases radios du même nom
        if(all && all.length>0) {
          $each(all, function(wdgt) {
			if(wdgt!=null && this.getName()==wdgt.getName()) {
              radios.push(wdgt.getElement().getElement('input'));
            }
          }.bind(this));
        }
        // Récupération de la valeur de la case actuellement cochée
        value = null;
        if(radios && radios.length>0) {
          $each(radios, function(radio){
            if(radio.checked == true ) { 
              value = radio.value;
            }
          }.bind(this));
        }
        return value;
      break;
      
      case 'checkbox':
        return this.getElement().getElement('input').value;
      break;
      
      case 'button':
        return this.getElement().getElement('span.center').innerHTML;
      break;
    
    }
  
  }
  
  ,getValues : function() {
  
    switch(this.getType()) {
    
      case 'checkbox':
        var values = [];
        $$('input[name='+this.getName()+']').each(function(input){ 
          if(input.checked)
            values.push(input.value);
        });
        return values;
      break;
      
      default:
        return [this.getValue()];
      break;
    
    }
  
  }
  
  ,setValue : function(val) {
  
     switch(this.getType()) {
     
       case 'button':
         return this.getElement().getElement('span.center').innerHTML = val;
       break;
       
       case 'text':
       case 'password':
       case 'textarea':
		 this.getElement().removeClass('ek-input-text-empty');
         return this.getElement().value = val;
       break;
     
     }
  
   }
   
  ,setIcon : function(url, small) {
    
    switch(this.getType()) {
      case 'button':
      
        small = (typeof small == "undefined") ? 0 : small.toInt();
        div = this.getElement();
        span = div.getElement('span.center');
        val = span.get('text').trim();
         
        this.setValue('');
        
        spanIcon = new Element('span');
        spanIcon.set('html','');
        
        if(val.length == 0) {
          iconStyle = {
              "background" : "url('"+url+"') "+(small==1?'0px 0px':'0')+" no-repeat"
            , "height": "21px"
            , "float" : "left"
            , "margin-top" : "2px"
            , "padding-left": (small==1?'12px':'13px')
          };
        } else {
          iconStyle = {
              "background" : "url('"+url+"') "+(small==1?'0px 0px':'0px 0')+" no-repeat"
            , "height" : "17px"
            , "float" : "left"
            , "margin-top" : "2px"
            , "padding-left" : (small==1?'13px':'19px')
          };
        }

        spanIcon.setStyles(iconStyle);
        span.adopt(spanIcon);

        if(val.length != 0) {
          span.appendText(val);
        }
        
      break;
      
    }
      
  }
  
  ,setStyle : function(property, value){
    
    if(typeof property != 'undefined' && typeof value != 'undefined') {
      div = this.getElement();
      return div.setStyle(property, value);
    }
  }
  
  ,setStyles : function(object){
    if(typeof object == 'object') {
      div = this.getElement();
      return div.setStyles(object);
    }
  }
  
  ,seekAndSelect : function(value,state) {
  
    state = !(state === false);
  
    switch(this.getType()) {
    
      case 'radio':
      case 'checkbox':
        $$('input[name='+this.getName()+']').each(function(input){ 
          if(input.value == value) {
            inst = input.getParent().retrieve('widget');
            inst.check(state);
          }
        }.bind(this));
      break;
      
      default:
        // Nothing
      break;
      
    }
  
  }
   
  ,prepare : function() {
    
    //W('Added widget: type/'+this.getType()+' id/'+this.getID()+' name/'+this.getName()+'');
    switch(this.getType()) {
    
      case 'tabs':
      
        div = this.getElement();
        children = div.getChildren();
        div.set('html','');
        div.adopt(new Element('div').addClass('ek-tab-list').setStyles({'clear':'both', 'display':'block'}));
        
        children.each(function(child){ div.adopt(child); });
        
        containers = div.getElements('div.ek-tab-container');
        if(containers.length>0) {
          for(i=0;i<containers.length;i++) {
          
            container = containers[i];
            title = container.getElement('div.ek-tab-title');
            newTitle = title.clone();
            title.destroy();
            newTitle.injectInside(div.getElement('div.ek-tab-list'));
            newTitle.addClass('radius-3px-top').addClass('shadow-light').setStyles({'cursor':'pointer','float':'left'});
            newTitle.store('number', i);
            
            newTitle.addEvent('click',function(){
               titles = this.root.getElement('div.ek-tab-list').getElements('div.ek-tab-title');
               this.containers.addClass('disabled');
               this.current.removeClass('disabled');
               titles.removeClass('ek-tab-active');
               this.title.addClass('ek-tab-active');
               this.instance.fireEvent('change', this.title);
            }.bind({ root:div , containers:containers , current:container , title:newTitle, instance:this }));

            container.addClass('radius-3px').addClass('disabled').setStyles({'clear':'both'});
            
            if(container.get('class').match(/active/i))
              newTitle.fireEvent('click');
            
            delete title;
            
          }
          
        }
      break;
    
      case 'radio':
      case 'checkbox':
      
        // --- Récuperation des elements
        span = this.getElement();
        input = span.getElement('input');
        label = span.getElement('label');
        vbox = label.getElement('span');
        
        if(span.retrieve('ready') == 1) {
          return(true);
        }
        
        span.store('ready',1); 
        
        // --- onChange
        onChange = function() {
          setTimeout(function() {
            switch(this.input.type) {
            
              //--- checkbox
              case 'checkbox':
                if(this.input.checked == true) {
                  this.inst.fireEvent('check', this.inst);
                  this.vbox.setStyles({'background-position': '-16px '+this.vbox.getStyle('background-position').split(/\s/)[1] });
                } else {
                  this.inst.fireEvent('uncheck', this.inst);
                  this.vbox.setStyles({'background-position': '0 '+this.vbox.getStyle('background-position').split(/\s/)[1] });
                }
				this.inst.fireEvent('change');
              break;
              
              //--- radio
              case 'radio': 
                $$('span.ek-radio-'+this.input.name+'').each(function(el){
                  oldPos = el.getStyle('background-position').split(/\s/);
                  el.setStyles({'background-position': '0 '+el.getStyle('background-position').split(/\s/)[1] });
                  el.getParent().getParent().removeClass('ek-radio-checked');
                  this.inst.fireEvent('uncheck', this.inst);
                }.bind(this));
                this.inst.fireEvent('check', this.inst);
                this.inst.getElement().addClass('ek-radio-checked');
                this.vbox.setStyles({'background-position': '-16px '+this.vbox.getStyle('background-position').split(/\s/)[1] });
				this.inst.fireEvent('change');
              break;
              // fin switch
              
            }
          }.bind(this), 0);
        }.bind({ inst:this , span:span , input:input , label:label , vbox:vbox });
        
        // --- onMouseOver
        onMouseOver = function() {
          setTimeout(function() {
            switch(this.input.type) {
            
              //--- radio
              case 'radio':
                this.vbox.setStyles({'background-position': this.vbox.getStyle('background-position').split(/\s/)[0]+' -381px' });
              break;
              
              //--- checkbox
              case 'checkbox':
                this.vbox.setStyles({'background-position': this.vbox.getStyle('background-position').split(/\s/)[0]+' -27px' });
              break;
              
            }
          }.bind(this), 0);
        }.bind({ span:span , input:input , label:label , vbox:vbox });
        
        // --- onMouseOut
        onMouseOut = function() {
          setTimeout(function() {
            switch(this.input.type) {
            
              //--- radio
              case 'radio':
                this.vbox.setStyles({'background-position': this.vbox.getStyle('background-position').split(/\s/)[0]+' -357px' });
                break;
                
              //--- checkbox
              case 'checkbox':
                this.vbox.setStyles({'background-position': this.vbox.getStyle('background-position').split(/\s/)[0]+' -3px' });
              break;
              
            }
          }.bind(this), 0);
        }.bind({ span:span , input:input , label:label , vbox:vbox });
        // --- Ajout des évènements
        
        if(input.checked==true) {
          var parts = vbox.getStyle('background-position').split(/\s/);
          var y = parts[1] || '-3px';
          vbox.setStyles({'background-position': '-16px '+y });
          this.getElement().addClass('ek-radio-checked');
        }
        
        input.addEvent('change',   onChange);
        span.addEvent('mousedown', onMouseOver);
        span.addEvent('mouseup',  onMouseOut);
        
      break;
      
      case 'text':
      case 'password':
      case 'textarea':
      
        input = this.getElement();
        
        if(input.hasClass('ek-default-value')) {
        
          input.store('default',input.value);
          input.addEvent('focus', function(){ 
            def = this.input.retrieve('default');
            this.input.addClass('ek-input-text-nempty').removeClass('ek-input-text-empty');
            if(def == this.input.value) { this.input.value = ''; }
			this.inst.fireEvent('focus');
          }.bind({ inst:this,input:input }));
          input.addEvent('blur', function(){
            def = this.input.retrieve('default');
            if(this.input.value == '') {
              this.input.value = def;
              this.input.removeClass('ek-input-text-nempty').addClass('ek-input-text-empty');
            }
			this.inst.fireEvent('blur');
          }.bind({ inst:this,input:input }));
          
          input.removeClass('ek-input-text-nempty').addClass('ek-input-text-empty');
          
        }
        
        input.addEvent('change', function() {
          this.inst.fireEvent('change');
        }.bind({ inst:this,input:input }));
        
        input.addEvent('keydown', function(key) {
          this.inst.fireEvent('keydown', key);
        }.bind({ inst:this,input:input }));
        
        input.addEvent('keyup', function(key) {
          this.inst.fireEvent('keyup', key);
        }.bind({ inst:this,input:input }));
        
      break;
      
      case 'button':
        span = this.getElement();
        link = span.getElements('a')[0];
        link.addEvent('mouseup', function() {
          this.fireEvent('click');
        }.bind(this));
      break;

    }
    
  }

});

// ---------------------------------------------------------------------------------------------------

Widget.checkbox = new Class({
  
  options : {
      'label':'Aucun label'
    , 'name':''
    , 'id':''
    , 'value':''
    , 'checked':0
    , 'style':''
  }
  
  , Implements : [Options]
  
  , initialize : function(options) {
  
    this.setOptions(options);
    
    if(this.options.id=='')
      this.options.id = 'ek-checkbox-'+UniqueID();
    
    el = this.create();

    return el.retrieve('widget');
    
  }
  
  , create : function() {
    
    var span = new Element('span', {'class':'ek-checkbox ek-widget', 'style':this.options.style});
    
    var input = new Element('input', {
        'type': 'checkbox'
      , 'value': this.options.value
      , 'id':this.options.id
      , 'name': this.options.name
      , 'checked': ( (this.options.checked.toInt()>0) ? 'checked' : '' )
    });
    
    span.adopt( input );
    
    var label = new Element('label', {'for':this.options.id, 'html':this.options.label});
    (new Element('span', {'class':'ek-checkbox-'+this.options.name})).inject(label, 'top');
        
    span.adopt( label );
    
    Widgets.addObject(new Widget({ type:'checkbox', element:span , id:this.options.id , name:this.options.name}), span);
    
    this.element = span;
    
    return span;
    
  }
  
});

// ---------------------------------------------------------------------------------------------------

Widget.radio = new Class({
  
  options : {
      'label':'Aucun label'
    , 'name':''
    , 'id':''
    , 'value':''
    , 'checked':0
    , 'style':''
    , 'element' : null
  }
  
  , Implements : [Options]
  
  , initialize : function(options) {
    this.setOptions(options);
    
    if(this.options.id=='')
      this.options.id = 'ek-radio-'+UniqueID();
    
    //return this.create();
    
    el = this.create();

    return el.retrieve('widget');
    
  }
  
  , create : function() {
    
    var span = new Element('span', {'class':'ek-radio', 'style': 'float:left;'+this.options.style});
    
    span.adopt( new Element('input', {
        'type': 'radio'
      , 'value': this.options.value
      , 'id':this.options.id
      , 'name': this.options.name
      , 'checked': this.options.checked.toInt()
    }) );
    
    var label = new Element('label', {'for':this.options.id, 'html':this.options.label});
    (new Element('span', {'class':'ek-radio-'+this.options.name})).inject(label, 'top');
        
    span.adopt( label );
    
    Widgets.addObject(new Widget({ type:'radio', element:span , id:this.options.id , name:this.options.name}), span);
    
    this.element = span;
    
    return span;
    
  }
  
});

// ---------------------------------------------------------------------------------------------------

Widget.button = new Class ({
  
  options : {
     'value':''
    ,'name':''
    ,'id':''
    ,'theme':'color'
    ,'size':20
    ,'class':''
    ,'style':''
    ,'type':'button'
    ,'color':''
    ,'bold':0
    ,'icon':''
    ,'href':''
    ,'alt':''
    ,'small':0
    ,'rel':''
    ,'element':null
  }
  
  , Implements : [Options]
  
  , initialize : function(options) {
  
    this.setOptions(options);
    
    if(this.options.id=='')
      this.options.id = 'ek-button-'+UniqueID(); // ?? ek-radio ...
    
    if(this.options.name=='')
      this.options.name = this.options.id; // ?? ek-radio ...

    el = this.create();

    return el.retrieve('widget');
    
  }
  
  , create : function() {
  
    if(this.options.theme=='color') {
      var theme =  'ek-button-color';
      
      if(this.options.color!='') {
        theme += (this.options.small==1) ? ' ek-button-color-' + this.options.color + '-small' :  ' ek-button-color-' + this.options.color;
      } else {
        theme += (this.options.small==1) ? ' ek-button-color-small' : ' ek-button-color';
      }
      
    } else {
      var theme = 'ek-button-' + this.options.theme;
    }
    
    if(this.options.bold == 1)
      this.options.style += ';font-weight:bold';
    
    if(this.options.href=='')
      this.options.href = "javascript:void(0);";
    
    var iconStyle = '';
    
    var iconStyle = null;
    if(this.options.icon != '') {
      if(this.options.value == '') {
        iconStyle = {
            'background': 'url(' + this.options.icon + ') no-repeat'
          , 'height': '21px'
          , 'float': 'left'
          , 'margin-top': '2px'
          , 'padding-left': this.options.small==1?'10px':'13px'
        }
      } else {
        iconStyle = {
            'background': 'url(' + this.options.icon + ') no-repeat'
          , 'height': '17px'
          , 'float': 'left'
          , 'margin-top': '2px'
          , 'padding-left': this.options.small==1?'13px':'19px'
        }
      }
      
    }
        
    var div = new Element('div', {
      'class':'ek-button ' + theme + ' ' + this.options['class'],
      'id':this.options.id,
      'name':this.options.name,
      'style':this.options.style
    });
    
    var a = new Element('a', {
       'href':this.options.href
      ,'class':'ek-button-link'
      ,'alt':this.options.alt
      ,'title':this.options.alt
      ,'rel': this.options.rel
    });
    
    var spanLeft = new Element('span', {'class':'left'});
    spanLeft.adopt( new Element('img', {'src':wwwroot+'/media/system/img/spacer.gif'}) );
    
    var spanCenter = new Element('span', {'class':'center', 'html':this.options.value.trim()});
    
    if(iconStyle != null) {
      var spanIcon = new Element('span', {'html':'&nbsp;'});
      spanIcon.setStyles(iconStyle);
      spanIcon.inject(spanCenter, 'top');
    }
    
    var spanRight = new Element('span', {'class':'right'});
    spanRight.adopt( new Element('img', {'src':wwwroot+'/media/system/img/spacer.gif'}) );
    
    a.adopt(spanLeft);
    a.adopt(spanCenter);
    a.adopt(spanRight);
    div.adopt(a);
    
    Widgets.addObject(new Widget({ type:'button', element:div , id:this.options.id , name:this.options.name}), div);
    
    this.element = div;
    
    return div;
    
  }
  
});

// ---------------------------------------------------------------------------------------------------
   
Widget.help = new Class({
  
  options : {
      'title':'Aucun titre'
    , 'text':''
    , 'id':''
    , 'style':''
    , 'element' : null
  }
  
  , Implements : [Options]
  
  , initialize : function(options) {
    this.setOptions(options);
    
    if(this.options.id=='')
      this.options.id = 'ek-help-'+UniqueID();
    
    //return this.create();
    
    el = this.create();

    return el.retrieve('widget');
    
  }
  
  , create : function() {
    
    var div = new Element('div', {'class':'ek-help', 'style': 'float:left;'+this.options.style});
    
    var div_a = new Element('a', {
        'href': 'javascript:void(0)'
      , 'rel': "<div style='font-size:14px;'>Aide : "+this.options.title+"</div>"+this.options.text
      , 'class': 'ek-tips'
    });
    
    div_a.adopt( new Element('img', {
        'src': wwwroot+'/media/system/img/admin/help.png'
      , 'style': 'border: 0;'
    }) );
    
    div.adopt(div_a);
    
    
    
    Widgets.addObject(new Widget({ type:'help', title:this.options.title, text:this.options.text, element:div , id:this.options.id}), div);
    
    this.element = div;
    
    return div;
    
  }
  
});


// ---------------------------------------------------------------------------------------------------

var FileChooser = new Class({
  
  
  options : {
    type : 'filechooser'
   ,element : null
   ,id : UniqueID()
   ,name : UniqueID()
   ,defaultValue : null
   ,single : 0
  }
  
  // ------
  
  , Implements : [Options]
  
  , Extends : Widget
  
  // ------
  
  , initialize : function(options) {
  
    this.setOptions(options);
    
  }
  
  // ------
  
  , listDirId : {}
  , values : []
  , valueChanged : false
  
  // ------
  
  ,eventListener : new Events()
 
  ,addEvent : function(name, func) {
    
    this.eventListener.addEvent(name,func);

    return this;
    
  }	
  
  ,resetEvents : function() {
  
    this.eventListener.$events = {};
    this.link.$events = {};
    
    return this;
  
  }
  
  ,fireEvent : function(name, bind) {
 
    this.eventListener.fireEvent(name,bind);

  }
  
  // ------
  
  , prepare : function(){

      this.span = this.getElement();
      this.link = this.span.getElements('a')[0];

      this.link.addEvent('mouseup', this.choose.bind(this));
      
  }
  
  ,choose : function() {
      
      var span = this.span;
      var link = this.link;
      
      if($('ek-file-chooser'))
        $('ek-file-chooser').destroy();
      
        this.libid = link.getProperty('rel').split('-')[0].toInt();
        this.single = (link.getProperty('rel').split('-')[1].toInt() == 1) ? true : false;
        
        if($('mask-file-chooser') == null) {
          
          $(document.body).adopt(new Element('div', {id: 'mask-file-chooser'}));
          
          $('mask-file-chooser').setStyle('z-index', 310000); //99);
          $('mask-file-chooser').addClass('mask');
          
        } else {
        
          $('mask-file-chooser').removeClass('disabled');
          
        }
          
        // Affichage de la fenêtre principale
        if($('ek-file-chooser') == null) {
        
           var divFC = new Element('div', {'id':'ek-file-chooser', 'class' : 'elastic'});
           
           var title = new Element('h2', {
             'class':'title'
            ,'html': '<a href="javascript:void(0)" title="'+$L.common.close+'" class="close">'+$L.common.close+'</a>'+$L.backoffice.filechooser.title
           });

           divFC.adopt(title);
           
           this.divArbo = new Element('div', {'class':'arbo'});
           divFC.adopt(this.divArbo);
           
           this.divContenu = new Element('div', {'class':'contenu'});
           divFC.adopt(this.divContenu);
  
           var divB = new Element('div' , {'class':'bottom'});
           divB.adopt(new Element('div', {'class':'finfos', 'html': '<div id="file-chooser-icon"></div><div id="file-chooser-infos"></div>' }))
           divB.adopt(new Element('a', {'href':'javascript:void(0)', 'class':'alert-button', 'name':'chooser-select-all-files', 'html':'Tout sélectionner' }))
           divB.adopt(new Element('a', {'href':'javascript:void(0)', 'class':'alert-button', 'name':'chooser-ok', 'html':$L.common.validate }))
           divB.adopt(new Element('a', {'href':'javascript:void(0)', 'class':'alert-button', 'name':'chooser-cancel', 'html':$L.common.cancel }))
           divFC.adopt(divB);
           
           divFC.inject($('mask-file-chooser'));

        } else {
        
          $('ek-file-chooser').removeClass('disabled');
          this.divArbo = $('ek-file-chooser').getElement('div.arbo');
          this.divContenu = $('ek-file-chooser').getElement('div.contenu');
          
        }
            
        // ---
        
        btn = $$('div#ek-file-chooser a[name=chooser-select-all-files]')[0];     
        btn.removeEvents(['mouseup']).addEvent('mouseup', this.chooserCheckAllFiles.bind(this));
            
        // ---
        
        btn = $$('div#ek-file-chooser a[name=chooser-cancel]')[0];     
        btn.removeEvents(['mouseup']).addEvent('mouseup', this.chooserCancel.bind(this));
        
        // ---
        
        btn = $$('div#ek-file-chooser a[name=chooser-ok]')[0];
        btn.removeEvents(['mouseup']).addEvent('mouseup', this.chooserValidate.bind(this));
        
        // ---
        
        $$('div#ek-file-chooser div.contenu')[0].setStyles({
          height: document.getSize().y-350
        });
 
        // ---
        
        // Affichage du masque
        $('mask-file-chooser').removeClass('disabled');
        $(document).addEvent('scroll', function(){
         
          var top = document.getScroll().y;
            $('mask-file-chooser').setStyle('top', top.toInt());
          
          $('mask-file-chooser').setStyle('height', $(document).getSize().y);
        });
       
        $(document).fireEvent('scroll');
        
        this.fireEvent('choosing');
        
        // Récupération des données pour le répertoire racine
        this.getData(0);
        
  }
  
  // ------
  
  , getData : function(dirid) {
      
      if(typeof dirid != "number") {
        dirid = 0;
      }
      
      var remote = new Remote({
        name : 'filelibrary'
        , command : 'makeChooserHTML'
        , params : {'catid' : this.libid, 'dirid':dirid , 'single':(this.single?1:0) }
      });
      
      remote.addEvent('complete', function(r){
        
        switch(r.response.code){
        
          case 1:
            this.divContenu.set('html', r.response.data);
            Widgets.scan.bind(Widgets)();
            
            this.getInfoDir(dirid);
            
            //*
            if($W('files')!= null) {
              $W('files').addEvent('change', function(e){
                this.valueChanged = true;
              }.bind(this))
            }
            //*/
            
            this.divContenu.getElements('div.dir').addEvent('mouseup', function(e) {
              
              var rel = e.target.getProperty('rel');
              
              var dirid = rel.split('-')[1];
              
              this.getData.bind(this)(dirid.toInt());
              
            }.bind(this));
            
          break;
        
        }
        
      }.bind(this));
      
      remote.addEvent('error', function(){
        new BackOffice.Alert().error($L.backoffice.internetError,$L.backoffice.internetComError);
      }.bind(this));
  
      
      remote.call();
  }
  
  // ------
  
  , getInfoDir: function(dirid) {
      
      
      if(dirid == 0) {
        this.divArbo.set('html', '');
        this.divArbo.addClass('disabled');
        return;
      }
      
      if(typeof this.listDirId[dirid] == "undefined") {
        
        var remote = new Remote({
          name : 'filelibrary'
          , command : 'getDirInfo'
          , params : {'dirid':dirid }
        });
        
        
        remote.addEvent('complete', function(r){
          
          switch(r.response.code){
          
            case 1:
              this.listDirId[dirid] = r.response.data;
              this.setArbo(dirid);
            break;
            
            case 2 :
              new BackOffice.Alert().error($L.common.forbidden, $L.common.levelError);
            break;
            
            case 3:
              new BackOffice.Alert().error($L.backoffice.filechooser.infoDir, $L.common.unknowError);
            break;
          
          }
          
        }.bind(this));
        
        
        remote.addEvent('error', function(){
          new BackOffice.Alert().error($L.backoffice.internetError,$L.backoffice.internetComError);
        }.bind(this));
    
        
        remote.call();
        
      } else 
        this.setArbo(dirid);
    
  }
  
  // ------
  
  , setArbo : function(dirid) {
      
    if(typeof this.listDirId[dirid] == "undefined")
      return false;
    else {
      
      var html = '<img src="'+wwwroot+'/'+system.iconPath+'/arrow_medium_left.png" alt="" />';
      html += this.getArbo(dirid);
      
      this.divArbo.set('html', html);
      this.divArbo.removeClass('disabled');
      
      if(this.divArbo.getElement('img') != null) {
        this.divArbo.getElement('img').addEvent('mouseup', function() {
        
          this.getData.bind(this)(this.listDirId[dirid].parent.toInt());
          
        }.bind(this));
      }
      
    }
  }
  
  // ------
  
  , getArbo : function(dirid) {
     
     if(typeof this.listDirId[dirid] != "undefined") {
       
       if(this.listDirId[dirid].parent!=0)
         return this.getArbo(this.listDirId[dirid].parent)+' / '+this.listDirId[dirid].dirname;
       else
         return this.listDirId[dirid].dirname;
         
     } else {
      return false;
     }
  }
  
  // ------
  
  , close : function() {
    this.divContenu.set('html', '');
    this.divArbo.set('html', '');
    $('mask-file-chooser').addClass('disabled');
    $('ek-file-chooser').addClass('disabled');
    //this.resetEvents();
  }
  
  // ------
    
  ,resetEvents : function() {
  
     this.$events = {};
     this.eventListener.$events = {};
     
  }
   
  // ------
  
  , chooserCancel : function(){ 
    this.fireEvent('cancel');
    this.close();
  }
  
  // ------
  
  , chooserValidate : function(){
    this.fireEvent('choosed', [this.getValues()]);
    this.close();
  }
  
  // ------
  
  , chooserCheckAllFiles : function() {
  
    $W('files').checkAll();
  
  }
  
  // ------
  
  , getValues : function() {
    
    if(this.valueChanged == true) {
      this.values = [];
      
      var values = $W('files').getValues();
      
      var remote = new Remote({
          name : 'filelibrary'
          , async : false
          , command : 'getFilesInfo'
          , params : {'Afid':values }
        });
        
        
        remote.addEvent('complete', function(r){
          
          switch(r.response.code){
          
            case 1:
              this.valueChanged = false;
              this.values = r.response.data;
            break;
            
            case 2 :
              new BackOffice.Alert().error($L.common.forbidden, $L.common.levelError);
            break;
            
            case 3:
              new BackOffice.Alert().error($L.backoffice.filechooser.infoDir, $L.common.unknowError);
            break;
          
          }
          
        }.bind(this));
        
        
        remote.addEvent('error', function(){
          new BackOffice.Alert().error($L.backoffice.internetError,$L.backoffice.internetComError);
        }.bind(this));
    
        
        remote.call();
      
    }
    
    return this.values;
  }
  
});

// ---------------------------------------------------------------------------------------------------

FileChooser.ShowInfo = function(filename, upname, ext, filesize) {

  $('file-chooser-icon').set('html', '<img src="'+wwwroot+'/temp/uploads/'+upname+'" style="max-width:70px;max-height:70px;" />');
  $('file-chooser-infos').set('html', '<b>'+filename+'</b>');
  
}

// ---------------------------------------------------------------------------------------------------

var Widgets = {

   getAll : function() {
     var listWidgets = $$('.ek-widget'); 
     var instancesWidgets = [];
     if(listWidgets.length>0) {
       listWidgets.each(function(el){
         instancesWidgets.push(el.retrieve('widget'));
       });
     }
     return instancesWidgets;
   }

  ,$ : function(id,value) {
    l = this.getAll();
    if(l.length>0) {
      //var el = [];
      var el = null;
      l.each(function(w){
        if(w != null) {
          if(w.options.id == id || w.options.name == id) {
            //el.push( w );W(value);
            if(value != null) {
              if(value == w.value) {
                el = w;
              }
            } else el = w;
          }
        }
      });
      if(el!=null) return el; //( el.length>1 ? el : el[0] );
    }
    return null;
  }
  
  ,$$ : function(type) {
    
    list = [];
    
    Widgets.getAll().each(function(widget){
      if(widget.options.type == type) {
        list.push(widget);
      }
    })
    
    return list;
    
  }
  
  ,scan : function() {
  
    // Scan des cases à cocher : ek-checkbox
    $$('span.ek-checkbox').each(function(o){
      this.addObject(new Widget({ type:'checkbox', element:o , id:o.getElement('input').id , name:o.getElement('input').name}), o);
    }.bind(this));
    
    // Scan des cases à choix unique : ek-radio
    $$('span.ek-radio').each(function(o){
      this.addObject(new Widget({ type:'radio', element:o , id:o.getElement('input').id , name:o.getElement('input').name}), o);
    }.bind(this));
    
    // Scan des entrées de texte
    $$('input.ek-input-text, input.ek-input-text-small').each(function(o){
      this.addObject(new Widget({ type:'text', element:o , id:o.id , name:o.name}), o);
    }.bind(this));
    
    // Scan des entrées de mot de passe
    $$('input.ek-input-password').each(function(o){
      this.addObject(new Widget({ type:'password', element:o , id:o.id , name:o.name}), o);
    }.bind(this));
    
    // Scan des entrées de texte multi-lignes
    $$('textarea.ek-textarea').each(function(o){
      this.addObject(new Widget({ type:'textarea', element:o , id:o.id , name:o.name}), o);
    }.bind(this));

    // Scan des boutons
    $$('div.ek-button').each(function(o){
      this.addObject(new Widget({ type:'button', element:o , id:o.id , name:o.getProperty('name')}), o);
    }.bind(this));
    
    // Scan des blocs d'onglets : ek-tab
    $$('div.ek-tab').each(function(o){
      this.addObject(new Widget({ type:'tabs', element:o , id:o.id , name:o.getProperty('name')}), o);
    }.bind(this));
    
    $$('div.ek-chooser').each(function(o){
       this.addObject(new FileChooser({type:'filechooser', element:o, id:o.id, name:o.getProperty('name')}), o);
    }.bind(this));

  }

 ,addObject : function(object, element) { 
     
    if( element.retrieve('widget')==null ) { // this.$(object.options.id)
      
      object.prepare();
      element.addClass('ek-widget').store('widget', object);
      return true;
      
    } else return false;
    
  }

}

// ---------------------------------------------------------------------------------------------------

// Permet à la classe Element de MooTools d'adopter des instances de la classe Widget

Element.prototype.adoptOld = Element.prototype.adopt; 

Element.prototype.adopt = function(el) {

  if(typeof el == 'object' && el.isWidget) {
  
    if(el.getElement)
      this.appendChild(el.getElement());
        
    return this;
  
  } else {
  
    Array.flatten(arguments).each(function(element){
		element = document.id(element, true);
		if (element) this.appendChild(element);
	}, this);
	return this;
  
  }
  
}//.bind(Element);

// ---------------------------------------------------------------------------------------------------

var $W = Widgets.$.bind(Widgets);

// ---------------------------------------------------------------------------------------------------

window.addEvent('domready', function() {
 
  Widgets.scan.bind(Widgets)(); 
  
});
