xhr = [];
Popup = function (url, o) {    
    this.url = url;
    this.inLoading = false;
    
    this.options = $.extend({
    	autoLoad: true,
    	autoOpen: true,
        close: function(){
    		(xhr[url] && xhr[url].abort());    		
	        $(this).closest('.ui-dialog').find('.ui-dialog-content').remove();
	        $(this).dialog('destroy');

	        return false;
    	},
    	format: 'html',
        maxHeight: 500,
        maxWidth: 500,
        method: 'get',
        modal: false,
        params: [],
        resizable: true,
        success : function() {},
    	title: this.url,
    	url: this.url
    }, o || {});

    this.dialog = $('<div/>').dialog(this.options);
	
    (this.options.autoOpen && this.open());
}
Popup.prototype = new Object;
Popup.prototype.open = function() {
	if (this.inLoading) return;
	
	this.dialog.dialog('open');
	this.beginLoading();
	
	(this.options.autoLoad && this.loadData(this.url, this.options.params, this.options.success));
}
Popup.prototype.loadData = function(url, params, success) {
	var oPopup = this; //Requis car dans la méthode de callback, le this devient l'objet ajax... merci jQuery ;)
	
    callbackJSON = function(json, textStatus) {
    	oPopup.endLoading();
    	
    	if (json.errorMessage && json.errorMessage.length) {
            $.Growl.show({
                'title'  : 'Exception PHP',
                'message': json.errorMessage,
                'icon'   : 'clouds',
                'timeout': false
              });
            json.debug += json.errorMessage + '<br /><br />' + json.message;
    	} else if (json.refresh && json.refresh == true) {
    		var title = 'Action terminée';
        	if (json.messageSuccess && json.messageSuccess.length)
        		title = json.messageSuccess[0];
        	if (json.messageFailure && json.messageFailure.length)
        		title = json.messageFailure[0];
        	
        	$('body').block({
        		message: '<h1>'+title+'</h1><p>Rafraichissement de la page en cours...</p>',
        		baseZ: 2000
        	});
            window.location.reload();
            return false;
        } else if (json.url && json.url != null) {
    		var title = 'Action terminée';
        	if (json.messageSuccess && json.messageSuccess.length)
        		title = json.messageSuccess[0];
        	if (json.messageFailure && json.messageFailure.length)
        		title = json.messageFailure[0];
        	
        	$('body').block({
        		message: '<h1>'+title+'</h1><p>Redirection en cours...</p>',
        		baseZ: 2000
        	});
            window.location = json.url;
            return false;
        } else if (json.messageSuccess && json.messageSuccess.length) {
            $.Growl.show({
                'title'  : 'Réussite',
                'message': json.messageSuccess.join('<br />'),
                'icon'   : 'star',
                'timeout': 5000
              });
    	} else if (json.messageFailure && json.messageFailure.length) {
            $.Growl.show({
                'title'  : 'Erreur/Alerte',
                'message': json.messageFailure.join('<br />'),
                'icon'   : 'clouds',
                'timeout': 5000
              });
    	}
    	
    	if (json.closePopup) {
    		return oPopup.dialog.dialog('close');
    	}

        //On supprime éventuellement l'ancien formulaire (ou autre), utile si on charge une seconde fois la même page
        (json.id && oPopup.dialog.find('#'+json.id).remove());        
        
        var oldSize = oPopup.getSize();
        (json.title && oPopup.dialog.data('title.dialog', json.title));
        if (json.buttons) {
        	if (json.buttons.length == 0) {
        		json.buttons = {
        			'Fermer': function() {$(this).dialog('close');}
        		};
        	}
        	
        	oPopup.dialog.data('buttons.dialog', json.buttons);
        }
        if (!json.content) {
        	alert('Aucun contenu renvoyé...');
        	return false;
        }        

        oPopup.dialog.closest('.ui-dialog').find('.ui-dialog-content').html(json.content);
        (json.beforeResize && json.beforeResize());
        
        //TODO: Si la fenêtre a été redimenssionnée par l'utilisateur, elle ne devrait plus être redimensionnée automatiquement lors d'un prochain chargement
        var newSize = oPopup.resize(oldSize, json.script);
        
        oPopup.dialog.dialog('moveToTop');

        //TODO: Que l'ajaxForm retourne l'objet xhr afin de pouvoir annuler la requête en cours de route
        $('#'+json.id).ajaxForm({
            dataType: "json",
            beforeSubmit: function(data, form, o) {
            	o.url += '/format/json';
        		oPopup.beginLoading();
            },
            success: callback
        });

        if (json.debug) {
            if($('#debug').length == 0) {
                $(json.debug).appendTo('#main');
            }
            $('#debug').replaceWith(json.debug);
            $('#debug').hide().fadeIn('slow');
        }
        
        (success && success(oPopup));
    }
    
    callbackHTML = function(html, status) {
    	oPopup.endLoading();
    	
        var oldSize = oPopup.getSize();        
        oPopup.dialog.closest('.ui-dialog').find('.ui-dialog-content').html(html);
        var newSize = oPopup.resize(oldSize);
        oPopup.dialog.dialog('moveToTop');
        
        (oPopup.options.title && oPopup.dialog.data('title.dialog', oPopup.options.title));
        
        (success && success(oPopup));
    }
    
    switch (this.options.format) {
    	case 'json' : var callback = callbackJSON; break;
    	case 'html' : var callback = callbackHTML; break;
    	default: alert('Méthode de callback pour "' + this.options.format +'" non définie'); return false;
    }

    var data = $.extend({
    	format: this.options.format
    }, this.options.data || {});
    data = $.extend(data, params || {});

    if (this.options.method == 'get')
    	xhr[url] = $.get(url, data, callback, this.options.format);   
    else
    	xhr[url] = $.post(url, data, callback, this.options.format);    
}
Popup.prototype.beginLoading = function() {
	//if(this.inLoading) return;
	this.inLoading = true;
    this.dialog.dialog('option', 'title', 'Chargement...');
    //this.dialog.dialog('option', 'resizable', false);
    this.dialog.closest('.ui-dialog').block({
    	//FIXME: Ajouter baseurl au chemin de l'image
        message: '<img class="loading" src="/skins/default/img/loading.gif" alt="Chargement..." />',
        css: {
    		border: 'none',
    		background: 'none'
    	}
    });        	
}
Popup.prototype.endLoading = function(json) {
	this.inLoading = false;
    this.dialog.dialog('option', 'resizable', this.options.resizable);
    this.dialog.closest('.ui-dialog').unblock();
}
Popup.prototype.getSize = function() {
	return {
		height: this.dialog.closest('.ui-dialog').height(),
		width: this.dialog.closest('.ui-dialog').width()
	};
}
Popup.prototype.resize = function(origin, script) {
	var origin = $.extend({
		height: this.dialog.dialog('option', 'height'),
		width: this.dialog.dialog('option', 'width')
	}, origin || {});
	
	var target = {};
	
	(this.options.beforeResize && this.options.beforeResize());

	this.dialog.closest('.ui-dialog')
	     .find('.ui-dialog-content').css({
	    	 minHeight: 0
	     }); //Corrige un bug avec les boutons lors d'un redimenssionnement de la popup

    this.dialog.closest('.ui-dialog').find('.ui-dialog-content').height('auto');
    this.dialog.closest('.ui-dialog').find('.ui-dialog-content').width('auto');
    this.dialog.data('height.dialog', 'auto');
    this.dialog.data('width.dialog', 'auto');
	
	var html = this.dialog.closest('.ui-dialog').find('.ui-dialog-content').html();
	this.dialog.closest('.ui-dialog').find('.ui-dialog-content').show().html('');
	target.uiHeight = this.dialog.closest('.ui-dialog').height();
	this.dialog.closest('.ui-dialog').find('.ui-dialog-content').html(html);

	if (this.dialog.closest('.ui-dialog').width() > this.dialog.dialog('option', 'maxWidth')) {
	    this.dialog.data('width.dialog', this.dialog.dialog('option', 'maxWidth'));
	}
	
    target.height = Math.max(
    	this.dialog.dialog('option', 'minHeight'),
        Math.min(
        	this.dialog.closest('.ui-dialog').height(),
        	this.dialog.dialog('option', 'maxHeight')
    	)
	);
    target.width = Math.max(
    	this.dialog.dialog('option', 'minWidth'),
    	Math.min(
    		this.dialog.closest('.ui-dialog').width(),
    		this.dialog.dialog('option', 'maxWidth')
    	)
    );
    
	this.dialog.closest('.ui-dialog').find('.ui-dialog-content').hide();
    
	this.dialog.data('width.dialog', origin.width);
	this.dialog.data('height.dialog', origin.height);
	this.dialog.closest('.ui-dialog')
    	 .animate({
    		 width: target.width + 1,
    		 height: target.height,
    		 //Animation vers le centre de l'écran
    		 left: $(window).width()/2 - target.width/2,
    		 top: $(window).height()/2 - target.height/2
    	 },{
    		 duration:400
    	 });
	this.dialog.closest('.ui-dialog').find('.ui-dialog-content').fadeIn('slow');

	var oPopup = this;
	oPopup.dialog.closest('.ui-dialog').queue(function() {
		oPopup.dialog.data('height.dialog', target.height); 
		oPopup.dialog.closest('.ui-dialog').find('.ui-dialog-content').height(target.height - target.uiHeight);
	 	
	 	//L'éventuel script est déclenché tard pour éviter quelques bugs d'affichage lors du redimensionnement
	 	//Cependant, la taille calculé n'est peut-être pas très correcte si le script modifiait l'interface...
        (script && script());

        $(this).dequeue();
	});
	
	/*
	 * FIXME: Taille après un drag de la popup
	 * Exemple pour recréer le bug :
	 * - Charger une popup
	 * - Aggrandir sa taille (surtout sa hauteur)
	 * - Recharger la popup sans la fermer avec un contenu plus petit qu'actuellement
	 * - Une fois chargée, la déplacer
	 * - PAF, sa hauteur redevient comme avant le second chargement
	 */ 
    
	return target;
}

