// represents a WplForm object on the client
WplForm = function (id, options) {
	if (typeof options == 'undefined') {
		options = {};
	}

	this._id = id;
	this._options = options;
	this._items = [];

	var thiss = this;

	var observer = function (event) {
		if (!thiss.check()) {
			thiss.updateDisplay();
			thiss.getErrorStrategy().drawFormErrorsubmit(thiss);

			Event.stop(event);
		}
	}

	Event.observe($(id + 'Form'), "submit", observer);
};
// get the error strategy object for this form
WplForm.prototype.getErrorStrategy = function () {
	if (typeof this._options.errorStrategy == 'undefined') {
		// This is the default one
		return WplForm.ErrorStrategies.ErrorArea;
	} else {
		return this._options.errorStrategy;
	}
}
// check all form items - returns boolean
WplForm.prototype.check = function () {
	var ret = true;
	for (var i = 0; i < this._items.length; i++) {
		ret = this._items[i].check() && ret;
	}
	return ret;
}
// add another item to the form
WplForm.prototype.addItem = function (item) {
	this._items.push(item);

	item._attachToParent(this);
}
// update the visual display of the entire form
WplForm.prototype.updateDisplay = function () {
	this.getErrorStrategy().drawFormErrors(this);
}
WplForm.prototype.getItem = function (name) {
	for (var i = 0; i < this._items.length; i++) {
		if (this._items[i].getName() == name) {
			return this._items[i];
		}
	}
	return null;
}


// represents a WplForm_Item on the client
WplFormItem = function (elId, name, initialErrors) {
	var el = $(elId);

	this._name = name;
	this._validators = [];
	this._isChecked = false;
	this._errors = initialErrors;
	this._el = el;

	if (el) {
		// Ugly, but means we can reference this object later.
		el.wplFormItem = this;
	}
};
// Attach to parent (called from parent)
WplFormItem.prototype._attachToParent = function (wplForm) {
	this._parentWplForm = wplForm;

	if (wplForm._options.updateOnElChange && this._el) {
		// Observer for when form item changes
		var thiss = this;
		var observer = function () {thiss.elChanged();};

		// Attach both usual observer and the prototype timed one
		new Form.Element.EventObserver(this._el, observer);
		Event.observe(this._el, "change", observer);
	}
}
// add a validator for this field
WplFormItem.prototype.addValidator = function (validator) {
	this._validators.push(validator);
}
// Check that this form item validates
//
// It returns the status, and updates the internal list of errors too.
// It does not change the display.
WplFormItem.prototype.check = function () {
	this._errors = [];
	for (var i = 0; i < this._validators.length; i++) {
		var validator = this._validators[i];
		var result = validator.validate(this);
		if (!result) {
			var error = validator.getMessage();
			this._errors.push(error);
		}
	}
	this._isChecked = true;
	return (this._errors.length == 0);
}
WplFormItem.prototype.getValue = function () {
	return Form.Element.getValue(this._el);
}
WplFormItem.prototype.getName = function () {
	return this._name;
}
WplFormItem.prototype.getId = function () {
	return this._parentWplForm._id + this._name;
}
WplFormItem.prototype.getErrors = function () {
	return this._errors;
}
// this form element has changed
WplFormItem.prototype.elChanged = function () {
	this.check();
	this._parentWplForm.updateDisplay();
}
WplFormItem.prototype.getParentWplForm = function () {
	return this._parentWplForm;
}

// Error strategies
//
// these hold strategies for displaying errors in the form.
WplForm.ErrorStrategies = {};
// a strategy for an "error area" at the top of the form.
WplForm.ErrorStrategies.ErrorArea = {};
// update the form with the current error status
WplForm.ErrorStrategies.ErrorArea.drawFormErrors = function (form) {
	// update the "errorArea" with a list of the errors:

	var out = "";

	for (var i = 0; i < form._items.length; i++) {
		var formItem = form._items[i];
		var errors = formItem.getErrors();
		for (var j = 0; j < errors.length; j++) {
			out += "<li>" + errors[j] + "</li>";
		}

		if (formItem._el && formItem._isChecked) {
			var errorEl = $(formItem._el.id + 'Fie');
			if (errorEl) {
				if (errors.length > 0) {
					Element.removeClassName(errorEl, "validatedGood");
					Element.addClassName(errorEl, "validatedBad");
				} else {
					Element.removeClassName(errorEl, "validatedBad");
					Element.addClassName(errorEl, "validatedGood");
				}
			}
		}
	}

	if (out.length > 0) {
		out = "Before you can continue you must correct:<ul>" + out + "</ul>";
	}

	var errorArea = $(form._id + "FormErrorArea");
	if (errorArea) {
		errorArea.innerHTML = out;
		}
};
WplForm.ErrorStrategies.ErrorArea.drawFormErrorsubmit = function (form) {
	if (typeof WplDialog != 'undefined') {
		WplDialog.openAlert("You must complete the form first!", 260);
	} else {
		alert("You must complete the form first");
	}
}


