/**
 * @author Abdellah Boutmouzzar abdellah@3wkom.net
 * TODO:
 */
var abAjaxForm = new Class({
	Implements: Options,
	options: {
		abForm: '.abForm',
		abResponseHolder: '.abResponseHolder',
		abValidate: true,
		abValidator: {},
		abRequired: '.required',
		abSpinner: '.abSpinner',
		abTween: false,
		abTweenProperty: 'right',
		abTweenAmount: 50,
		abDispatchResponse: true,
		abRefreshCaptcha: true,
		abEvalScripts: true,
		abUseAlerts: false,
		abLangId: 1,
		onClick: $empty,
		onComplete: $empty
	},
	initialize: function(abMode, options){
		this.setOptions(options);
		this.abForm = this.options.abForm;
		this.abResponseHolder = this.options.abResponseHolder;
		this.abValidate = this.options.abValidate;
		this.abValidator = this.options.abValidator;
		this.abRequired = this.options.abRequired;
		this.abSpinner = this.options.abSpinner;
		this.abTween = this.options.abTween;
		this.abTweenProperty = this.options.abTweenProperty;
		this.abTweenAmount = this.options.abTweenAmount;
		this.abDispatchResponse = this.options.abDispatchResponse;
		this.abRefreshCaptcha = this.options.abRefreshCaptcha;
		this.abEvalScripts = this.options.abEvalScripts;
		this.abUseAlerts = this.options.abUseAlerts;
		this.abLangId = this.options.abLangId;
		this.abMode = abMode || 'Basic';
		this.abReady = true;

		this.abResponseHolderH = [];
		this.abFormH = [];
		
		this.abInitLocale();
		this.abInitEvents();
	},
	abInitEvents: function(){
		$$(this.abForm).each(function(el, i){
			var submitTrigger = el;
			if (this.abMode == 'Advanced') {
				submitTrigger = $$(this.abForm)[i].getElement('form');
				this.abFormH[i] = this.abFormH[i] || $$(this.abForm)[i].getFirst().getSize().y;
				this.abResponseHolderH[i] = this.abResponseHolderH[i] || $$(this.abResponseHolder)[i].getFirst().getSize().y - 20;
				this.abPreInitEvents(i);
			}
			if (this.abResponseHolder != false && $type($$(this.abResponseHolder)[i]) == 'element' && this.abTween) {
				$$(this.abResponseHolder)[i].set('tween', {
					duration: 'short'
				});
				this.abPos = $$(this.abResponseHolder)[i].getStyle(this.abTweenProperty).toInt();
			}
			if ($type(el.getElement(this.abSpinner)) == 'element') {
				el.getElement(this.abSpinner).setStyles({
					width: '100%',
					height: '100%'
				});
			}
			submitTrigger.addEvent('submit', function(e){
				e.stop();
				if (this.abValidate) {
					var required = submitTrigger.getElements('input' + this.abRequired);
					$each(required, function(req, m){
						if (this.abValidator.validate(req)) {
							this.abReady = true;
						}
						else {
							this.abReady = false;
						}
					}.bind(this));
				}
				if (this.abReady) {
					//passer i au lieu de l'élément courant va rendre le code un peu lourd (en écriture), mais le navigateur lui dira merci ;-)
					this.abHandleRequests(this.abMode, i);
				}
			}.bind(this));
		}.bind(this));
	},
	abHandleRequests: function(abMode, i){
		//vérifier que l'élément existe
		if ($type($$(this.abForm)[i]) == 'element') {
			if (abMode == 'Basic') {
				new Request.JSON({
					url: $$(this.abForm)[i].action,
					data: $$(this.abForm)[i].toQueryString() + '&from=abAjaxForm',
					onSuccess: function(response){
						$$(this.abForm)[i].getElement(this.abSpinner).setStyle('display', 'none');
						$each(response, function(value, key){
							if(this.abUseAlerts) {
								alert(html_entity_decode(value));
							}
							else {
								if (this.abDispatchResponse && $type($$(this.abResponseHolder)[i]) == 'element') {
									$$(this.abResponseHolder)[i].getElement('.' + key).set('text', '');
									$$(this.abResponseHolder)[i].getElement('.' + key).set('html', value);
								}
								else {
									//$$(this.abResponseHolder)[i].addClass(key).set('text', value).tween('left', [0, '2px']);
									//(function() {$$(this.abResponseHolder)[i].tween('letter-spacing', ['2px', 0])}).delay(250);
									$$(this.abResponseHolder)[i].set('text', '');
									new Element('span', {
										'class': key,
										html: value
									}).inject($$(this.abResponseHolder)[i]);
									
									if (this.abTween) {
										$$(this.abResponseHolder)[i].tween(this.abTweenProperty, (this.abPos + this.abTweenAmount) + 'px');
										(function(){
											$$(this.abResponseHolder)[i].tween(this.abTweenProperty, this.abPos + 'px')
										}.bind(this)).delay(250);
									}
								}
							}
						}.bind(this));

						this.options.onComplete();

					}.bind(this),
					onRequest: function(){
						$$(this.abForm)[i].getElement(this.abSpinner).setStyle('display', 'block');
					}.bind(this)
				}).send();
			}

			if (abMode == 'Advanced') {
				new Request.JSON({
					url: $$(this.abForm)[i].getElement('form').action,
					data: $$(this.abForm)[i].getElement('form').toQueryString() + '&from=abAjaxForm',
					onSuccess: function(response){
						$$(this.abForm)[i].getElement(this.abSpinner).setStyle('display', 'none');
						if ($type($$(this.abResponseHolder)[i]) == 'element') {
							this.abDoFinish = true;
							$each(response, function(value, key){
								//cheat pour evaluer les scripts dans ce type de request
								if(this.abEvalScripts && key == 'abDomReady') {
									eval(value);
								}
								else {
									if (this.abDispatchResponse) {
										if ($type($$(this.abResponseHolder)[i].getElement('.abHolder-' + key)) == 'element') {
											$$(this.abResponseHolder)[i].getElement('.abHolder-' + key).set('text', '');
											$$(this.abResponseHolder)[i].getElement('.abHolder-' + key).set('html', value);
										}
									}
									else {
										$$(this.abResponseHolder)[i].set('text', '');
										new Element('span', {
											'class': key,
											html: value
										}).inject($$(this.abResponseHolder)[i]);
										
										if (this.abTween) {
											$$(this.abResponseHolder)[i].tween(this.abTweenProperty, (this.abPos + this.abTweenAmount) + 'px');
											(function(){
												$$(this.abResponseHolder)[i].tween(this.abTweenProperty, this.abPos + 'px')
											}.bind(this)).delay(250);
										}
									}
								}
							}.bind(this));
						}
						if(this.abDoFinish) {
							$$(this.abForm)[i].morph({
								'height': 0,
								'opacity': 0,
								'overflow': 'hidden'
							});
							$$(this.abResponseHolder)[i].morph({
								'height': this.abResponseHolderH[i],
								'opacity': 1
							});
	
							this.options.onComplete();
						}

					}.bind(this),
					onRequest: function(){
						$$(this.abForm)[i].getElement(this.abSpinner).setStyle('display', 'block');
					}.bind(this)
				}).send();
			}
		}
	},
	abPreInitEvents: function(i){
		$$($$(this.abResponseHolder)[i], $$(this.abForm)[i]).set('morph', {
			duration: 500
		});

		$$(this.abResponseHolder)[i].getElement('.abFormToggler').addEvent('click', function(e){
			e.stop();
			if(this.abRefreshCaptcha) {
				$$(this.abForm)[i].getElement(".captcha_regenerator").fireEvent("click", {stop:$empty});
			}
			$$(this.abResponseHolder)[i].morph({
				'opacity': 0,
				'height': 0,
				'overflow': 'hidden'
			});
			$$(this.abForm).morph({
				'opacity': 0,
				'height': 0
			});
			$$(this.abForm)[i].morph({
				'opacity': 1,
				'height': this.abFormH[i]
			});
			this.options.onClick();
		}.bind(this));
	},
	abInitLocale: function(){
	},
	abClassExists: function(c){
		return typeof(c) == 'function' && typeof(c.prototype) == 'object' ? true : false;
	}
});