$.fn.popup = function(o) {
	o = $.extend({
		beforeOpen: function(url, o) { return true; },
		event: 'click',
		format: 'html',
		buttons: {'Fermer': function(){$(this).dialog("close");}},
		multiple: false
	}, o || {});
	
	$(this).live(o.event, function(){		
		if (!o.multiple && typeof(popupForms) == 'undefined') popupForms = [];

		if ($(this).attr('title') != 'undefined')
			o.title = $(this).attr('title');
		//FIXME: Même si htmlentitified par PHP, les balises dans title sont exécutées...
		
		var url = $(this).attr('href');

		if (typeof(o.beforeOpen) == 'function') {
			if (!o.beforeOpen(url, o)) {
				return false;
			}
		}
		
		if (o.multiple) {
			popup = new Popup(url, o);
		} else {
			//TODO: Créer des "catégories" de popup, que ce ne soit pas uniquement basé sur l'url (exemple afficher un seul profil à la fois alors que la page cotient plusieurs liens différents vers plusieurs profils)
			if (typeof(popupForms[url]) == 'undefined') {
				o.beforeclose = function(event, ui) {
					delete popupForms[url];
				};
				popupForms[url] = new Popup(url, o);
			} else {
				popupForms[url].open();
			}
		}
		
		return false;
	});
};
$.fn.popupForm = function(o) {
	o = $.extend({
		format: 'json'
	}, o || {});
	
	$(this).popup(o);
        
	return false;
};


