/**
 * Extension du prototype
 */

(function() {
	
	// Bind : exécute une fonction dans le contexte "that"
	Function.prototype.bind = function(that) {
		var fn = this ;
		return function() {
			fn.apply(that, arguments) ;
		} ;
	} ;
	
	// Temporise l'exécution d'une fonction : si la fonction est appelée
	// plusieurs fois, les appels PRÉCÉDENTS sont annulés
	Function.prototype.bufferLast = function(delay) {
		var fn = this ;
		return function() {
			clearTimeout(fn.timeout) ;
			fn.timeout = setTimeout(fn.bind(this), delay) ;
		} ;
	} ;
	
	// Temporise l'exécution d'une fonction : si la fonction est appelée
	// plusieurs fois, les appels SUIVANTS sont ignorés
	Function.prototype.bufferFirst = function(delay) {
		var fn = this ;
		return function() {
			if (!fn.timeout) {
				fn.timeout = setTimeout(function() {
					(fn.bind(this))() ;
					fn.timeout = null ;
				}.bind(this), delay) ;
			}
		} ;
	} ;
	
	// Sprintf
	// Example : console.log("hello %s %s times".sprintf('world', 10)) ; // "hello world 10 times"
	String.prototype.sprintf = function() {
		// Next char should not be converted
		var convert = false ;
		
		// Result string
		var res = '' ;
		
		// Cast arguments as array
		args = [] ;
		for (i = 0 ; i < arguments.length ; i++)
			args[i] = arguments[i] ;
		
		// For each char in the current string
		for (i = 0 ; i < this.length ; i++) {
			if (convert) {
				switch(this[i]) {
					case 's' : res = res + args.shift() ; break ;
					default  : res = res + this[i] ; break ;
				}
				convert = false ;
			}
			else if (this[i] == '%')
				convert = true ;
			else
				res = res + this[i] ;
		}
		return res ;
		
	} ;
	
	// Sprintf-like with associative array (json object)
	// Example : console.log("hello {name}".osprintf({name: "francois"})) ; // "hello francois"
	String.prototype.osprintf = function(o) {
		var res = this ;
		for (key in o)
			res = res.replace(new RegExp('\{'+key+'\}'), o[key]) ;
		return res ;
	} ;
	
})() ;

/**
 * Extension du core jQuery
 */

(function($) {
	
	// toggleClass multiple, prévu dans une future version de jQuery
	var originalToggleClass = $.fn.toggleClass ;
	$.fn.toggleClass = function(cls, sw) {
		var args = arguments ;
		$(cls.split(/\s+/)).each(function (index, value) {
			args[0] = value ;
			originalToggleClass.apply(this, args) ;
		}.bind(this)) ;
		return this ;
	} ;
	
})(jQuery) ;

/**
 * Fonctions personnalisées
 */

(function($) {
	$.extend({
		// Accéder à un élément dont l'id est enregistré dans un attribut d'un autre élément
		rand: function() {
			if      (arguments.length == 1) { min = 0            ; max = arguments[0] ; }
			else if (arguments.length == 2) { min = arguments[0] ; max = arguments[1] ; }
			else                            { min = 0            ; max = 1000000000   ; }
			return Math.round(Math.random()*(max - min))+min ;
		}
	}) ;
})(jQuery) ;

/**
 * Méthodes personnalisées
 */

(function($) {
	$.fn.extend({
		// Accéder à un élément dont l'id est enregistré dans un attribut d'un autre élément
		jump: function(attr) {
			return this.map(function() {
				return $('#'+$(this).attr(attr))[0] ;
			}) ;
		}
	}) ;
})(jQuery) ;

/**
 * Initialisations
 */

$(document).ready(function() {
	// <a rel="{toggler:{id:'elem',init:'hide'}, popup:{params:'width=300,height=200'}}">
	$('*[rel][rel!=nofollow]:not(link)').each(function() {
		var data = eval('(' + $(this).attr('rel') + ')') ;
		$.each(data, function(fn, o) {
			if (fn = eval('$.fn.'+fn))
				fn.apply(this, [o]) ;
		}.bind($(this))) ;
	}) ;
	
}) ;
