/**
 * Classe de gestion des requêtes : 
 * - Chargement en cours
 * - Événements de requêtes Ajax
 * 
 * @class       Loader
 * @implements  Options
 * @copyright   Copyright (c) 2007-2008 XL Marketing, <http://www.xlmarketing.fr/>
 * @author      Nicolas Sorosac <nicolas.sorosac@xlmarketing.fr>
 */
var Loader = {
	
	Implements: Options,
	
	/**
	 * L'objet de requête Ajax en cours d'utilisation.
	 * @var {Request|null} request
	 */
	request: null,
	
	/**
	 * Indique s'il y a un chargement en cours.
	 * @var {Boolean} loadingExists
	 */
	loadingExists: false,
	
	/**
	 * Indique s'il y a une superposition affichée à l'écran
	 * (assombrissement de l'écran pour l'affichage du chargement).
	 * @var {Boolean} overlayExists
	 */
	overlayExists: false,
	
	/**
	 * Collection d'éléments DOM contenus dans l'indicateur de chargement.
	 * @var {Collection[Elements]} loaderSubElements
	 */
	subElements: {},
	
	/**
	 * Options de base (langue, répertoire, etc.)
	 */
	options: {
		'baseUrl': '',
		'debug':   false,
		'text':    {
			'loading':        "Chargement en cours...",
			'cancelButton':   "Recharger la page",
			'loadingProblem': "La requête ne semble pas aboutir. Vous pouvez annuler l'action en cours et recharger la page en cliquant sur le bouton ci-dessous et essayer à nouveau.",
			'changes':        "Vos modifications seront conservées."
		}
	},
	
	/**
	 * Constructeur de la classe
	 */
	initialize: function(options){
		this.setOptions(options);
		this.text = this.options.text;
		this.initLoading();
		this.makeEvents();
	},
	
	/**
	 * window.onResize
	 */
	onResize: function(){
		if (this.subElements.container)
			this.subElements.container.setStyles({
				'top':  window.getSize().y / 2 - 80,
				'left': window.getSize().x / 2 - 180
			});
	},
	
	/**
	 * window.onScroll
	 */
	onScroll: function(){
        if (Browser.Engine.trident4)
    		if (this.subElements.container)
    			this.subElements.container.setStyles({
    				'top':  window.getSize().y / 2 - 80  + window.getScroll().y,
    				'left': window.getSize().x / 2 - 180 + window.getScroll().x
    			});
	},
	
	/*******************************************************************************/
	/*** *** ***                                                                 ***/
	/***                      ÉVÉNEMENTS DE REQUÊTES AJAX                        ***/
	/***                                                                 *** *** ***/
	/*******************************************************************************/
	
	/**
	 * Quand la requête est envoyée.
	 * 
	 * Au bout de MAX_REQUEST_EXECUTION_TIME secondes,
	 * si rien ne s'est passé : on annule la requête AJAX
	 */
	onRequest: function(bind){
		this.request = bind; // L'instance d'objet Request.
		this.loading();      // Lancer l'animation de chargement.
		(function(){         // Au bout d'un certain temps...
			if (!bind.isSuccess()) // Si la requête a réussi...
				this.endRequest(); // Arrêter l'animation de chargement.
		}.bind(this)).delay(window.MAX_REQUEST_EXECUTION_TIME || 10000);
	},
	
	/**
	 * En cas d'échec de la requête (code d'erreur).
	 */
	onFailure: function(instance, message){
		if (this.debug){
			message += ": readyState=" + instance.readyState;
			message += ", status="     + instance.status;
			alert(message, 'error');
		}
		this.endRequest();
	},
	
	/**
	 * En cas d'annulation de la requête en cours.
	 */
	onCancel: function(message){
		if (this.debug)
			alert(message, 'error');
		this.endRequest();
	},
	
	/**
	 * Annuler une requête AJAX
	 */
	cancelRequest: function(hide){
		if (this.request != null)
			this.request.cancel();
		if (hide === true)
			this.hideLoading();
		this.request = null;
	},
	
	/**
	 * Terminer une requête AJAX
	 */
	endRequest: function(){
		this.cancelRequest(true);
	},
	
	/**
	 * @return {Boolean}
	 */
	isRequesting: function(){
		return (this.request != null);
	},
	
	/*******************************************************************************/
	/*** *** ***                                                                 ***/
	/***                        INDICATEUR DE CHARGEMENT                         ***/
	/***                                                                 *** *** ***/
	/*******************************************************************************/
	
	/**
	 * Afficher un indicateur de chargement et la possibilité d'annuler 
	 * l'action en cours lors d'une requête AJAX lourde comprenant la 
	 * génération de fichiers PDF, la manipulation d'images avec 
	 * ImageMagick et la manipulation de données MySQL.
	 *
	 * @access public
	 * @return {Void}
	 */
	loading: function(){
		// On charge le loading dans le DOM
		this.initLoading();
		// On fait apparaître les éléments HTML
		if (!Browser.Engine.webkit)
			this.subElements.overlay.setStyles({
				'visibility': 'visible',
				'opacity': 0
			}).fade(0.5);
		this.subElements.container.setStyle('display', 'block').fade('in');
		this.toggleTroubleElements(false);
	},
	
	/**
	 * Affiche un message d'erreur et propose de recharger la page
	 * 
	 * @access public
	 * @return {Void}
	 */
	cancelLoading: function(){
		
		if (this.loadingExists){
			
			new Element('br').inject(this.subElements.container, 'bottom');
			new Element('br').inject(this.subElements.container, 'bottom');
			
			new Element('p', {
				'html': this.options.text.loadingProblem + '<br \/><strong>' + this.options.text.changes + '<\/strong>',
				'styles': {
					'display':      'inline',
					'text-align':   'center',
					'font-size':    '12px',
					'padding-left': '20px',
					'background':   'transparent',
					'margin':       '0px auto'
				}
			}).inject(this.subElements.container, 'bottom');
			
			new Element('br').inject(this.subElements.container, 'bottom');
			
			new Element('button', {
				'id':     'bouton-annuler-requete',
				'type':   'button',
				'html':   '<img src="' + this.options.baseUrl + '/public/images/icons/cancel.png" alt="" width="16" height="16" class="png" \/> ' + this.options.text.cancelButton,
				'events': {
					'click': function(){
						this.cancelRequest();     // on annule la requête AJAX en cours
						window.location.reload(); // on recharge la page
					}.bind(this)
				}
			}).inject(this.subElements.container, 'bottom');
			
			if (Browser.Engine.trident4)
				$$('#loading-container .png').pngfix();
		}
	},
	
	/**
	 * Charger l'indicateur de chargement dans le DOM
	 * 
	 * @access private
	 * @return {Void}
	 */
	initLoading: function(){
		
		// Ne continuer que si c'est la 1ère utilisation du loading
		if (!this.loadingExists){
			
			this.subElements.overlay = new Element('div', {
				'id':    'loading-overlay',
				'class': 'png',
                'styles': {
                    'position':   (Browser.Engine.trident4) ? 'absolute' : 'fixed',
                    'top':        '0px',
                    'left':       '0px',
					'height':     window.getScrollSize().y,
					'width':      window.getScrollSize().x,
                    'text-align': 'center'
                }
			}).inject($(document.body), 'top');
			
			this.subElements.container = new Element('div', {
				'id':   'loading-container',
				'styles': {
                    'position': (Browser.Engine.trident4) ? 'absolute' : 'fixed',
					'top':      window.getSize().y / 2 - 80,
                    'left':     window.getSize().x / 2 - 160,
					'display':  'none'
				}
			}).inject($(document.body), 'top');
			
			this.subElements.text = new Element('p', {
				'text': this.options.text.loading,
				'styles': {
					'display':             'inline',
					'text-align':          'left',
					'font-size':           '14px',
					'padding-left':        '25px',
					'background-color':    'transparent',
					'background-image':    'url(' + this.options.baseUrl + '/public/images/spinner.gif)',
					'background-repeat':   'no-repeat',
					'background-position': 'left center',
					'margin':              '0 auto'
				}
			}).inject(this.subElements.container, 'bottom');
			
			this.loadingExists = true;
		}
	},
	
	/**
	 * Masque l'indicateur de chargement
	 *
	 * @access private
	 * @return {Void}
	 */
	hideLoading: function(){
		if ($('loading-container') != null) $('loading-container').fade('out').setStyle('display', 'none');
		if ($('loading-overlay')   != null) $('loading-overlay').fade('out');
		this.toggleTroubleElements(true);
	},
	
	/**
	 * Événements divers
	 */
	makeEvents: function(){
		window.addEvents({
            'resize': this.onResize.bind(this),
            'scroll': this.onScroll.bind(this)
        });
	},
    
    /**
     * @access private
	 * @return {Void}
     * @param {Boolean} on
     * @copyright Shadowbox <http://mjijackson.com/>
     */
    toggleTroubleElements: function(on){
        var vis = (on ? "visible" : "hidden");
        var selects = document.getElementsByTagName("select");
        for (i = 0, len = selects.length; i < len; ++i) {
            selects[i].style.visibility = vis
        }
        var objects = document.getElementsByTagName("object");
        for (i = 0, len = objects.length; i < len; ++i) {
            objects[i].style.visibility = vis
        }
        var embeds = document.getElementsByTagName("embed");
        for (i = 0, len = embeds.length; i < len; ++i) {
            embeds[i].style.visibility = vis
        }
        var iframes = document.getElementsByTagName("iframe");
        for (i = 0, len = iframes.length; i < len; ++i) {
            iframes[i].style.visibility = vis
        }
    }
	
}; // Fin classe "Loader"

Loader = new Class(Loader);