$.fn.quoteSelection = function(url) {
	//Récupération de la sélection
    var selectionObject;
    var range;
	var quote;

	if (window.getSelection) {
		selectionObject = window.getSelection();
	} else if (document.selection) {
		selectionObject = document.selection.createRange();
		range = selectionObject;
	}
	
    if (selectionObject.getRangeAt) {
        //$(this).alert('Aucun texte n\'est sélectionné');
    	try {
    		range = selectionObject.getRangeAt(0);
    	} catch( e ) {
            $().alert('Aucun texte n\'est sélectionné');
    		return false;
    	}
    } else if (selectionObject.anchorNode){ // Safari!
        range = document.createRange();
        range.setStart(selectionObject.anchorNode,selectionObject.anchorOffset);
        range.setEnd(selectionObject.focusNode,selectionObject.focusOffset);
    }
	
	if (range.commonAncestorContainer) {
		ancestor = range.commonAncestorContainer;
	} else { //IE
		ancestor = range.parentElement();
	}
	
	try {
		quote = (new XMLSerializer()).serializeToString(range.cloneContents());
	} catch (e) { //IE
		quote = range.htmlText;
	}

    if (quote == '') {
    	$().alert('Aucun texte n\'est sélectionné');
        return false;
    }

    //Récupération de l'identifiant du message cité
    var params = url.split('/');
    var idx;
    $.each(params, function(i, v){
        if (v == 'id') {
            idx = i + 1;
            return false;
        }
    });

    //On vérifie que la sélection est contenue dans le message cité.
    var mId = 'content-' + params[idx];
    var valid = ($(ancestor).attr('id') == mId);
    if (!valid) {
        $(ancestor).parents().each(function(i){
            if ($(this).attr('id') == mId) {
                valid = true;
            }
        });
    }

    if (!valid) {
    	$().alert('Vous ne pouvez pas sélectionner de texte hors du message cité.');
        return false;
    }

    return quote;
}

/*
 * Fonction pour afficher un message de confirmation avant de suivre le lien
 */
$.fn.alert = function(message, callback) {
	o = $.extend({
		dialogClass: 'ui-dialog-alert',
        draggable: false,
        maxWidth: 500,
        message: message,
        modal: true,
        resizable: true,
        zIndex: 10000,
        title: 'Alerte',
        close: function(){
            $(this).closest('.ui-dialog').find('.ui-dialog-content').remove();
            $(this).dialog('destroy');
            return false;
        },
        buttons: {
        	Ok: function() {
        		(callback && callback()); 
        		div.dialog('destroy');
        	}
        }
    }, {});

    div = $('<div />').dialog(o)
	    .closest('.ui-dialog')
		.find('.ui-dialog-content').hide().fadeIn('slow')
		.html(o.message);
    div.dialog('option', 'position', div.dialog('option', 'position'));
    div.dialog('moveToTop');
    
    return div;
};
$.fn.confirm = function(o) {    
	$(this).live('click', function(){	    
	    confirmation(o, $(this));
	    
	    return false;
	});
	
	return $(this);
};

