
Drupal.Ajax = new Object;

Drupal.Ajax.plugins = {};

Drupal.Ajax.firstRun = false;

/**
 * Init function. This is being executed by Drupal behaviours. See bottom of
 * script.
 * 
 * @param {HTMLElement}
 *            context
 * @return {Bool}
 */
Drupal.Ajax.init = function(context) {
	var f, s;
	if (f = $('.ajax-form', context)) {
		if (!Drupal.Ajax.firstRun) {
			Drupal.Ajax.invoke('init');
			Drupal.Ajax.firstRun = true;
		}
		s = $('input[type="submit"],input[id^="edit-submit"]', f);
		s.click(function() {
			this.form.ajax_activator = $(this);
			return true;
		});
		f.each(function() {
			this.ajax_activator = null;
			$(this).submit(function() {
				if (this.ajax_activator === null) {
					this.ajax_activator = $('#edit-submit', this);
				}
				if (this.ajax_activator.hasClass('ajax-trigger')) {
					Drupal.Ajax.go($(this), this.ajax_activator);
					return false;
				} else {
					return true;
				}
			});
			return true;
		});
	}
	return true;
};

/**
 * Invokes plugins
 * 
 * @param {Object}
 *            formObj
 * @param {Object}
 *            submitter
 */
Drupal.Ajax.invoke = function(hook, args) {
	var plugin, r, ret;
	ret = true;
	for (plugin in Drupal.Ajax.plugins) {
		r = Drupal.Ajax.plugins[plugin](hook, args);
		if (r === false) {
			ret = false;
		}
	}
	return ret;
};

/**
 * Handles submission
 * 
 * @param {Object}
 *            submitter_
 * @return {Bool}
 */
Drupal.Ajax.go = function(formObj, submitter) {
	var submitterVal, submitterName, extraData;
	Drupal.Ajax.invoke('submit', {
		submitter : submitter
	});
	submitterVal = submitter.val();
	submitterName = submitter.attr('name');
	submitter.val(Drupal.t('espere ...'));
	extraData = {};
	extraData[submitterName] = submitterVal;
	extraData['drupal_ajax'] = '1';
	formObj.ajaxSubmit( {
		extraData : extraData,
		beforeSubmit : function(data) {
			data[data.length] = {
				name : submitterName,
				value : submitterVal
			};
			data[data.length] = {
				name : 'drupal_ajax',
				value : '1'
			};
			return true;
		},
		dataType : 'json',
		error : function(XMLHttpRequest, textStatus, errorThrown) {
			window.alert(Drupal
					.t('ajax.module: An unknown error has occurred.'));
			if (window.console) {
				console.log('error', arguments);
			}
			return true;
		},
		success : function(data) {
			submitter.val(submitterVal);
			Drupal.Ajax.response(submitter, formObj, data);
			return true;
		}
	});
	return false;
};

/**
 * Handles scroller
 * 
 * @param {Object}
 *            submitter
 * @return {Bool}
 */
Drupal.Ajax.scroller = function(submitter) {
	var scroll_weight, box, found, timer;
	scroll_weight = 100;
	timer = window.setInterval(function() {
		box = submitter;
		found = false;
		// Watch for thickbox
			while (box.parentNode !== null
					&& Drupal.Ajax.invoke('scrollFind', {
						container : box
					})) {
				box = box.parentNode;
				// Document
				if (box === document) {
					if (box.documentElement.scrollTop
							&& box.documentElement.scrollTop > 0) {
						box.documentElement.scrollTop -= scroll_weight;
						found = true;
					}
				}
				// Body
				else if (box === document.body) {
					if (box.scrollTop && box.scrollTop > 0) {
						box.scrollTop -= scroll_weight;
						found = true;
					}
				}
				// Window
				else if (box === window) {
					if ((window.pageYOffset && window.pageYOffset > 0)
							|| (window.scrollY && window.scrollY > 0)) {
						window.scrollBy(0, -scroll_weight);
						found = true;
					}
				}
				// Any other element
				else {
					if (box.scrollTop && box.scrollTop > 0) {
						box.scrollTop -= scroll_weight;
						found = true;
					}
				}
			}
			// Check if completed
			if (!found) {
				window.clearInterval(timer);
			}
			return true;
		}, 100);
	return true;
};

/**
 * Handles messaging
 * 
 * @param {Object}
 *            formObj
 * @param {Object}
 *            submitter
 * @param {Object}
 *            data
 * @param {Object}
 *            options
 * @return {Bool}
 */
Drupal.Ajax.message = function(formObj, submitter, data, options) {
	var args;
	args = {
		formObj : formObj,
		submitter : submitter,
		data : data,
		options : options
	};
	if (Drupal.Ajax.invoke('message', args)) {
		Drupal.Ajax.writeMessage(args.formObj, args.submitter, args.options);
	}
	return true;
};

/**
 * Writes message
 * 
 * @param {Object}
 *            formObj
 * @param {Object}
 *            submitter
 * @param {Object}
 *            options
 * @return {Bool}
 */
