if(!Array.prototype.push) {
	Array.prototype.push = function() {
		var startLength = this.length;
		for (var i = 0; i < arguments.length; i++)
			this[startLength + i] = arguments[i];
		return this.length;
	}
};
if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {
  i || (i = 0);
  var length = this.length;
  if (i < 0) i = length + i;
  for (; i < length; i++)
    if (this[i] === item) return i;
  return -1;
};

if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) {
  i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
  var n = this.slice(0, i).reverse().indexOf(item);
  return (n < 0) ? n : i - n - 1;
};

if(!Array.prototype.remove) {
	Array.prototype.remove = function(pos) {
		if(isNaN(pos) || pos < 0 || pos >= this.length) return false;
		for(var i=0, n=0; i<this.length; i++)
			if(i!=pos) this[n++] = this[i];
		this.length -= 1;
   };
};

if(!Function.prototype.apply) {
	Function.prototype.apply = function(object, parameters) {
		var parameterStrings = new Array();
		if(!object) object = window;
		if(!parameters) parameters = new Array();
		for (var i = 0; i < parameters.length; i++)
			parameterStrings[i] = 'parameters[' + i + ']';
		object.__apply__ = this;
		var result = eval('object.__apply__(' +  parameterStrings.join(', ') + ')');
		object.__apply__ = null;
		return result;
	}
};

Vivieb = {};

