(function(){
	// Si les namespaces/classes nécessaires ne sont pas chargées : exception
	if(!window.ev){throw new Error("Le namespace 'ev' doit exister");}
	
	ev.Classe={
		/**
		 * Méthode permettant de déclarer un héritage de classe.
		 *
		 * NB : la fonction suivante pourrait ne fonctionner que
		 * sur les navigateur récents :
		 *    function extend(_child, _super){
		 *      _child.prototype.__proto__=_super.prototype;
		 *      _child.prototype.__super=_super;
		 *    }
		 *
		 * @see #isInstanceOf(Object, Class)
		 *
		 * @param {Class} _child : classe fille
		 * @param {Class} _super : classe mère de laquelle hérite la classe fille
		 * @throws si _child est null ou non défini
		 * @throws si _super est null ou non défini
		 * @throws si _child n'est pas une classe (pas de prototype)
		 * @throws si _super n'est pas une classe (pas de prototype)
		 */
		extend: function(_child, _super){
			if(!_child){throw new Error("ev.Classe.extend: NullPointerException(_child class cannot be null)");}
			if(!_super){throw new Error("ev.Classe.extend: NullPointerException(_super class cannot be null)");}
			if(!_child.prototype){throw new Error("ev.Classe.extend: Not a class : "+_child);}
			if(!_super.prototype){throw new Error("ev.Classe.extend: Not a class : "+_super);}
	
			// copie de toutes les propriétés de _super vers _child
			// (pour compatibilite anciens navigateurs ne supportant pas l'utilisation de prototype.__proto__)
			for(var property in _super.prototype){
				if(typeof(_child.prototype[property])=='undefined'){
					_child.prototype[property]=_super.prototype[property];
				}
			}
			// transfert du prototype de _super sur la propriété __proto__ du prototype de _child (nouveaux navigateur)
			_child.prototype.__proto__=_super.prototype;
			// stokage de la référence sur la super classe (pour meilleure performance de la méthode #isInstanceOf
			_child.prototype.__super=_super;
			return _child;
		},
	
		/**
		 * Fonction permettant de savoir si un objet (ou une classe) est
		 * une instance d'une classe donnée ou d'une classe dérivée.
		 *
		 * NOTA : une classe peut être considérée comme une instance d'une
		 * de ses super classes.
		 *
		 * La classe de l'objet _child doit être _super ou avoir été étendue de
		 * la classe _super ou d'une de ses classes filles (sinon le résultat
		 * sera 'faux').
	
		 * Toutes les classes de la chaine doivent avoir été étendues via la
		 * méthode extend(). Dans le cas contraire, l'héritage n'est pas
		 * supporté par cette méthode isInstanceOf(). La méthode renverra alors
		 * 'vrai' seulement si _child est une instance directe de la classe
		 * _super.
		 *
		 * @see #extend(Class, Class)
		 *
		 * @param {Object} _child : instance d'un objet de n'importe quelle classe fille de _super (ou une classe fille de _super, ou _super elle-même)
		 * @param {Class} _super : classe mère de laquelle doit hériter la classe fille
		 * @throws si _child est null ou non défini
		 * @throws si _super est null ou non défini
		 * @throws si _super n'est pas une classe (pas de prototype)
		 * @return true si la classe de _child est étendue (directement ou pas) de la classe _super
		 */
		isInstanceOf: function(_child, _super){
		//FIXME rendre ITERATIVE (c'est quand même plus performant)
			if(!_child){throw new Error("ev.Classe.isInstanceOf: NullPointerException(_child class cannot be null)");}
			if(!_super){throw new Error("ev.Classe.isInstanceOf: NullPointerException(_super class cannot be null)");}
			if(!_super.prototype){throw new Error("ev.Classe.isInstanceOf: Not a class : "+_super);}
	
			// si _child n'est pas une classe, c'est une instance d'objet
			if(!_child.prototype){
				// si la classe de _child est _super, on renvoi vrai (si le navigateur supporte l'héritage de classe, l'opérateur 'instanceof' suffira lorsque la réponse est 'vrai')
				if(_child instanceof _super){return true;}
				// sinon, si la classe de _child a une super classe, on teste si cette super classe est _super (ou étendue de _super)
				// Pour cela, il suffit de tester de façon récursive, si cette super classe est une instance de _super
				if(_child.__super){return _child.__super===_super||arguments.callee(_child.__super, _super);}
				// sinon, on renvoie 'faux' (_child n'est pas une instance de _super)
				return false;
			}
	
			// si _child est une classe, on teste si cette classe est _super (ou étendue de _super)
			if(_child===_super){return true;}
			// ... ou, si elle a une super classe étendue de _super
			if(_child.prototype.__super){return _child.prototype.__super===_super||arguments.callee(_child.prototype.__super, _super);}
			// sinon, on retourne 'faux' (_child n'hérite pas de _super)
			return false;
		},
	
		/**
		 * Permet de verifier qu'une classe est définie.
		 *
		 * @param {Class} _className : nom de classe (ou de namespace) à vérifier
		 */
		checkDefined: function(_className){
			if(typeof(log)==='function'){log("ev.Classe.checkDefined: test d'existance de la classe '"+_className+"'", "debug");}
			if(typeof(window[_className])==='function'){return;}
			// si nom complet (avec namespace)
			var names=_className.split(/\./);
			var nameCnt=names.length;
			var lastNamespace=window;
			var i=0;
			while(lastNamespace){
				lastNamespace=lastNamespace[names[i++]];
				if(i>=nameCnt){
					if(typeof(lastNamespace)==='function'){return;}
					break;
				}
			}
			console.error("ev.Classe.checkDefined: la classe "+_className+" n'est pas définie!");
		}
	};
	
	ev.log.debug('ev.Classe ok');
	ev.tools.onFileLoad('ev/Classe.js');
})();