/**
 * Transform a posix regexp to a perl (javascript) regular expression
 * 
 * @param pattern String POSIX regular expression
 * @return String Perl regular expression
 */
jQuery.posixToPerlRegExp = function(pattern) {
	var replaceToParenthesePatterns = [ /(\)\))/i, /(\)\)\?)/i ];
	var replaceToSlashPatterns =      [ /(\\\/)/i  ];
	var replaceToEmptyPatterns =      [
	                                    /(#\^)/i,
	                                    /(#)/i,
	                                    /(\(.:)/i,
	                                    /(\?)/i
	                                  ];
	
	var cleanedPattern = pattern;
	jQuery(replaceToEmptyPatterns).each(function() {
		while (cleanedPattern.match(this)) {
			cleanedPattern = cleanedPattern.replace(this, '');	
		}
	});
	
	jQuery(replaceToParenthesePatterns).each(function() {
		while (cleanedPattern.match(this)) {
			cleanedPattern = cleanedPattern.replace(this, ')');	
		}
	});
	
	jQuery(replaceToSlashPatterns).each(function() {
		while (cleanedPattern.match(this)) {
			cleanedPattern = cleanedPattern.replace(this, '/');	
		}
	});
	return cleanedPattern;
};


/**
 * Transform Object to a PHP GET parameters (with hook for subparameters)
 * example:
 * {
 *   foo: 'bar',
 *   toto: {
 *     tutu: 'tata'
 *   },
 *   toto2: [
 *     tutu2: 10
 *   ]
 * }
 * result:  foo=bar&toto[tutu]=tata&toto2[tutu2]=10
 * 
 * @param data Object object to serialize
 * @param prefix String prefix all parameters (option)     
 * @return string object serialized in url string 
 * 
 */
jQuery.urlSerialized = function(data, prefix) {
	var query = new Array();
	var subquery = new Array();
	var hasPrefix = prefix !== undefined;
	
	for (var value in data) {
		if (typeof data[value] === 'object') {
			var extPrefix = hasPrefix ? prefix + '[' + value + ']' : value;
			jQuery.merge(query, jQuery.urlSerialized(data[value], extPrefix));
		}
		else {
			query.push(( hasPrefix ? prefix + '[' : '') + value + ( hasPrefix ? ']' : '') + '=' + data[value]);
		}
	}
	
	return query;
};


/**
 * Execute method at DOM ready and after an ajax call
 */
jQuery.fn.readyOrAfterAjax = function(method) {
	jQuery(this).ready(method);
	jQuery(this).ajaxStop(method);
};

/**
 * FIXME Needs to be tested
 * Add a remove event. An action can be triggered when an item is removed
 * Example:
 * $('#some-element').bind('remove', function() {
 *     console.log('removed!');
 *     // do pre-mortem stuff here
 *     // 'this' is still a reference to the element, before removing it
 * });
 * 
 * // some other js code here [...]
 * 
 * $('#some-element').remove();
 */
/*
(function() {
	var ev = new jQuery.Event('remove');
	var orig = jQuery.fn.remove;
	jQuery.fn.remove = function() {
		jQuery(this).trigger(ev);
		orig.apply(this, arguments);
	}
})();

(function(hasClass) {
	jQuery.fn.hasClass = function hasClassRegExp(value) {
		if (value && typeof value.test === "function") {
			for (var i = 0, l = this.length; i < l; i++) {
				var classNames = this[i].className.split(/\s+/);
				for (var c = 0, cl = classNames.length; c < cl; c++) {
					if (value.test(classNames[c])) {
						return true;
					}
				}
			}
			return false;
		}
		else {
			return hasClass.call(this, value);
		}
	}
})(jQuery.fn.hasClass);

(function(removeClass) {
	jQuery.fn.removeClass = function(value) {
		if (value && typeof value.test === "function") {
			for (var i = 0, l = this.length; i < l; i++) {
				var elem = this[i];
				if (elem.nodeType === 1 && elem.className) {
					var classNames = elem.className.split(/\s+/);
					for (var n = classNames.length; n--;) {
						if (value.test(classNames[n])) {
							classNames.splice(n, 1);
						}
					}
					elem.className = jQuery.trim(classNames.join(" "));
				}
			}
		}
		else {
			removeClass.call(this, value);
		}
	}
})(jQuery.fn.removeClass);
*/

/**
 * Implement method to store data in a DOM Element
 * All values are stored in an attribute named "bs"
 */

/**
 * Private: used to retrieve object for storing 
 * first element of a jQuery() collection or element himself if uniq
 */
jQuery.fn.getAllBsData = function() {
	var data = jQuery(this).data('bs');
	
	if (!data || typeof data != 'object'){
		data = {};
		jQuery(this).data('bs', data);
	}
	return data;
}


/**
 * Set custom brainsonic attribute to a DOM Element
 * 
 * @param String name attribute name
 * @param All value 
 */
jQuery.fn.setBsData = function(name, value) {
	var storage = jQuery(this).getAllBsData();
	storage[name] = value;
	jQuery(this).data('bs', storage);
};


/**
 * Get custom brainsonic attribute to a DOM Element
 * 
 * @param String name attribute name
 * @return All type of value
 */
jQuery.fn.getBsData = function(name) {
	var storage = jQuery(this).getAllBsData();
	return storage ? storage[name] : undefined;
};


/**
 * Remove a custom brainsonic attribute
 * 
 * @param String name attribute name
 * @return Boolean
 */
jQuery.fn.removeBsData = function(name) {
	var removed = false;
	var storage = jQuery(this).getAllBsData();
	if (storage[name] != undefined) {
		delete storage[name];
		jQuery(this).data('bs', storage);
		removed = true;
	}
	return removed;
};


/**
 * Know if DOM Element has custom brainsonic attribute 
 * 
 * @param String name attribute name
 * @return Boolean
 */
jQuery.fn.hasBsData = function(name) {
	return jQuery(this).getBsData(name) == undefined ? false : true;
};