(function($){
	
	$.vv_bind = function(method, object) {
		return function() {
			return method.apply(object, arguments);
		}
	};

	$.vv_camelize = function(str) {
		if(!str) return;
		var splitted = str.split('-');
		var rslt = splitted[0];
		for(var i=1, ln=splitted.length; i<ln; i++) {
			var s = splitted[i];
			rslt += s.charAt(0).toUpperCase() + s.substring(1);
		}
		return rslt;
	};
	
	$.vv_endWith = function(str, end) {
		if(!str) return;
		return str.charAt(str.length-1) == end;
	};
	
	/**
	 * @method vv_exception
	 * 	triggers a formatted exception. The message can be specified by
	 * 	a property in the object referenced by the "exception" property
	 * 	in the "impl" property object of the instance passed as the
	 * 	"object" argument. The message can also be specified by the
	 * 	message property of the exception parameter and	appended to 
	 * 	object.impl.exception[name], if defined.
	 * 	The resulting message can also contain placeholders like "{n}" 
	 * 	with n starting from 0. All the placeholder with n=0 will be
	 * 	replaced with the third parameter to this method, all the 
	 * 	placeholder with n=1 will be replaced with the fourth parameter
	 *  to this method, and so on. 
	 * 
	 * @param {Object} object
	 * 	the instance from which the exception is generated. The object
	 * 	should define the toString method to identify itself.
	 * 
	 * @param {Object} exception
	 * 	object that rappresent the exception. It can have these properties:
	 * 		name {string}:
	 *  		the name of the exception. If specified, the method search 
	 *  		for a  property "name" in the "object.impl.exception" object 
	 *  		and it will use its value to format the exception message.
	 *  
	 * 		message {string}: 
	 * 			the message of the exception. If object define a 
	 * 			"impl.exception" property, this message will be appended to 
	 * 			impl.exception[name].
	 */
	$.vv_exception = function(object, exception) {
		var msg = (exception.name && object.impl && object.impl.exception 
			&& object.impl.exception[exception.name]) || '';
		if(msg && exception.message)
			msg += '\n\n';
		msg += exception.message || '';
		for(var i=0; msg.indexOf('{' + i + '}') != -1; i++)
			msg.replace(new RegExp('{' + i + '}','gm'), arguments[i+2] || '');
		msg = 'Object: ' + object + '\n\n' + msg;
		throw {name: name || '', message: msg};
	};

	
	$.vv_getCSSObject = function(cssString) {
		if(!cssString) return {};
		var cssObject = {};
		var styles = cssString.split(';');
		for(var i=0, ln=styles.length; i<ln; i++) {
			var style = styles[i].split(':');
			if(style.length == 2) {
				var styleName = $.trim(style[0]);
				styleName = styleName == 'float' ? $.styleFloat : $.vv_camelize(styleName);
				if(styleName) cssObject[styleName] = $.trim(style[1]);
			}
		}
		return cssObject;
	};
	
	$.vv_getArrayFromSerialization = function(serializedString) {
		var rslt = [];
		if(serializedString) {
			var properties = serializedString.split('&');
			for(var i=0, ln=properties.length; i<ln; i++) {
				var property = properties[i].split('=');
				if(property.length == 2) {
					rslt.push({
						name: $.trim(property[0]),
						value: $.trim(property[1])
					});
				}
			}
		}
		return rslt;
	};

	
	$.vv_getInteger = function(number, defaultValue) {
		number = parseInt(number);
		if(isNaN(number))
			number = parseInt(defaultValue);
		return number;
	};
	
	$.vv_roundToDecimal = function(number, decimals, upper) {
		
		if(upper == undefined)
			upper = true;
			
		var factor = Math.pow(10, decimals);
		
		number = number * factor;
		number = Math.floor(number + (upper ? 0.5 : 0) );
		number = number/factor;
		
		return number;
			
		
	}

	$.vv_addUniqueItem = function(array, keyName, item) {
		var idx = $.vv_indexOfKey(array, keyName, item[keyName]);
		if(idx != -1)
			array[idx] = item;
		else
			array.push(item);
	};
	
	$.vv_getItem = function(array, keyName, keyValue) {
		if(isNaN(array.length))
			return null; 
		for(var i=0, ln=array.length; i<ln; i++)
			if(array[i][keyName]==keyValue)
				return array[i];
		return null;
	};

	$.vv_indexOfKey = function(array, keyName, keyValue) {
		if(isNaN(array.length))
			return -1; 
		for(var i=0, ln=array.length; i<ln; i++)
			if(array[i][keyName]==keyValue)
				return i;
		return -1;
	};
	
	$.vv_removeItem = function(array, item) {
		for(var i=0, ln=array.length; i<ln; i++)
			if(array[i]==item) {
				array.remove(i);
				break;
			}
	};
	
	$.vv_getOuterWidth = function(el) {
		var outerWidth = 0;
		var size = parseInt(el.css('margin-left'));
		if(!isNaN(size))
			outerWidth += size;
		size = parseInt(el.css('border-left-width'));
		if(!isNaN(size))
			outerWidth += size;
		size =  parseInt(el.css('padding-left'));
		if(!isNaN(size))
			outerWidth += size;
		size = parseInt(el.css('width'));
		if(!isNaN(size))
			outerWidth += size;
		size = parseInt(el.css('padding-right'));
		if(!isNaN(size))
			outerWidth += size;
		size = parseInt(el.css('border-right-width'));
		if(!isNaN(size))
			outerWidth += size;
		size = parseInt(el.css('margin-right'));
		if(!isNaN(size))
			outerWidth += size;
		return outerWidth;
	};
	
	$.vv_getOuterHeight = function(el) {
		var outerHeight = 0;
		var size = parseInt(el.css('margin-top'));
		if(!isNaN(size))
			outerHeight += size;
		size = parseInt(el.css('border-top-width'));
		if(!isNaN(size))
			outerHeight += size;
		size =  parseInt(el.css('padding-top'));
		if(!isNaN(size))
			outerHeight += size;
		size = parseInt(el.css('height'));
		if(!isNaN(size))
			outerHeight += size;
		size = parseInt(el.css('padding-bottom'));
		if(!isNaN(size))
			outerHeight += size;
		size = parseInt(el.css('border-bottom-width'));
		if(!isNaN(size))
			outerHeight += size;
		size = parseInt(el.css('margin-bottom'));
		if(!isNaN(size))
			outerHeight += size;
		return outerHeight;
	};

	$.vv_tryThese = function () {
		var result;
		for(var i=0; i<arguments.length; i++) {
			try {
				result = arguments[i]();
				break;
			} catch (e) {}
		}
		return result;
	};	
	
	
/**
		 * @param selector {string}
		 *		the jquery selector of the elements which this method operates on
		 *		based on a comparison result.
		 * @param element {DOM Element}
		 *		DOM element that provides the first operand 
		 *		of the comparison as one of its attributes.
		 * @param value {any}
		 *		the value that that is the second operand 
		 *		of the comparison.
		 * @param {Object} options
		 *	options of the comparison. Expected options are:
		 *	attribute {string}	
		 *		the name of the element attribute that is the first operand 
		 *		of the comparison.
		 *		Default: 'value'
		 *	display {boolean}
		 *		indicates that elements selected by selector must be displayed if
		 *		undefined	: no effect
		 *		true		: element.attribute == value; hidden oterwhise.
		 *		false		: element.attribute != value; hidden oterwhise.
		 *	disabled {boolean}
		 *		indicates that elements selected by selector must be disabled if
		 *		undefined	: no effect
		 *		true		: element.attribute == value; enabled oterwhise.
		 *		false		: element.attribute != value; enabled oterwhise.
		 *	callback {function}
		 *		called at the end of the performed operations. 
		 *		The callback has the following firm:
		 *
		 *			function callback(jElem, displayed, enabled) { //this=element }
		 *
		 *		where:
		 *			- jElem	{jQuery}		: selected elements 
		 *			- displayed {boolean}	: true, if the selected elements have been displayed
		 *			- enabled {boolean}		: true, if the selected elements have been enabled
		 *
		 */	 
	$.vv_setBasedOn = function(selector, element, value, options) {
		var jElems = $(selector);
		if(!element || !jElems.length)
			return;
		var result = element[options.attribute || 'value'] == value;	
		if(options.display != undefined) {
			var displayed = options.display ? result : ! result;
			jElems.css('display', displayed ? '' : 'none');
		}
		if(options.disabled != undefined) {
			var disabled = options.disabled ? result : ! result;
			jElems.attr('disabled', disabled);
		}
		if($.isFunction(options.callback))
			options.callback.call(element, jElems, displayed, disabled);
	};
	
	/**
	 * Gets the URL to the subscribe procedure passing a pre-selected plan
	 * corresponding to the planCode parameter.
	 * 
	 * @param {string} defPlanGroupAbbr
	 * 	abbr field value of the first plan group that must be selected
	 * 	in the selection plan process.
	 * 	If null, a new user can select though all the available user
	 * 	types.
	 * 	If not null, the user type of a new account is fixed to the
	 * 	default user type associated to the plan group 
	 * @param {string} defPlanAbbr
	 * 	abbr field value of the first plan to display in the selection
	 * 	plan process.
	 * @param {string | string[]} planGroupAbbrs
	 * 	abbr field value of the plan group id which the creator can choose
	 * 	a plan from. The parameter can have several values. All the
	 * 	indicated plan group will be available in the selection plan
	 * 	process.
	 * 	If null, all the plan groups having the same ContactType of
	 * 	the reference user will be available.
	 * @param {string} baseURL (optional)
	 * This function assumes that the subscribe procedure starts in the
	 * page with '/web/guest/registration' as friendly url. 
	 * If not, set the baseURL parameter with the correct value.
	 * Indicates the entire URL if the domain is different. 
	 */
	
	$.vv_subscribePlan = function(defPlanGroupAbbr, defPlanAbbr, planGroupAbbrs, baseURL) {
		
		var url = baseURL || '/web/guest/registration';
		
		var params = {
			p_p_id						: 'registration',
			p_p_lifecycle				: '0',
			p_p_mode					: 'view',
			p_p_state					: 'normal',
			_registration_struts_action	: '/ext/registration/wizard',
			_registration_processType	: '2'
		}
		if(defPlanGroupAbbr)
			params._registration_defPlanGroupAbbr = defPlanGroupAbbr;
		if(defPlanAbbr)
			params._registration_defPlanAbbr = defPlanAbbr;
		url =  Liferay.Util.addParams(params, url);
		if(planGroupAbbrs) {
			if(!planGroupAbbrs.length)
				planGroupAbbrs = [planGroupAbbrs];
			for(var i=0, ln=planGroupAbbrs.length; i<ln; i++)
				url =  Liferay.Util.addParams({
						planGroupAbbr: planGroupAbbrs[i]
					}
					, url);
		}
		location.href =  Liferay.Util.addParams(params, url);
	};
	
	
	/**** Wrapped set commands */

	/**
	 * 
	 * @method vv_insert
	 * 	insert the elements in the wrapped set in respect to the 
	 * 	"target" element.
	 * 
	 * @param {DOM object, string} target
	 * 	the HTML element that will be refered to insert the elements. 
	 * 	It can be a DOM object reference or a valid jQuery selector.
	 * 	If more than one target are found with a jQuery selector, only
	 * 	the first one will be the target.
	 * 
	 * @param {string} position:
	 * 	the position where to insert the elements in respect to the 
	 * 	"target" element. It can be one of these values:
	 * 		"prepend":	elements will be inserted before the content 
	 * 					of "target".
	 * 		"append":	elements will be inserted after the content 
	 * 					of "target".
	 * 		"before":	elements will be inserted before "target".
	 * 		"after":	elements will be inserted after "target". 
	 * 	Default: "append"
	 * 
	 */
	$.fn.vv_insert = function(target, position) {
		
		target = jQuery(target);
		if(target.length == 0)
			throw {name: 'vv_insert_exception', message: 'target element not found!'};
		
		switch(position) {
			case 'prepend': return this.prependTo(target.get(0));
			case 'append': return this.appendTo(target.get(0));
			case 'before': return this.insertBefore(target.get(0));
			case 'after': return this.insertAfter(target.get(0));
			default: return this.appendTo(target.get(0));
		}
	};

    $.fn.vv_makePositioned = function() {
        return this.each(function() {
			var style = this.style;
			if(!style.position || style.position == 'static') {
				style.position = 'relative';
				// Opera returns the offset relative to the positioning context, when an
				// element is position relative but top and left have not been defined
	            if(window.opera) {
					style.top = 0;
					style.left = 0;
	            }
	        }   
        });
    };
/*	
	$.fn.vv_setTotalWidth = function(totalWidth) {
		
		if ($.boxModel)
			return this.each(function() {
				var el = $(this);
				var outerWidth = 0;
				var size = parseInt(el.css('margin-left'));
				if(!isNaN(size))
					outerWidth += size;
				size = parseInt(el.css('border-left-width'));
				if(!isNaN(size))
					outerWidth += size;
				size =  parseInt(el.css('padding-left'));
				if(!isNaN(size))
					outerWidth += size;
				if(!isNaN(size))
					outerWidth += size;
				size = parseInt(el.css('padding-right'));
				if(!isNaN(size))
					outerWidth += size;
				size = parseInt(el.css('border-right-width'));
				if(!isNaN(size))
					outerWidth += size;
				size = parseInt(el.css('margin-right'));
				if(!isNaN(size))
					outerWidth += size;
				el.width(parseInt(totalWidth - outerWidth));
			});
		
		return this.each(function() {
			var el = $(this);
			var outerWidth = 0;
			var size = parseInt(el.css('margin-left'));
			if(!isNaN(size))
				outerWidth += size;
			size = parseInt(el.css('margin-right'));
			if(!isNaN(size))
				outerWidth += size;
			el.width(parseInt(totalWidth - outerWidth));
		});
	};
	
	$.fn.vv_setTotalHeight = function(totalHeight) {

		if ($.boxModel)
			return this.each(function() {
				var el = $(this);
				var outerHeight = 0;
				var size = parseInt(el.css('margin-top'));
				if(!isNaN(size))
					outerHeight += size;
				size = parseInt(el.css('border-top-width'));
				if(!isNaN(size))
					outerHeight += size;
				size =  parseInt(el.css('padding-top'));
				if(!isNaN(size))
					outerHeight += size;
				size = parseInt(el.css('padding-bottom'));
				if(!isNaN(size))
					outerHeight += size;
				size = parseInt(deserializeel.css('border-bottom-width'));
				if(!isNaN(size))
					outerHeight += size;
				size = parseInt(el.css('margin-bottom'));
				if(!isNaN(size))
					outerHeight += size;
				el.height(parseInt(totalHeight - outerHeight));
			});		

		return this.each(function() {
			var el = $(this);
			var outerHeight = 0;
			var size = parseInt(el.css('margin-top'));
			if(!isNaN(size))
				outerHeight += size;
			size = parseInt(el.css('margin-bottom'));
			if(!isNaN(size))
				outerHeight += size;
			el.height(parseInt(totalHeight - outerHeight));
		});
	};
*/	
	/**
	 * deserialize from form serialization (form.js)
	 */
	$.fn.vv_deserialize = function(d,config) {
		var data= d;
		me  = this;

		if (d === undefined) {
			return me;
		}

		config = $.extend({ isPHPnaming	: false,
							overwrite	: true},config);
		
		// check if data is an array, and convert to hash, converting multiple entries of 
		// same name to an array
		if (d.constructor == Array)	{
			data={};
			for(var i=0; i<d.length; i++) {
				if (typeof data[d[i].name] != 'undefined') {
					if (data[d[i].name].constructor!= Array) {
						data[d[i].name]=[data[d[i].name],d[i].value];
					} else {
						data[d[i].name].push(d[i].value);
					}
				} else {
					data[d[i].name]=d[i].value;
				}
			}
		}

		// now data is a hash. insert each parameter into the form
		$('input,select,textarea',me)
		.each(function() {
				  var p=this.name;
				  var v = [];
				  
				  // handle wierd PHP names if required
				  if (config.isPHPnaming) {
					  p=p.replace(/\[\]$/,'');
				  }
				  if(p && data[p] != undefined) {
					  v = data[p].constructor == Array ? data[p] : [data[p]];
				  }
				  // Additional parameter overwrite
				  if (config.overwrite === true || data[p]) {
					  switch(this.type || this.tagName.toLowerCase()) {
					  case "radio":
					  case "checkbox":
						  this.checked=false;
						  for(var i=0;i<v.length;i++) {
							  this.checked|=(this.value!='' && v[i]==this.value);
						  }
						  break;
					  case "select-multiple" || "select":
						  for( i=0;i<this.options.length;i++) {
							  this.options[i].selected=false;
							  for(var j=0;j<v.length;j++) {
								  this.options[i].selected|=(this.options[i].value!='' && this.options[i].value==v[j]);
							  }
						  }
						  break;
					  case "button":
					  case "submit":
						  this.value=v.length>0?v.join(','):this.value;
							  break;
					  default:
						  this.value=v.join(',');
					  }
				  }
			  });
		return me;
	};
	
	$.fn.vv_setTotalWidth = function(totalWidth) {
		return this.each(function() {
			var el = $(this);
			var extraWidth = el.outerWidth(true) - el.width();
			el.width(parseInt(totalWidth, 10) - extraWidth);
		});
	};

	$.fn.vv_setTotalHeight = function(totalHeight) {
		return this.each(function() {
			var el = $(this);
			var extraHeight = el.outerHeight(true) - el.height();
			el.height(parseInt(totalHeight, 10) - extraHeight);
		});
	};

	$.fn.vv_fadeIn = function(speed, callback) { 
	    return this.animate({opacity: 'show'}, speed, function() { 
	        if (jQuery.browser.msie)  
	            this.style.removeAttribute('filter');  
	        if (jQuery.isFunction(callback)) 
	            callback();  
	    }); 
	}; 
	 
	$.fn.vv_fadeOut = function(speed, callback) { 
	    return this.animate({opacity: 'hide'}, speed, function() { 
	        if (jQuery.browser.msie)  
	            this.style.removeAttribute('filter');  
	        if (jQuery.isFunction(callback)) 
	            callback();  
	    }); 
	}; 
	 
	$.fn.vv_fadeTo = function(speed,to,callback) { 
	    return this.animate({opacity: to}, speed, function() { 
	        if (to == 1 && jQuery.browser.msie)  
	            this.style.removeAttribute('filter');  
	        if (jQuery.isFunction(callback)) 
	            callback();  
	    }); 
	};
	
	$.fn.displayFields = function(display) {
		return this.each(function() {
			$(this).css('display', display ? '' : 'none')
				.find('.field').attr('disabled', !display);
		});
	};
		
	$.fn.hideFields = function() {
		return this.each(function() {
			$(this).css('display', 'none')
				.find('.field').attr('disabled', true);
		});
	};
			
	$.fn.showFields = function() {
		return this.each(function() {
			$(this).css('display', '')
				.find('.field').attr('disabled', false);
		});
	};
		
})(jQuery);