
// Utility functions
function _arguments(args) {
	return Array.prototype.slice.apply(args, [0]);
}

function _bind(obj, fn) {
	return function() {
		return fn.apply(obj, _arguments(arguments).concat([this]));
	}
}

// Form-utility functions
function split_fields(name) {
	return name.split("-");
}

function join_fields(args) {
	var names = Array.prototype.slice.call(arguments, 0);
	return names.join("-");
}

// Generic field object
var Field = Class.create({
	__init: function(options) {
		this.options = options || {};
		if (this.options.choices) {
			this.choices = this.options.choices;
		}
	}
});

// BoundField is a field associated with a form and a name
var BoundField = Class.create({
	__init: function(form, field, name) {
		this.form = form;
		this.field = field;
		this.name = name;
	},
	html_name: function() {
		return this.form.add_prefix(this.name);
	},
	auto_id: function() {
		return "id_" + this.form.add_prefix(this.name);
	}
});

var Form = Class.create({
	__init: function(options) {
		if (!this.fields)
			this.fields = {};
		this.options = options || {};
		if (this.options.prefix)
		    this.prefix = this.options.prefix;
	},
	get_field: function(name) {
		if (this.fields[name])
			return BoundField(this, this.fields[name], name)
	},
	add_prefix: function(name) {
		if (this.options.prefix)
			return join_fields(this.options.prefix, name);
		else
			return name;
	}
}, {
	construct: function(spec, data, prefix) {
		data = data || {};
		var outform = {};
		for (var key in spec) {
			outform[key] = {
				"field": spec[key],
				"data": data[key]
			};
			if (typeof(prefix) == "string" && prefix.length > 0) {
				outform[key]["html_name"] = prefix + "-" + key;
				outform[key]["auto_id"] = "id_" + prefix + "-" + key;
			} else {
				outform[key]["html_name"] = key;
				outform[key]["auto_id"] = "id_" + key;
			}
		}
		return outform;
	}
});

var FormSet = Class.create({
	__init: function(prefix, selector, template) {
		this.selector = selector;
		
		if (typeof template == "string")
			template = Template.Cache[template];
		this.template = template;
		
		this.prefix = prefix;
		this.total_forms_count = null;
		this.initial_forms_count = null;
		
		this.forms = [];
	},
	add_prefix: function(name) {
		if (this.prefix)
			return join_fields(this.prefix, name);
		else
			return name;
	},
	prepare: function() {
		//jQuery("*[name^='"+this.prefix+"']").each(_bind(this, this.prepare_row));
		jQuery("*[name^='"+this.prefix+"']").each(_bind(this, this.prepare_row));
	},
	prepare_row: function(e, target) {
		var name = jQuery(target).attr("name");
		var suffix = name.substr(this.prefix.length + 1);
		
		if (suffix == "TOTAL_FORMS") {
			this.total_forms_count = jQuery(target).val()
		} else if (suffix == "INITIAL_FORMS") {
			this.initial_forms_count = jQuery(target).val();
		} else if (suffix.match(/^(\d+)/)) {
			var index = suffix.match(/^(\d+)/)[0];
			this.forms.push(index);
		} else {
			alert("Error");
		}
	},
	register_listeners: function() {
	},
	register_row_listeners: function() {
	},
	update_info: function(total_forms_count, initial_forms_count) {
	},
	append: function(context) {
		var $total_forms_field = jQuery("input[name='" + this.prefix + "-TOTAL_FORMS']");
		var index = parseInt($total_forms_field.val());
		$total_forms_field.val(index + 1);
		
		var form = this.form_class({ prefix: this.add_prefix(index) });
		
		context = context || {};
		if (!context.form) {
			context.form = {
				prefix: form.prefix, //this.add_prefix(index),
				index: index
			}
			for (var name in form.fields)
				context.form[name] = form.get_field(name);
		}
		//var html = this.template.render(context);
		var $item = jQuery(this.template.render(context));
		var $list = jQuery(this.selector);
		$list.append($item);
		this.register_row_listeners($list);
	},
	_append_trigger: function(e, target) {
		e.preventDefault();
		e.stopPropagation();
		this.append();
	},
	_delete_trigger: function(e, target) {
		e.preventDefault();
		e.stopPropagation();
		var $row = this._get_form_jQuery(target);
		$row.find("[name$=DELETE]").val("delete");
		$row.hide();
	},
	each_form: function(fn) {
		var ret = [];
		for (var i=0; i<this.forms.length; i++) {
			var form = info.forms[i];
			var prefix = info.prefix + "-" + i;
			var $inputs = jQuery("*[name^='" + prefix + "']");
			var $row = $inputs.parents("tr").eq(0);
			
			$inputs.each(function() {
				var name, basename;
				name = jQuery(this).attr("name");
				basename = name.substr(prefix.length);
				form[basename] = jQuery(this).val();
			});
			ret.push(fn(info, i));
		}
		return ret;
	}
});