Drupal.Ajax.writeMessage = function(formObj, submitter, options) {
	var i, _i, thisItem, log, errBox, h;
	if (options.action === 'notify') {
		// Cleanups
		$('.messages, .ajax-preview', formObj).remove();
		$('input, textarea').removeClass('error status warning required');
		// Preview
		if (options.type === 'preview') {
			log = $('<div>').addClass('ajax-preview');
			log.html(options.messages);
			formObj.prepend(log);
		}
		// Status, Error, Message
		else {
			log = $('<ul>');
			ajax_message_container = (Drupal.settings.ajax_message_container != undefined)?Drupal.settings.ajax_message_container:formObj[0];
			ajax_message_div_class = (Drupal.settings.ajax_div_class != undefined)?Drupal.settings.ajax_div_class:'';
			errBox = $(".messages." + options.type, ajax_message_container)
			for (i = 0, _i = options.messages.length; i < _i; i++) {
				thisItem = $('#' + options.messages[i].id, formObj[0])
				thisItem.addClass(options.type);
				if (options.messages[i].required) {
					thisItem.addClass('required');
				}
				log.append('<li>' + options.messages[i].value + '</li>');
			}
			if (errBox.length === 0) {
				errBox = $("<div class='messages " + options.type + " "  + ajax_message_div_class + "'>");
				$(ajax_message_container).prepend(errBox);
			}
			errBox.html(log);
		}
	} else if (options.action === 'clear') {
		$('.messages, .ajax-preview', formObj).remove();
	}
	Drupal.Ajax.scroller(submitter[0]);
	return true;
};

/**
 * Updates message containers
 * 
 * @param {Object}
 *            updaters
 * @return {Bool}
 */
Drupal.Ajax.updater = function(updaters) {
	var i, _i, elm;
	for (i = 0, _i = updaters.length; i < _i; i++) {
		elm = $(updaters[i].selector);
		// HTML:IN
		if (updaters[i].type === 'html_in') {
			elm.html(updaters[i].value);
		}
		// HTML:OUT
		else if (updaters[i].type === 'html_out') {
			elm.replaceWith(updaters[i].value);
		}
		// FIELD
		else if (updaters[i].type === 'field') {
			elm.val(updaters[i].value);
		}
		// REMOVE
		else if (updaters[i].type === 'remove') {
			elm.remove();
		}
	}
	return true;
};

/**
 * Handles data response
 * 
 * @param {Object}
 *            submitter
 * @param {Object}
 *            formObj
 * @param {Object}
 *            data
 * @return {Bool}
 */
Drupal.Ajax.response = function(submitter, formObj, data) {
	var newSubmitter;
	data.local = {
		submitter : submitter,
		form : formObj
	};
	if (data.status === false) { // si falló el submit, muestro los mensajes de error
		Drupal.Ajax.updater(data.updaters);
		if (!Drupal.Ajax.invoke('error', data)){
			Drupal.Ajax.message(formObj, submitter, data, {
				action : 'notify',
				messages : data.messages_error,
				type : 'error'
			});
		}
	} else { // el submit fue ok...
		if (data.preview !== null) { // si hay preview
			Drupal.Ajax.updater(data.updaters);
			Drupal.Ajax.message(formObj, submitter, data, {
				action : 'notify',
				messages : decodeURIComponent(data.preview),
				type : 'preview'
			});
		} else // si no hay preview
		if (data.redirect === null) { // Si no hay redirect
			if (data.messages_status.length > 0)
				Drupal.Ajax.message(formObj, submitter, data, {
					action : 'notify',
					messages : data.messages_status,
					type : 'status'
				});
			if (data.messages_warning.length > 0)
				Drupal.Ajax.message(formObj, submitter, data, {
					action : 'notify',
					messages : data.messages_warning,
					type : 'warning'
				});
			if (data.messages_status.length === 0
					&& data.messages_warning.length === 0)
				Drupal.Ajax.message(formObj, submitter, data, {
					action : 'clear'
				});
		} else { // Si hay redirect
			if (Drupal.Ajax.invoke('complete', data)) { // si el resultado de
														// invocar al hook
														// complete == true,
														// redirijo
				Drupal.Ajax.redirect(data.redirect);
			} else { // sino, updater y limpio mensajes
				Drupal.Ajax.updater(data.updaters);
				if (data.messages_status.length === 0
						&& data.messages_warning.length === 0) {
					Drupal.Ajax.message(formObj, submitter, data, {
						action : 'clear'
					});
				} else {
					Drupal.Ajax.message(formObj, submitter, data, {
						action : 'notify',
						messages : data.messages_status,
						type : 'status'
					});
				}
			}
		}
	}
	return true;
};

/**
 * Redirects to appropriate page
 * 
 * @todo Some of this functionality should possibly hapen on the server instead
 *       of client.
 * @param {String}
 *            url
 */
Drupal.Ajax.redirect = function(url) {
	window.location.href = url;
};

Drupal.behaviors.Ajax = Drupal.Ajax.init;