var confirmation = function(o, link) {
    var o = $.extend({
        autoOpen: true,
        bgiframe: true,
        cancelled: function() { return false; },
        completed: function() { },
        confirmed: function(link) {
        	if (link)
        		window.location = link.attr('href');
    		return true;
    	},
		dialogClass: 'ui-dialog-confirm',
        draggable: false,
        maxWidth: 500,
        message: "'Confirmer l\\'action ?'",
        modal: true,
        resizable: true,
        zIndex: 10000,
        title: 'Confirmation',
        close: function(){
            $(this).closest('.ui-dialog').find('.ui-dialog-content').remove();
            $(this).dialog('destroy');
            return false;
        },
        buttons: {
        	Valider: function() {
        		$(this).dialog('close');
        		o.confirmed(link);
        		o.completed(link);
        	},
        	Annuler : function() {
        		$(this).dialog('close');
        		o.cancelled(link);
        		o.completed(link);
        	}
        }
    }, o || {});
    
    if (typeof(popupDialog) != 'undefined')
    	popupDialog.dialog('close');
    
    popupDialog = $('<div />');
    popupDialog.dialog(o);
    popupDialog.closest('.ui-dialog')
    	.find('.ui-dialog-content').hide().fadeIn('slow')
    	.html(eval(o.message));
    popupDialog.dialog('option', 'resizable', false);
    popupDialog.dialog('option', 'position', popupDialog.dialog('option', 'position'));
    popupDialog.dialog('moveToTop');
};

var messageHandling = function(json) {
    if (json.errorMessage && json.errorMessage.length) {
        $.Growl.show({
          'title'  : 'Exception PHP',
          'message': json.errorMessage,
          'icon'   : 'parachute',
          'timeout': false
        });

        json.debug += json.errorMessage + '<br /><br />' + json.message;
    }
    if (json.messageSuccess && json.messageSuccess.length) {
        $.Growl.show({
          'title'  : 'Réussite',
          'message': json.messageSuccess.join('<br />'),
          'icon'   : 'star',
          'timeout': 5000
        });
    }
    if (json.messageFailure && json.messageFailure.length) {
        $.Growl.show({
          'title'  : 'Erreur/Alerte',
          'message': json.messageFailure.join('<br />'),
          'icon'   : 'clouds',
          'timeout': 5000
        });
    }

};

var displayDebug = function(json) {
    if (json.debug) {
        if($('#debug').length == 0) {
            $(json.debug).appendTo('#main');
        }
        $('#debug').replaceWith(json.debug);
        $('#debug').hide().fadeIn('slow');
    }
};

var reloadOrRedirect = function(json) {
	var title = 'Action terminée';
	
	if (json.refresh && json.refresh == true) {        	
    	$('body').block({
    		message: '<p>Rafraichissement de la page en cours...</p>',
    		baseZ: 2000
    	});
        window.location.reload();
        
        return false;
    } else if (json.url && json.url != null) {        	
    	$('body').block({
    		message: '<p>Redirection en cours...</p>',
    		baseZ: 2000
    	});
        window.location = json.url;
        
        return false;
    }
}

$(function(){
    $('#spaces-list div').hover(
	    function(){ $(this).removeClass('ui-state-default').addClass('ui-state-focus'); },
	    function(){ $(this).removeClass('ui-state-focus').addClass('ui-state-default'); }
    );

	$(".popup").popup();
	$(".popup-profile").popup({
		maxWidth: 700,
		buttons:{
			'Fermer': function(){$(this).dialog('close');},
			'Profil complet' : function(a) {
				window.location = $(this).dialog('option', 'url');
			}
		}
	});
	$(".popup-form").popupForm();
	$('a.link-chat').click(function(){
		window.open($(this).attr('href'), 'salon_' + labelSalon.replace('-','_'), 'toolbar=no, location=yes, directories=no, status=no, menubar=no, scrollbars=yes, resizable=yes, width=800, height=650');
		return false;
	});
	
	if (isConnected) {
		var timeoutIsLaunched = false;
		var test = function() {
			timeoutIsLaunched = true;
			var countdown = 15;
			
			var popup = $().alert('<h2>Inactivité trop importante !</h2>Veuillez confirmer votre présence en cliquant sur "OK" ou vous serez déconnecté de la plateforme.', function() {
		        clearInterval(interval);
		        resetGlobalTimeout();
		        timeoutIsLaunched = false;
			});
			
			var interval = setInterval(function() {			
				var buttons = popup.dialog('option', 'buttons');
				var text = '';
				for(a in buttons) {
					var label = 'OK ('+(countdown--)+')';					
					buttons[label] = buttons[a];
					delete buttons[a];
				}
				
				if (countdown == 0) {
			        clearInterval(interval);
					window.location = urlLogout;
				}	
				
				popup.dialog('option', 'buttons', buttons);

			}, 1000);
		};

		var globalTimeout = setTimeout(test, 7200000); //2h
		var resetGlobalTimeout = function() {
	        clearTimeout(globalTimeout);
	        globalTimeout = setTimeout(test, 7200000);		
		};
		
		$(document).click(function(){
			!timeoutIsLaunched && resetGlobalTimeout();
			return true;
		});
	} else {
		var loadForm = function(form) {
			var form = $(form).ajaxForm({
	            dataType: 'json',
	            beforeSubmit: function(data, form, o) {
	                o.url += '/format/json';
	                $('#submit1', form)
	                    .attr('disabled','disabled')
	                    .hide()
	                    .before($(iconLoading));
	            },
	            success: function(json, textStatus, form) {
	                messageHandling(json);
	                displayDebug(json);
	
	                if (json.form) {
	                    var form = loadForm(json.form);
	                    
	                    $('#form-login-container').empty().html(form);
	                    
	                    return false;
	                }
	                
	                reloadOrRedirect(json);
	
	                return false;
	            }
	        });

            $('#cancel', form)
            	.unbind('submit.form-plugin')
            	.unbind('click.form-plugin')
            	.click(function(){
					$('#form-login-container').hide();
					return false;
				});
			
			return form;
		};		
		
		loadForm($('#form-login'));
		
		$('#link-login').click(function() {
			$('#form-login-container').toggle();            
			$('#form-login').find(':input:first').focus();
            
			return false;
		});
	}
});