function html_entity_decode (string, quote_style) {
    // http://kevin.vanzonneveld.net
    // +   original by: john (http://www.jd-tech.net)
    // +      input by: ger
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   bugfixed by: Onno Marsman
    // +   improved by: marc andreu
    // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +      input by: Ratheous
    // +   bugfixed by: Brett Zamir (http://brett-zamir.me)
    // +      input by: Nick Kolosov (http://sammy.ru)
    // +   bugfixed by: Fox
    // -    depends on: get_html_translation_table
    // *     example 1: html_entity_decode('Kevin &amp; van Zonneveld');
    // *     returns 1: 'Kevin & van Zonneveld'
    // *     example 2: html_entity_decode('&amp;lt;');
    // *     returns 2: '&lt;'

    var hash_map = {}, symbol = '', tmp_str = '', entity = '';
    tmp_str = string.toString();
    
    if (false === (hash_map = this.get_html_translation_table('HTML_ENTITIES', quote_style))) {
        return false;
    }

    // fix &amp; problem
    // http://phpjs.org/functions/get_html_translation_table:416#comment_97660
    delete(hash_map['&']);
    hash_map['&'] = '&amp;';

    for (symbol in hash_map) {
        entity = hash_map[symbol];
        tmp_str = tmp_str.split(entity).join(symbol);
    }
    tmp_str = tmp_str.split('&#039;').join("'");
    
    return tmp_str;
}

