
Formidator = function(formId, profile) {
	bindMethods(this);
	this._errors = [];
	if (arguments.length > 1) {
		this._setProfile(profile);
	}
	if (arguments.length > 0) {
		this._process(formId);
	}
};

Formidator.prototype = update({}, {

	_errors: [],
	_profile: { // the default profile
		// required fields
		'required': [],
		// user defined constraints
		// constraint can be a regular expression string
		// or a user defined function
		// or an identifier from pedefined contraints
		'constraints': {},
		// define messages by field name
		'msg': {},
		//
		'msgTpl': 'There is a problem with your form.\n\n%s',
		// set true for a simple alert message
		// or define a function for callback
		'error': true,
		// define a css class fieldError
		// to prefent field highlight - set highlight to false
		'highlight': 'fieldError'
	},

	$: function(fieldName) {
		var domId = fieldName.split('[').join('.').replace(/\]/, '');
		return $(domId);
	},

	_highlightFields: function(formData) {
		try {
			var i = 0, f;
			// reset fields to default
			while (e = formData[i]) {
				try {
					removeElementClass(this.$(e), this._profile.highlight)
				} catch(e) {
					//
				}
				i++;
			}
			// set error class
			i = 0; f = null;
			while (e = this._errors[i]) {
				//~ setElementClass(this.$(e.fieldName), this._profile.highlight);
				toggleElementClass(this._profile.highlight, this.$(e.fieldName));
				i++;
			}
		} catch(e) { console.error(e); }
	},

	_onError: function(formData) {
		if (this._errors.length > 0) {
			if (typeof(this._profile.highlight) == 'string') {
				this._highlightFields(formData);
			}
			if (typeof(this._profile.error) == 'function') {
				this._profile.error(this._errors, this);
			} else if (this._profile.error == true) {
				var i = 0, e, m = '';
				while (e = this._errors[i]) {
					m+= e.message + '\n';
					i++;
				}
				alert(this._profile.msgTpl.replace(/%s/, m));
			}
		}
	},

	_pushError: function(fieldName, constraint) {
		var m = '';
		if (!isUndefinedOrNull(this._profile.msg[fieldName])) {
			m = this._profile.msg[fieldName];
		} else {
			m = 'Field - ' + fieldName + ' - is required.';
		}
		var e = {
			'fieldName': fieldName,
			'message': m,
			'constraint': (constraint)
		};
		this._errors.push(e);
	},

	_setProfile: function(profile) {
		this._profile = merge(this._profile, profile);
	},

	_checkRequired: function(fieldName) {
		var rtc = 1;

		var r = this._profile.required;
		if (findValue(this._profile.required, fieldName) < 0) {
			return rtc;
		}
		rtc = 0;
		var f = this.$(fieldName);
		switch (f.tagName) {
			case 'INPUT':
				switch (getNodeAttribute(f, 'type')) {
					case 'checkbox': // ???
						if (!f.checked)
							rtc = -1;
						break;
					default:
						if (!f.value)
							rtc = -1;
						break;
				}
				break;
			case 'SELECT':
//				alert(f.value);
				break;
		}
		if (rtc < 0) {
			this._pushError(fieldName);
		}
		return rtc;
	},

	_checkConstraint: function(fieldName) {
		var rtc = 1;
		if (isUndefinedOrNull(this._profile.constraints[fieldName])) {
			return rtc;
		}
		var rtc = 0;
		var f = this.$(fieldName);
		var v = f.value;
		var c = this._profile.constraints[fieldName];
		switch (typeof(c)) {
			case 'string':
				rtc = (!Formidator.Constraints.testRegExp(v, c, '')) ? -1 : 0;
				break;
			case 'function':
				rtc = (!c(f, this)) ? -1 : 0;
				break;
		}
		if (rtc < 0) {
			this._pushError(fieldName);
		}
		return rtc;
	},

	_highlightField: function(fieldName, err) {
		if (err) {
			//
		}
	},

	_process: function(formId) {
		var d = formContents($(formId))[0];
		var i = 0, f, p = this._profile, c;
		while (f = d[i]) {
			if (this._checkRequired(f) >= 0) {
				this._checkConstraint(f);
			}
			i++;
		}

		// find required checkboxes --
		var j = 0, c;
		while (c = this._profile.required[j]) {
			if (findValue(d, c) < 0) {
				this._pushError(c);
			}
			j++;
		}

		if (!this.isValid()) {
			this._onError(d);
		} else {
			this._highlightFields(d);
		}
	},

	isValid: function() {
		return (this._errors.length < 1);
	}
});

Formidator.validate = function(form, profile) {
	var f = new Formidator(form, profile);
	return f.isValid();
};

// --

Formidator.Constraints = {

	_regExp: {
		// default re constraints
		email: 		'^(([a-zA-Z0-9_\\.\\+\\-\\=\\?\\^\\#]){1,64}\\@(([a-zA-Z0-9\\-]){1,251}\\.){1,252}[a-zA-Z0-9]{2,4})$',
		email_opts: 'i',
		integer: 	'^([0-9]*)$',
		zip_code: 	'^(\\d{4,5})$', // de and at zip codes only
		phone: 		'^((\\D*\\d\\D*){6,})$',		// found also /^(\+\d)*\s*(\(\d{3}\)\s*)*\d{3}(-{0,1}|\s{0,1})\d{2}(-{0,1}|\s{0,1})\d{2}$/
		ip_address: '^(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})$',
		login:		'^([a-zA-Z0-9_\\-\\.]{4,20})$',
		login_opts: 'i',
		password:	'^([a-zA-Z0-9_\\-\\.]{4,20})$',
		password_opts: 'i'

	},

	testRegExp: function(str, regExp, regExpOpts) {
		if (!isUndefinedOrNull(this._regExp[regExp])) {
			regExp = this._regExp[regExp];
			if (isUndefinedOrNull(regExpOpts) && !isUndefinedOrNull(this._regExp[regExp  + '_opts'])) {
				regExpOpts  = this._regExp[regExp  + '_opts'];
			}
		}
		if (typeof(regExp) == 'object') {
			regExpOpts = regExp[1];
			regExp = regExp[0];
		}
		if (typeof(regExpOpts) == 'undefined') {
			regExpOpts = '';
		}
		var r = new RegExp(regExp, regExpOpts), m;
//		console.log('-->', r.exec(str));
		return (m = r.exec(str)) ? m[1] : false;
	}

	// functions ...
};