(function($) {
    var current;
    var currentClone;
    var currentContainerId;
    var loadTabulateFormParams = {};
    var loadTabulateFormForceReload = false;
    var baseZindex = 100;
    
	//all hover and click logic for buttons	
	$(".gp-button:not(.ui-state-disabled)")
	.live('mouseover', function(){
		$(this).addClass("ui-state-hover"); 
	})
	.live('mouseout', function(){ 		
		$(this).removeClass("ui-state-hover"); 
	})
	.live('mousedown', function(){
		$(this).addClass("ui-state-active");
	})
	.live('mouseup', function(){
		$(this).removeClass("ui-state-active");
	});
	
	$(".list-link > li:not(.ui-state-disabled)," +
	  ".ui-action-link:not(.ui-state-disabled)")	
	.live('mouseover', function(){
		$(this).addClass("ui-state-hover"); 
		
    	var container = $('#'+currentContainerId);
		if (container.is(':visible')) return;
	
		$(this).addClass("hover"); 
	})
	.live('mouseout', function(){ 
		$(this).removeClass("ui-state-hover"); 
		
    	var container = $('#'+currentContainerId);
		if (container.is(':visible')) return;
		
		$(this).removeClass("hover"); 
	});
	
	var selectUserAndGroupLoading = false;
	var selectUserAndGroupContainer;
	
	$.fn.selectUserAndGroup = function(o) {
		o = $.extend({ modal: true, displayButton: true }, o || {});		
		
		this.attr('readonly', 'readonly');
		
		$('#receivers').attr('name', 'receiverTexts');
		$('#receiverTexts').attr('name', 'receivers');
		
		var tmp = $('#receivers').val();
		$('#receivers').val($('#receiverTexts').val());
		$('#receiverTexts').val(tmp);

		if (!o.displayButton) return false;
		
		var button = $('<button type="button" class="ui-icon ui-icon-plus"></button>')
			.html('Sélectionner');		
		this.after(button);
		var buttonClear = $('<button type="button" class="ui-icon ui-icon-trash"></button>');
		button.after(buttonClear);

		receivers = new Array();
		receiverTexts = new Array();
		
		//Si le champ est prérempli, copier son contenu et afficher le texte
		var _generateSelect = function(json){
			var select = $('<select id="gids"/>');
	        var optgroupGi = $('<optgroup/>')
	        	.attr('label', 'Groupe institutionnel')
	        	.appendTo(select);
	        var optgroupGt = $('<optgroup/>')
	        	.attr('label', 'Groupe de travail')
	        	.appendTo(optgroupGt);

	        for(i in json.groups) {
	            var option = $('<option/>').val(i).text(json.groups[i].name);

	            json.groups[i].type == 'gi' ?
	                option.appendTo(optgroupGi):
	                option.appendTo(optgroupGt);
	        }
	        
	        $('<option value="0" selected="selected">').text('Tous les membres de la session').appendTo(select);
	        
	        $(optgroupGi).length && $(optgroupGi).appendTo(select);
	        $(optgroupGt).length && $(optgroupGt).appendTo(select);
	        
	        return select;
		};
		
		var _generateUserList = function(users, selected) {
	        var ul = $('<ul id="uids">')
	        	.css({margin: 0, maxHeight : '350px', overflow : 'auto'});
			
			if (selected == undefined) {
		        for(i in users) {
		        	$('<li/>')
		        		.append($('<input type="checkbox" name="uids[]" />').attr('id', 'uid' + i).val(i))
		        		.append($('<label/>').text(users[i]).attr('for', 'uid' + i))
		        		.appendTo(ul);
		        }
		        
		        return ul;
			}
			
            for(i in selected) {
	        	$('<li/>')
	        		.append($('<input type="checkbox" name="uids[]" />').attr('id', 'uid' + selected[i]).val(selected[i]))
	        		.append($('<label/>').text(users[selected[i]]).attr('for', 'uid' + selected[i]))
	        		.appendTo(ul);
            }

	        return ul;
		}
		
		buttonClear.click(function(){
			receivers = new Array();
			receiverTexts = new Array();
			
			$('input[name=receivers]').val('');
			$('input[name=receiverTexts]').val('');
		});
		
		button.click(function(){
			if (selectUserAndGroupLoading) return;
			
			if (selectUserAndGroupContainer != undefined) {selectUserAndGroupContainer.dialog('open'); return false;}

		    var input = $(this).prev();

		    selectUserAndGroupLoading = true;

		    //FIXME: baseUrl !!!!!!!!!!!
		    $.getJSON(o.url, function(json) {
		        var string = '';

		        selectUserAndGroupContainer = $('<div/>');

		        //Sélection de tous les utilisateurs affichés
		        $('<input/>').attr('type', 'checkbox').click(function() {
		            var checked = $(this).attr('checked');
		            $('#uids input[name=\'uids[]\']').each(function() {
		                $(this).attr('checked', checked);
		            });
		        }).appendTo(selectUserAndGroupContainer);
		        
		        
		        var select = _generateSelect(json)
		            .change(function(event) {
		                $('#uids').remove();

		                if (this.value == 0) {
		                    var ul = _generateUserList(json.users);
		                } else {
		                    var users = false;
		                    
		                    if (json.groups[this.value] == undefined) { 
		                    	alert('Pas de groupe trouvé. Tout afficher');
		                    	return;
		                    }

		                    var ul = _generateUserList(json.users, json.groups[this.value].users);
		                }
                    	$(this).after(ul);
		            })
		            .appendTo(selectUserAndGroupContainer);

		        var ul = _generateUserList(json.users)
	        		.appendTo(selectUserAndGroupContainer);
		        
		        //container.appendTo($('body')).css({zIndex: '9999',position: 'absolute', left: '200px', top: '200px'});
		        selectUserAndGroupContainer.dialog({
		            modal: o.modal,
		            title: 'Sélection des destinataires',
		            width: 450,
		            buttons: {
						'Fermer': function(){$(this).dialog('close');},
		                'Ajouter le groupe': function() {
		        			if (json.groups[$('#gids').val()] == undefined) {
		        				alert('Vous devez sélectionner un groupe avant de pouvoir en ajouter un');
		        				return;
		        			}
		        	
		        			var gid = 'G:' + $('#gids').val();
		        			var inArray = false;
		        			for (i in receivers) {		        				
		        				if (receivers[i] == gid) inArray = true;
		        			}
		        			
		        			if (inArray) return;
		        			
		        			receivers.push(gid);		        			
		        			receiverTexts.push(json.groups[$('#gids').val()].name);
		        			
		        			$('input[name=receivers]').val(receivers.join(','));
		        			$('input[name=receiverTexts]').val(receiverTexts.join(','));
		                },
		                'Ajouter les utilisateurs sélectionnés': function() {
		                	$("input[name=uids[]]:checked").each(function(i){
		                		var uid = $(this).val();
		                		
			        			var inArray = false;
			        			for (i in receivers) {		        				
			        				if (receivers[i] == uid) inArray = true;
			        			}
			        			
			        			if (inArray) return;
		                		
			        			receivers.push(uid);		        			
			        			receiverTexts.push(json.users[uid]);
		                	});
		        			
		        			$('input[name=receivers]').val(receivers.join(','));
		        			$('input[name=receiverTexts]').val(receiverTexts.join(','));
		                }
		            }
		        });

		        selectUserAndGroupLoading = false;
		    });
		    
		    return false;
		});
		
		return this;
	};	
    
	$.fn.extend({

	    /**
	     * Stores the original version of offset(), so that we don't lose it
	     */
	    _offset : $.fn.offset,

	    /**
	     * Set or get the specific left and top position of the matched
	     * elements, relative the the browser window by calling setXY
	     * @param {Object} newOffset
	     */
	    offset : function(newOffset){
	        return !newOffset ? this._offset() : this.each(function(){
	            var el = this;

	            var hide = false;

	            if($(el).css('display')=='none'){
	                hide = true;
	                $(el).show();
	            };

	            var style_pos = $(el).css('position');

	            // default to relative
	            if (style_pos == 'static') {
	                $(el).css('position','relative');
	                style_pos = 'relative';
	            };

	            var offset = $(el).offset();

	            if (offset){
	                var delta = {
	                    left : parseInt($(el).css('left'), 10),
	                    top: parseInt($(el).css('top'), 10)
	                };

	                // in case of 'auto'
	                if (isNaN(delta.left))
	                    delta.left = (style_pos == 'relative') ? 0 : el.offsetLeft;
	                if (isNaN(delta.top))
	                    delta.top = (style_pos == 'relative') ? 0 : el.offsetTop;

	                if (newOffset.left || newOffset.left===0)
	                    $(el).css('left',Math.round(newOffset.left - offset.left + delta.left) + 'px');

	                if (newOffset.top || newOffset.top===0)
	                    $(el).css('top',Math.round(newOffset.top - offset.top + delta.top) + 'px');
	            };
	            if(hide) $(el).hide();
	        });
	    }

	});	

	$.extend({
	    getJSON: function( url, data, callback ) {
	        if ( jQuery.isFunction( data ) ) {
	            callback = data;
	            data = {format: 'json'};
	        }

	        data.format = 'json';

	        var gCallback = function(json) {
	            messageHandling(json);
	            displayDebug(json);

	            callback(json);
	        };

	        return jQuery.get(url, data, gCallback, 'json');
	    },

	    getFormJSON: function( url, data, callbackOnLoad, callbackOnSuccess ) {
	        $.getJSON( url, data, function(json) {
	            var loadForm = function(json) {
	                return $(json.form).ajaxForm({
	                    dataType: 'json',
	                    beforeSubmit: function(data, form, o) {
	                        o.url += '/format/json';
	                        $('#submit1', form)
	                            .attr('disabled','disabled')
	                            .hide()
	                            .before($(iconLoading));
	                    },
	                    success: function(json, textStatus, form) {
	                        messageHandling(json);
	                        displayDebug(json);

	                        if (json.form) {
	                            $('#json-container').empty();

	                            var form = loadForm(json);
		                        
	                            callbackOnLoad(json, form);

	                            return false;
	                        }

	                        $('#submit1', form)
	                            .removeAttr('disabled')
	                            .show()
	                            .prev().remove();
	                        
	                        !json.notClearForm && form.clearForm();

	                        callbackOnSuccess(json, form);
	                        
	                        reloadOrRedirect(json);

	                        return false;
	                    }
	                });
	            };
	            
	            var form = loadForm(json);

	            callbackOnLoad(json, form);
	        });
	    },
	    
	    messageHandling: function(json) {
	        messageHandling(json);
	    },
	    
	    displayDebug: function(json){
	    	displayDebug(json);
	    }
	});	
	
    function setOffset(container, el) {
        //FIXME: Hack temporaire... qui dépend des css actuelle...
        var dTop = container.parent().attr('id') == 'main' ? 22 : 21;
        var newTop  = el.offset().top + dTop;
        var newLeft = el.offset().left;

        if (el.outerWidth() < container.outerWidth()) {
        	tmpLeft = el.offset().left + (el.outerWidth() / 2) - (container.outerWidth() / 2);
        	newLeft = tmpLeft >= 5 ? tmpLeft : 5;
        }        

        if ($('#main').innerWidth() < (newLeft + container.outerWidth())) {
            newLeft = $('#main').innerWidth() - container.outerWidth() - 12;
        }

        container.offset({top: newTop, left: newLeft});
    };

    var activateLink = function(link) {
        link.removeClass('ui-corner-all')
            .addClass('ui-corner-top')
            .addClass('ui-state-active')
            .addClass('active')
            .css('z-index', baseZindex + 1);
        
        return true;
    };

    var desactivateLink = function(link) {
        link.addClass('ui-corner-all')
            .removeClass('ui-corner-top')
            .removeClass('ui-state-active')
    		.removeClass('hover')
            .removeClass('active')
            .css('z-index', baseZindex - 1);
        
        return true;
    };
    
    var focusOnFirstElement = function(form) {
	    form.find(':input:first').focus();
    }
        
    $.fn.loadTabulateFormSetParam = function(params) {
    	loadTabulateFormParams = $.extend({}, params || {});    	
    	loadTabulateFormForceReload = true;
    	
    	return $(this);
    };
    
    $.fn.hideTabulateForm = function() {
    	if (current != null) desactivateLink(current);
    	$('#'+currentContainerId).hide();
    }
    
    $.fn.moveOrHideTabulateForm = function() {
    	if (current == null) return;
    	
    	var container = $('#'+currentContainerId);
    	
    	current.is(':visible') 
    		? setOffset(container, current)
    	    : desactivateLink(current) && container.hide();
    }
    
	$.fn.loadTabulateForm = function(o) {
	    var options = $.extend({
	    	name: 'default',
	    	callbackOnSuccess: function(){},
	    	callbackOnLoad: function(){},
	    	callbackOnChange: function(){},
	    	reloadOnChange: true, //On recharge le formulaire si on change de lien de même nom
	    	cache: true //On ne recharge pas un formulaire déjà chargé
	    }, o || {});
	    
		return $(this).live('click', function() {//name, callbackOnSuccess, callbackOnLoad, callbackOnChange) {
			if ($(this).hasClass('ui-state-disabled')) return false;
		
			var idContainer = (options.cache && options.reloadOnChange) 
				? $(this).attr('href').replace(/\W/g, '')
				: options.name;
				
		    var dialog = $(this).parents('.ui-dialog');
		    if (dialog.length) {
		    	baseZindex = 1100;
		    	dialog.bind('dialogclose', function(event, ui) {
		    		$().hideTabulateForm();
		    	});
		    } else {
		    	baseZindex = 100;
		    }
			
			if (!$('#' + idContainer).length) {
				$('<div id="'+idContainer+'" class="ui-form-popup ui-corner-bottom"></div>')
			        .css('position', 'absolute')
			        .appendTo($('#main'))
			        .hide();
			}
			
			var container = $('#' + idContainer).css('z-index', baseZindex);
			
			if (!current) current = $(this);
            
            var link = $(this);

            if (idContainer == currentContainerId) {
                if (!loadTabulateFormForceReload && currentClone != null && currentClone.attr('href') == $(this).attr('href')) {
                    current = link;	
                    container.toggle();                    
                    container.is(':hidden')
                        ? desactivateLink(current)
                        : activateLink(current) && jQuery.isFunction(options.callbackOnChange) && options.callbackOnChange($(this), container.find('form'));
                        
                    setOffset(container, current);
                	return false;
                }

                container.hide();
                desactivateLink(current);
            } else {
                desactivateLink(current);
                $('#'+currentContainerId).hide();
            }

            activateLink(link);
            
        	options.reloadOnChange;

            if (!container.find('form').length || loadTabulateFormForceReload || (options.reloadOnChange && !options.cache)) {
            	container.empty()
	                .append($(iconLoading).css('margin', '.5em auto').css('display', 'block'))
	                .width($(this).innerWidth());
            }

            setOffset(container, link);               
            
            container.show();

            currentContainerId = idContainer;
            current = link;
            currentClone = link.clone();

            if (container.find('form').length && !loadTabulateFormForceReload && (!options.reloadOnChange || options.cache)) {
            	(!options.cache || (options.cache && !options.reloadOnChange)) && container.find('form').clearForm();

            	focusOnFirstElement(container.find('form'));
            	
                jQuery.isFunction(options.callbackOnChange) && options.callbackOnChange($(this), container.find('form'));
                
            	return false;
            }

            loadTabulateFormForceReload = false;
            
            $.getFormJSON(
                $(this).attr('href'),
                loadTabulateFormParams,
                function(json, form) {
                	if (!json.form) {
                		currentContainerId = null;
	                    desactivateLink(current);
	                    container.hide();
	                    
	                    return false;
                	}

                    $('#cancel, #preview', form)
                    	.unbind('submit.form-plugin')
                    	.unbind('click.form-plugin');
                    	
                    $('#cancel', form).click(function(){
    		    		$().hideTabulateForm();
                    	return false;
                    });

                	container.html(form);
                    container.width('auto');
                    setOffset(container, link);

                	focusOnFirstElement(form);

                    jQuery.isFunction(options.callbackOnLoad) && options.callbackOnLoad(json, form);
                },
                function(json) {
                    desactivateLink(current);
                    container.hide();

                    jQuery.isFunction(options.callbackOnSuccess) && options.callbackOnSuccess(json, current);
                }
            );
            
            return false;
        });
	};
	
	$.fn.loadTabulateStatic = function(name) {
	    var idContainer = name;

		if (!$('#' + idContainer).length) {
			$('<div id="'+idContainer+'" />');
		}

		$('#'+idContainer).css('position', 'absolute')
	        .addClass('ui-state-active')
	        .appendTo($('#main'))
	        .hide();
		
		return $(this).live('click', function() {			
			if (!current) current = $(this);
            
            var link = $(this);

            if (idContainer == currentContainerId) {
                setOffset($('#'+idContainer), link);
                $('#'+idContainer).toggle();
                
                $('#'+idContainer).is(':hidden')
                    ? desactivateLink(current.css('z-index', baseZindex - 1))
                    : activateLink(current);
                
                if (currentClone != null && currentClone.attr('href') == $(this).attr('href')) {
                    setOffset($('#'+idContainer), link);
                	return false;
                }
            } else {
                desactivateLink(current.css('z-index', baseZindex - 1));
                $('#'+currentContainerId).hide();
            }
            
            $('#'+idContainer).width() < $(this).innerWidth() && $('#'+idContainer).width($(this).innerWidth());

            activateLink($(this));
            
            setOffset($('#'+idContainer), $(this));
            setOffset($('#'+idContainer), $(this));  
            
            $('#'+idContainer).show();

            currentContainerId = idContainer;
            current = $(this);
            currentClone = $(this).clone();
            
            return false;
		});		
	};
})(jQuery);