// This is what a WplFormValidator should look like:
//
//WplFormValidator = function () {
//
//}
//WplFormValidator.prototype.validate = function (value) {
//	alert("overide me!");
//}
//WplFormValidator.prototype.getMessage = function () {
//	alert("overide me!");
//}



WplFormValidators = {};

WplFormValidators.getValidator = function (name, params, message) {
	if (this.validators[name]) {
		var constructor = this.validators[name];

		return new constructor(params, message);
	} else {
		return null;
	}
}
WplFormValidators.tryAddValidator = function (formItem, name, params, message) {
	var validator = this.getValidator(name, params, message);
	if (validator) {
		// a valdiator exists - add it to the form item
		formItem.addValidator(validator);
	} else {
		// a validator hasn't been defined yet for this
	}
}

WplFormValidators.validators = {};

// doctrine_length validator
WplFormValidators.validators.doctrine_length = function (params, message) {
	this._message = message;
	this._params = params;
};
WplFormValidators.validators.doctrine_length.prototype.validate = function (item) {
	return (item.getValue().length <= this._params.doctrine);
}
WplFormValidators.validators.doctrine_length.prototype.getMessage = function () {
	return this._message;
}

// doctrine_notblank validator
WplFormValidators.validators.doctrine_notblank = function (params, message) {
	this._message = message;
	this._params = params;
};
WplFormValidators.validators.doctrine_notblank.prototype.validate = function (item) {
	return (item.getValue().length > 0);
}
WplFormValidators.validators.doctrine_notblank.prototype.getMessage = function () {
	return this._message;
};

// doctrine_minlength validator
WplFormValidators.validators.doctrine_minlength = function (params, message) {
	this._message = message;
	this._params = params;
};
WplFormValidators.validators.doctrine_minlength.prototype.validate = function (item) {
	return (item.getValue().length >= this._params.doctrine);
};
WplFormValidators.validators.doctrine_minlength.prototype.getMessage = function () {
	return this._message;
};

// doctrine_email validator
WplFormValidators.validators.doctrine_email = function (params, message) {
	this._message = message;
	this._params = params;
};
WplFormValidators.validators.doctrine_email.prototype.validate = function (item) {
	if (!item.getValue()) {
		return true;
	}
	var filter  = /^([^@])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
	return filter.test(item.getValue());
};
WplFormValidators.validators.doctrine_email.prototype.getMessage = function () {
	return this._message;
};

// doctrine_regexp validator
WplFormValidators.validators.doctrine_regexp = function (params, message) {
	this._message = message;
	this._params = params;
};
WplFormValidators.validators.doctrine_regexp.prototype.validate = function (item) {
	var regexStr = this._params.doctrine.substring(1, this._params.doctrine.length - 1);
	var regex = new RegExp(regexStr);

	return (!!item.getValue().match(regex));
};
WplFormValidators.validators.doctrine_regexp.prototype.getMessage = function () {
	return this._message;
};

// compare validator
WplFormValidators.validators.compare = function (params, message) {
	this._message = message;
	this._params = params;
};
WplFormValidators.validators.compare.prototype.validate = function (item) {
	var value = item.getValue();
	var otherItem = item.getParentWplForm().getItem(this._params.other);

	if (otherItem) {
		var otherValue = otherItem.getValue();
		return (value == otherValue);
	}

	return true;
};
WplFormValidators.validators.compare.prototype.getMessage = function () {
	return this._message;
};

// isnot validator
WplFormValidators.validators.isnot = function (params, message) {
	this._message = message;
	this._params = params;
};
WplFormValidators.validators.isnot.prototype.validate = function (item) {
	return (item.getValue() != this._params.isnot);
};
WplFormValidators.validators.isnot.prototype.getMessage = function () {
	return this._message;
};

// notEqual validator
WplFormValidators.validators.notEqual = function (params, message) {
	this._message = message;
	this._params = params;
};
WplFormValidators.validators.notEqual.prototype.validate = function (item) {
	return (item.getValue() != this._params);
};
WplFormValidators.validators.notEqual.prototype.getMessage = function () {
	return this._message;
};

// telephone validator
WplFormValidators.validators.telephone = function (params, message) {
	this._message = message;
	this._params = params;
};
WplFormValidators.validators.telephone.prototype.validate = function (item) {
	var value = item.getValue();
	if (0 == value.length) {
		return true;
	}
	return (value.replace(/[^0-9]/g, '').length >= 10);
};
WplFormValidators.validators.telephone.prototype.getMessage = function () {
	return this._message;
};

