AJAX_ERROR = 'ERROR';
AJAX_OK = 'OK';

/**
 * Replacement for jQuery Ajax function with showing loader.
 *
 **/
(function($){
	/** @var object objects created loaders */
	var loaders = {};
	/** @var object count of loaders created on objects */
	var loadersCount = {};

	$.extend({
		loaderGetElem: function() {
			return $('<div class="ajax_loader"><div class="ajax_loader_overlay"></div><div class="ajax_loader_loader"></div></div>');
		}
	});

	/**
	* Show loader on elements.
	*/
	$.fn.loaderShow = function() {
		return this.each(function() {
			var elem = $(this).get(0);
			if($.isNumber(loadersCount[elem]) && loadersCount[elem] > 0) {
				++ loadersCount[elem];
				return;
			}
			loadersCount[elem] = 1;
			var zIndex = $(this).elemZIndex();
			loaders[elem] = $.loaderGetElem()
				.appendTo('body')
				.css({
					left: $(this).offset().left,
					top: $(this).offset().top,
					width: $(this).outerWidth(),
					height: $(this).outerHeight(),
					zIndex: zIndex>0 ? zIndex + 1 : 999
				});
		});
	};

	/**
	* Hide loader on elements.
	*/
	$.fn.loaderHide = function() {
		return this.each(function() {
			var elem = $(this).get(0);
			if($.isNumber(loadersCount[elem]) && loadersCount[elem] > 1) {
				-- loadersCount[elem];
				return;
			} else {
				loadersCount[elem] = 0;
				if($.isSet(loaders[elem])){
					$(loaders[elem]).remove();
				}
				delete loaders[elem];
			}
		});
	};

	/**
	* Hide all loaders on element.
	*/
	$.fn.loaderHideAll = function() {
		var elem = $(this).get(0);
		if($.isSet(loaders[elem])){
			$(loaders[elem]).remove();
		}
		delete loaders[elem];
		delete loadersCount[elem];
	}



	/**
	* Replacement for jQuery ajax method.
	* @param object options ajax method options, same as for jQueryAjax. Additional parameters:
	* @param string errorMsg message shown when request or response parsing fails or when error status is send by backend
	*/
	$.fn.elAjax = function(options, errorMsg) {
		var loaderElems = this;

		if(options == null || ! $.isObject(options)) {
			options = {};
		}

		$(loaderElems).loaderShow();

		var showFunc = function(data, textStatus, callback){
			if (data.status == AJAX_ERROR)	{
				var error = errorMsg;
				if (data.errors) {
					error = $.merge([error], data.errors);
				}
				options.error(null, null, error, data);
			} else {
				if (callback != null)	{
					callback(data, textStatus);
				}
			}
			$(loaderElems).loaderHide();
		};
		if($.isFunction(options.success)) {
			var oldSuccessFunc = options.success;
			options.success = function(data, textStatus) {
				showFunc(data, textStatus, oldSuccessFunc);
			}
		} else {
			options.success = function(data, textStatus) {
				showFunc(data, textStatus);
			}
		}

		var errorFunc = function() {
			$(loaderElems).loaderHide();
		}
		if($.isFunction(options.error)) {
			var oldErrorFunc = options.error;
			options.error = function(request, status, error, data) {
				oldErrorFunc(request, status, error, data);
				errorFunc();
			}
		} else {
			options.error = errorFunc;
		}

		return $.ajax(options);
	};
})(jQuery);
