// represents a WplForm object on the client
WplForm = function (id, options) {
	this._id = id;
	if (typeof options == 'undefined') {
		options = {};
	}
	this._options = options;
	this._items = [];

	var thiss = this;
	
	var observer = function (event) {
		if (!thiss.check()) {
			thiss.updateDisplay();
			thiss.getErrorStrategy().drawFormErrorsubmit(thiss);
			
			Event.stop(event);
		} else {
			thiss.onsubmit();
		}
	}
	
	Event.observe($(id + 'Form'), "submit", observer);
	
};
WplForm.prototype.onsubmit = function () {}
// 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.FloatingLabels;
		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._parentWplForm = 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 (el, name, initialErrors) {
	this._name = name;
	this._validators = [];
	this._errors = initialErrors;
	this._el = el;
	this._parentWplForm;
	
	// let us attach this to the el:
	var thiss = this;
	//Event.observe(el, "change", function () {thiss.elChanged();});
	//Event.observe(el, "keyup", function () {thiss.elKeyup();});
};
// 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);
		}
	}
	return (this._errors.length == 0);
}
// updates the state of thie form field 
WplFormItem.prototype.updateDisplay = function () {
	// set error status for this field in the display
	var state = (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();
}
// with the keyup, we only want it to REMOVE errors, not ADD them :)
// the new errors can be caught with the change event.
WplFormItem.prototype.elKeyup = function () {
	var hasErrors = (this._errors.length > 0);
	if (!hasErrors) {
		return;
	}
	this.check();
	if (this._errors.length == 0) {
		// no longer has errors - update the display
		this._parentWplForm.updateDisplay();
	}
}
WplFormItem.prototype.getParentWplForm = function () {
	return this._parentWplForm;
}
// this tells the form item to update errors. etc. associated with it.
WplFormItem.prototype.updateDisplay = function () {
	
}


// Error strategies
//
// these hold strategies for displayign 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 = "";
	var errorCount = 0;
	
	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>"; 
			errorCount++;
		}
		if (errors.length > 0) {
			Element.removeClassName(formItem._el, "validatedGood");
			Element.addClassName(formItem._el, "validatedBad");
		} else {
			Element.removeClassName(formItem._el, "validatedBad");
			Element.addClassName(formItem._el, "validatedGood");
		}
	}
	
	if (out.length > 0) {
		out = "<ul>" + out + "</ul>";
	}
	
	var errorArea = $(form._id + "FormErrorArea");
	if (errorArea) {
		// add the list of the errors to the "error area"
		errorArea.innerHTML = out;
		if (errorCount > 0) {
			errorArea.show();
		} else {
			errorArea.hide();
		}
	}
};
WplForm.ErrorStrategies.ErrorArea.drawFormErrorsubmit = function (form) {
	if (typeof WplDialog == 'class') {
		WplDialog.openAlert("You must complete the form first!", 300);			
	} else {
		alert("You must complete the form first");
	}
}

// 
WplForm.ErrorStrategies.ItemErrors = {};
WplForm.ErrorStrategies.ItemErrors.drawFormErrors = function (form) {
	var errorCount = 0;	
	for (var i = 0; i < form._items.length; i++) {
		var formItem = form._items[i];
		var errors = formItem.getErrors();
		var hasErrors = (errors.length > 0);
		
		var itemEl = $('afi_' + formItem.getId());
		if (itemEl) {
			if (hasErrors) {
				itemEl.addClassName('haserrors');
			} else {
				itemEl.removeClassName('haserrors');
			}
		}
		
		var errorEl = $('afie_' + formItem.getId());
		if (errorEl) {
			if (hasErrors) {
				// get rid of all current errors so we can redraw them
				errorEl.show();
				errorEl.innerHTML = '';
				
				for (var j = 0; j < errors.length; j++) {
					var error = errors[j];
					var te = document.createTextNode(error);
					var li = document.createElement('li');
					
					li.appendChild(te);
					errorEl.appendChild(li);
					
					errorCount++;
				}
			} else {
				errorEl.hide();
			}
		}
	}
	
	var errorArea = $(form._id + "FormErrorArea");
	if (errorArea) {
		if (errorCount > 0) {
			errorArea.show();
		} else {
			errorArea.hide();
		}
	}
};
WplForm.ErrorStrategies.ItemErrors.drawFormErrorsubmit = function (form) {
	// 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) {	
	if (!item.getValue()) {
		return true;
	}
	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;
}