function get_html_translation_table (table, quote_style) {
    // http://kevin.vanzonneveld.net
    // +   original by: Philip Peterson
    // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   bugfixed by: noname
    // +   bugfixed by: Alex
    // +   bugfixed by: Marco
    // +   bugfixed by: madipta
    // +   improved by: KELAN
    // +   improved by: Brett Zamir (http://brett-zamir.me)
    // +   bugfixed by: Brett Zamir (http://brett-zamir.me)
    // +      input by: Frank Forte
    // +   bugfixed by: T.Wild
    // +      input by: Ratheous
    // %          note: It has been decided that we're not going to add global
    // %          note: dependencies to php.js, meaning the constants are not
    // %          note: real constants, but strings instead. Integers are also supported if someone
    // %          note: chooses to create the constants themselves.
    // *     example 1: get_html_translation_table('HTML_SPECIALCHARS');
    // *     returns 1: {'"': '&quot;', '&': '&amp;', '<': '&lt;', '>': '&gt;'}
    
    var entities = {}, hash_map = {}, decimal = 0, symbol = '';
    var constMappingTable = {}, constMappingQuoteStyle = {};
    var useTable = {}, useQuoteStyle = {};
    
    // Translate arguments
    constMappingTable[0]      = 'HTML_SPECIALCHARS';
    constMappingTable[1]      = 'HTML_ENTITIES';
    constMappingQuoteStyle[0] = 'ENT_NOQUOTES';
    constMappingQuoteStyle[2] = 'ENT_COMPAT';
    constMappingQuoteStyle[3] = 'ENT_QUOTES';

    useTable       = !isNaN(table) ? constMappingTable[table] : table ? table.toUpperCase() : 'HTML_SPECIALCHARS';
    useQuoteStyle = !isNaN(quote_style) ? constMappingQuoteStyle[quote_style] : quote_style ? quote_style.toUpperCase() : 'ENT_COMPAT';

    if (useTable !== 'HTML_SPECIALCHARS' && useTable !== 'HTML_ENTITIES') {
        throw new Error("Table: "+useTable+' not supported');
        // return false;
    }

    entities['38'] = '&amp;';
    if (useTable === 'HTML_ENTITIES') {
        entities['160'] = '&nbsp;';
        entities['161'] = '&iexcl;';
        entities['162'] = '&cent;';
        entities['163'] = '&pound;';
        entities['164'] = '&curren;';
        entities['165'] = '&yen;';
        entities['166'] = '&brvbar;';
        entities['167'] = '&sect;';
        entities['168'] = '&uml;';
        entities['169'] = '&copy;';
        entities['170'] = '&ordf;';
        entities['171'] = '&laquo;';
        entities['172'] = '&not;';
        entities['173'] = '&shy;';
        entities['174'] = '&reg;';
        entities['175'] = '&macr;';
        entities['176'] = '&deg;';
        entities['177'] = '&plusmn;';
        entities['178'] = '&sup2;';
        entities['179'] = '&sup3;';
        entities['180'] = '&acute;';
        entities['181'] = '&micro;';
        entities['182'] = '&para;';
        entities['183'] = '&middot;';
        entities['184'] = '&cedil;';
        entities['185'] = '&sup1;';
        entities['186'] = '&ordm;';
        entities['187'] = '&raquo;';
        entities['188'] = '&frac14;';
        entities['189'] = '&frac12;';
        entities['190'] = '&frac34;';
        entities['191'] = '&iquest;';
        entities['192'] = '&Agrave;';
        entities['193'] = '&Aacute;';
        entities['194'] = '&Acirc;';
        entities['195'] = '&Atilde;';
        entities['196'] = '&Auml;';
        entities['197'] = '&Aring;';
        entities['198'] = '&AElig;';
        entities['199'] = '&Ccedil;';
        entities['200'] = '&Egrave;';
        entities['201'] = '&Eacute;';
        entities['202'] = '&Ecirc;';
        entities['203'] = '&Euml;';
        entities['204'] = '&Igrave;';
        entities['205'] = '&Iacute;';
        entities['206'] = '&Icirc;';
        entities['207'] = '&Iuml;';
        entities['208'] = '&ETH;';
        entities['209'] = '&Ntilde;';
        entities['210'] = '&Ograve;';
        entities['211'] = '&Oacute;';
        entities['212'] = '&Ocirc;';
        entities['213'] = '&Otilde;';
        entities['214'] = '&Ouml;';
        entities['215'] = '&times;';
        entities['216'] = '&Oslash;';
        entities['217'] = '&Ugrave;';
        entities['218'] = '&Uacute;';
        entities['219'] = '&Ucirc;';
        entities['220'] = '&Uuml;';
        entities['221'] = '&Yacute;';
        entities['222'] = '&THORN;';
        entities['223'] = '&szlig;';
        entities['224'] = '&agrave;';
        entities['225'] = '&aacute;';
        entities['226'] = '&acirc;';
        entities['227'] = '&atilde;';
        entities['228'] = '&auml;';
        entities['229'] = '&aring;';
        entities['230'] = '&aelig;';
        entities['231'] = '&ccedil;';
        entities['232'] = '&egrave;';
        entities['233'] = '&eacute;';
        entities['234'] = '&ecirc;';
        entities['235'] = '&euml;';
        entities['236'] = '&igrave;';
        entities['237'] = '&iacute;';
        entities['238'] = '&icirc;';
        entities['239'] = '&iuml;';
        entities['240'] = '&eth;';
        entities['241'] = '&ntilde;';
        entities['242'] = '&ograve;';
        entities['243'] = '&oacute;';
        entities['244'] = '&ocirc;';
        entities['245'] = '&otilde;';
        entities['246'] = '&ouml;';
        entities['247'] = '&divide;';
        entities['248'] = '&oslash;';
        entities['249'] = '&ugrave;';
        entities['250'] = '&uacute;';
        entities['251'] = '&ucirc;';
        entities['252'] = '&uuml;';
        entities['253'] = '&yacute;';
        entities['254'] = '&thorn;';
        entities['255'] = '&yuml;';
    }

    if (useQuoteStyle !== 'ENT_NOQUOTES') {
        entities['34'] = '&quot;';
    }
    if (useQuoteStyle === 'ENT_QUOTES') {
        entities['39'] = '&#39;';
    }
    entities['60'] = '&lt;';
    entities['62'] = '&gt;';


    // ascii decimals to real symbols
    for (decimal in entities) {
        symbol = String.fromCharCode(decimal);
        hash_map[symbol] = entities[decimal];
    }
    
    return hash_map;
}

