/*

$.stripesAjaxAction


parameter description:
    action: 
        string - the stripes action url (including context path)
    params: 
        map or string - map of parameters that will be passed to the stripes action. Passing the string
        'stripesEventName' is equivalent to passing the map {'stripesEventName': ''} 
    options: map
        {
            beforeSubmit: 
                function() - executed before sending the ajax request, can abort the request by returning false
            afterResponse: 
                function(data) - executed immediately after the request is completed and before the response data
                is evaluated, can abort response evaluation by returning false
            message:
                function(text) - called for each stripes message contained inside the response (the message text will
                be passed as argument)
            validationError:
                function(text, field) - called for each stripes validation error: the error text and, if present, the 
                error field will be passed as arguments (note that global errors do not define an error field)
            complete:
                function(data, numProcessed) - called after all the errors and messages have been processed, the 
                response data and the total number of messages and validation errors processed will be passed as 
                arguments
        }
	that: the element to which the functions will be applied, defaults to this if not provided

returns false

Usage example:

    $('a.ajaxAction').bind('click', function() { 
        return $.stripesAjaxAction(
            '/path/actions/test.action', 
            {eventName: '', user : 'pippo' },
            {
                beforeSubmit: function() { alert('submitted'); },
                afterResponse: function(data) { alert('received response of type : ' + data.response.type); },
                message: function(text) { alert(text); },
                validationError: function(text, field) { alert('text: ' + text + '\nfield: ' + field); }
                complete: function(data) { alert('completed'); }
            });
        }
    );


$(selector).stripesAjaxAction
parameter description:
    type: string indicating event type (e.g. 'click') to bind
    other parameters: see $.stripesAjaxAction

returns $(this)

Usage example:
    
    $('a#ajaxLink').stripesAjaxAction(
        'click', 
        '/path/actions/test.action',
        {eventName: '', user : 'pippo' },
        {
            beforeSubmit: function() { alert('submitted'); },
            afterResponse: function(data) { alert('received response of type : ' + data.response.type); },
            message: function(text) { alert(text); },
            validationError: function(text, field) { alert('text: ' + text + '\nfield: ' + field); },
            complete: function(data, numProcessed) { alert('completed. processed: ' + numProcessed); }
        }
    );


 *** WORK IN PROGRESS **
$(selector).stripesAjaxForm
parameter description:
    options: map
        {
            afterResponse: 
                function(data) - executed immediately after the request is completed and before stripes messages and
                validation errors are evaluated. Can abort response evaluation by returning false
            message:
                function(text) - called for each stripes message contained inside the response (the message text will
                be passed as argument)
            validationError:
                function(text, field) - called for each stripes validation error: the error text and, if present, the 
                error field will be passed as arguments (note that global errors do not define an error field)
            complete:
                function(data, numProcessed) - called after all the errors and messages have been processed, the 
                response data and the total number of messages and validation errors processed will be passed as 
                arguments (note that this overrides the complete option of $().ajaxForm
			
			(any other parameters accepted by $().ajaxForm or $.ajax)
        }

 */

;
(function($) {

	$.stripesAjaxAction = function(action, params, options, that) {
		if (!action) {
			// no action provided
			return false;
		}
		if (!that)
			that = this;

		if (typeof params === 'string') {
			var tmp = {};
			tmp[params] = '';
			params = tmp;
		} else {
			params = params || {};
		}
		options = options || {};

		if (options.beforeSubmit && options.beforeSubmit.apply(that) === false) {
			// aborted by beforeSubmit
			return false;
		}

		$.getJSON(action, params, function(data) {
			if (options.afterResponse && options.afterResponse.apply(that, [ data ]) === false) {
				// aborted by afterResponse
				return;
			}

			var numProcessed = $.processStripesAjaxOutcome(data, options.message, options.validationError, that);
			if (options.complete)
				options.complete.apply(that, [ data, numProcessed ]);
		});
		return false;
	};

	// element-based version of $.stripesAjaxAction
	$.fn.stripesAjaxAction = function(type, action, params, options) {
		var that = this;
		return $(that).bind(type, function() {
			return $.stripesAjaxAction.apply(action, params, options, that);
		});
	};
	
	$.fn.stripesAjaxForm = function(options)
	{
		var that = this;
		if(typeof options === 'function') {
			options = { success: options };
		}
		var afterResponse1 = options.afterResponse;
		var message1 = options.message;
		var validationError1 = options.validationError;
		var complete1 = options.complete;
		delete options.afterResponse;
		delete options.message;
		delete options.validationError;
		delete options.complete;

		var stripesOptions = { dataType: 'json' };
		stripesOptions.success = function(json)
		{
			if (afterResponse1 && afterResponse1.apply(that, [ json ]) === false) {
				// aborted by afterResponse
				return;
			}

			var numProcessed = $.processStripesAjaxOutcome(json, message1, validationError1, that);
			if (complete1)
				complete1.apply(that, [ json, numProcessed ]);
		};
		
		$.extend(options, stripesOptions);
		$(that).ajaxForm(options);
	};

	/**
	 * display the outcome of a stripes ajax call
	 * 
	 * @param data
	 *            the ajax response data
	 * @param message
	 *            function(text) to be called on message
	 * @param onValidationError
	 *            function(text, field) to be called on validation error
	 * @return the total number of errors and messages processed
	 */
	$.processStripesAjaxOutcome = function(data, message, validationError, that) {
		var count = 0;
		if (!data) {
			return count;
		}
		var errorsPresent = (data.response && data.response.errcode) || data.errors;

		if (errorsPresent && validationError) {
			if (data.response.errcode) {
				validationError('error: ' + data.response.errcode + ' - ' + data.response.errmsg);
				count++;
			}
			if (data.errors) {
				for ( var field in data.errors) {
					var fieldErrs = data.errors[field];
					if (fieldErrs instanceof Array) {
						for ( var err in fieldErrs) {
							if (field === '_global') {
								validationError(err);
							} else {
								validationError(err, field);
							}
							count++;
						}
					} else {
						if (field === '_global') {
							validationError(fieldErrs);
						} else {
							validationError(fieldErrs, field);
						}
						count++;
					}
				}
			}
		}
		if (message && data.messages) {
			if (data.messages instanceof Array) {
				for ( var msg in data.messages) {
					message(msg);
					count++;
				}
			} else {
				message(data.messages);
				count++;
			}
		}
		return count;
	};

})(jQuery);
