;(function($) {
	if (typeof($.fn.elementsCloner) != "undefined")
		return ;
		
	var ElementsCloner = function(el, options, data) {
			this.el = $(el);
			this.options = $.extend({}, options || {});
			
			this.init();
			if (data == null) {
				for (var i = 0; i < this.options.defaultItemCount; i++)
					this.addItem(null, true);
			} else {
				for (var i = 0; i < data.length; i++)
					this.addItem(data[i], true);
			}
			
			this.reInitItems();
		},
		TEMPLATE_ITEM_CLASS = "__ec-template-item";
	
	ElementsCloner.prototype = {
		constructor: ElementsCloner,
		
		get: function(key) {
			return this.options[key];
		},
		
		getMessage: function(key) {
			return this.options.message[key];
		},
		
		init: function() {
			var opt = this.options,
				self = this;
		
			this.getTemplate().hide();

			$(this.get("addItemSelector"), this.el).click(function() {
				self.addItem();
				
				return false;
			});
			
			$(this.get("removeAllSelector"), this.el).click(function() {
				self.removeAll();
				
				return false;
			});
		},
		
		initItem: function(item) {
			var self = this;

			item.find(this.get("removeItemSelector")).click(function() {
				self.removeItem(this);
				
				return false;
			});
			
			item.find(this.get("upItemSelector")).click(function() {
				self.upItem(this);
				
				return false;
			});
			
			item.find(this.get("downItemSelector")).click(function() {
				self.downItem(this);
				
				return false;
			});
		},
		
		reInitItems: function() {
			var items = this.el.find("." + TEMPLATE_ITEM_CLASS),
				self = this;
			if (items.length > 0) {
				items.removeClass(this.get("firstItemClass")).removeClass(this.get("lastItemClass"));
				$(items[0]).addClass(this.get("firstItemClass"));
				$(items[items.length - 1]).addClass(this.get("lastItemClass"));
			}
			
			if (this.get("enableNumFormat")) {
				var numSelector = this.get("numSelector"),
					numFormat = this.get("numFormat"); 
				items.each(function(i) {
					$(this).find(numSelector).html(numFormat.replace("#{$num}", i + 1));
				});
			}
			
			this.el.trigger("reInitItem");
		},
		
		addItem: function(data, silent) {
			data = data || null;
			silent = silent || false;

			var template = this.getTemplate(),
				templateClone = template.clone().removeClass(this.get("templateClass")).addClass(TEMPLATE_ITEM_CLASS).show(),
				lastItem = this.el.find("." + TEMPLATE_ITEM_CLASS + ":last").get(0);

			(lastItem ? $(lastItem) : template).after(templateClone);
			this.initItem(templateClone);

			if (data && typeof(data) == "object") {
				var keyField = this.get("keyField"),
					id = typeof(data[keyField]) != "undefined" ? data[keyField] : null;

				for (var dataKey in data) {
					var elKey = this.get("itemPrefix") + dataKey;
					this.setElValue(templateClone.find("." + elKey), data[dataKey], id);
				}
			}

			if (!silent)
				this.reInitItems();
		},
		
		removeItem: function(el, silent) {
			silent = silent || false;
		
			if (!silent && !confirm(this.getMessage("removeConfirm")))
				return false;
		
			$(el).closest("." + TEMPLATE_ITEM_CLASS).remove();
			this.reInitItems();
			
			return true;
		},
		
		removeAll: function(silent) {
			silent = silent || false;
		
			if (!silent && !confirm(this.getMessage("removeAllConfirm")))
				return false;
			
			this.el.find("." + TEMPLATE_ITEM_CLASS).remove();
			this.el.trigger("removeAll");

			return true;
		},
		
		upItem: function(el) {
			var item = $(el).closest("." + TEMPLATE_ITEM_CLASS),
				swapItem = item.prev();
			if (!swapItem || !swapItem.hasClass(TEMPLATE_ITEM_CLASS))
				return false;
	
			item.detach();
			swapItem.before(item);
			
			this.reInitItems();

			return true;
		},
		
		downItem: function(el) {
			var item = $(el).closest("." + TEMPLATE_ITEM_CLASS),
				swapItem = item.next();
			if (!swapItem || !swapItem.hasClass(TEMPLATE_ITEM_CLASS))
				return false;
	
			item.detach();
			swapItem.after(item);
			
			this.reInitItems();

			return true;
		},
		
		getTemplate: function() {
			if (typeof (this._template) == "undefined") {
				this._template = $("." + this.get("templateClass"), this.el);
				$('ariselect', this._template).replaceWith(function () {
					var html = $(this)[0].outerHTML;
					return html ? $(html.replace(/<ariselect/i, '<select').replace(/<\/ariselect/i, '</select')) : html
				})
			}
			return this._template
		},

		getElKey: function(el) {
			var key = null,
				prefix = this.get("itemPrefix"),
				cssClass = el.attr("class"),
				pos = cssClass.indexOf(prefix);

			if (pos == -1)
				return key;
				
			var endPos = cssClass.indexOf(" ", pos);
			if (endPos == -1) endPos = cssClass.length;
			key = cssClass.substr(pos + prefix.length, endPos - pos - prefix.length);

			return key;
		},

		getElValue: function(el, id) {
			var val = null;
			
			if (el.is("INPUT[type=radio]")) {
				if (el.is(":checked")) {
					val = id;
				}
			} else {
				val = el.val();
			}
			
			return val;
		},

		setElValue: function(el, value, id) {
			if (!el) return false;
			
			id = id || null;
			
			if ($(el).is("INPUT[type=radio]")){
				if (id !== null && value == id)
					$(el).attr("checked", "checked")
			} else {
				$(el).val(value);
			}
			
			return true;
		},

		getData: function() {
			var data = [],
				self = this,
				keyField = this.get("keyField"),
				itemPrefix = this.get("itemPrefix"),
				keySelector = "." + itemPrefix + keyField;

			this.el.find("." + TEMPLATE_ITEM_CLASS).each(function() {
				var dataItem = {},
					id = self.getElValue($(keySelector, this));
				
				$(this).find(self.get("itemSelector")).each(function() {
					var el = $(this),
						key = self.getElKey(el);
					
					if (!key) return ;
					
					dataItem[key] = self.getElValue(el, id);
				});
				
				data.push(dataItem);
			});

			return data;
		}
	};
		
	$.fn.elementsCloner = function(options, data) {
		if (typeof(data) == "undefined")
			data = null;
		options = options || {};
		options["message"] = $.extend({
			"removeConfirm": "Are you sure you want to remove this item?",
			"removeAllConfirm": "Are you sure you want to remove all items?"
		}, options["message"] || {});
		options =  $.extend({
			firstItemClass: "ec-first-item",
			lastItemClass: "ec-last-item",
			templateClass: "ec-template",
			addItemSelector: ".ec-ctrl-add",
			removeItemSelector: ".ec-ctrl-remove",
			removeAllSelector: ".ec-ctrl-removeall",
			upItemSelector: ".ec-ctrl-up",
			downItemSelector: ".ec-ctrl-down",
			numSelector: ".ec-num",
			numFormat: "#{$num}.",
			itemPrefix: "ec-key-",
			itemSelector: ".ec-item",
			enableNumFormat: true,
			defaultItemCount: 3,
			keyField: null
		}, options);

		var widgets = [];
		this.each(function() {
			var cloner = new ElementsCloner(this, options, data);
			
			widgets.push(cloner);
		});
		
		return widgets.length == 1 ? widgets[0] : widgets;
	};
})(jQuery);