/**
 * @package TT_WordPress_Library
 * @subpackage Form
 * @author Alex Southan
 * @link http://tiptapdesign.co.uk/
 */
jQuery(document).ready(function($) {
	/**
	 * Print error message.
	 * @param {String} id
	 * @param {String} message
	 */
	function doError(id, message) {
		if (id.indexOf('#') == 0)
			id = id.substr(1);
		$('#field_' + id).addClass('field-error');
		var error = $('#' + id + ' ~ .input-error');
		if (error.length < 1)
			$('#' + id).after('<span class="input-error">' + message + '</span>');
		else
			error.text(message);
	}

	/**
	 * Remove error message.
	 * @param {String} id
	 */
	function undoError(id) {
		if (id.indexOf('#') == 0)
			id = id.substr(1);
		$('#field_' + id).removeClass('field-error');
		$('#' + id + ' ~ .input-error').remove();
	}

	/**
	 * Validate an input.
	 * @param {Object} e Document element object
	 * @param {Boolean} minimal Validate only length and required
	 * @return {Boolean}
	 */
	function validateInput(e, minimal) {
		e = $(e);
		if (!e.hasClass('validate'))
			return true;

		if (!minimal)
			minimal = false;

		var rules = e.data('rules');
		if (!rules) {
			rules = {}
			var m = e.attr('class').match(/validate\s*(\{[^}]*\})/i);
			if (m && m[1]) {
				try {
					eval('rules=' + m[1]);
				} catch(eInvalidJSON) {}
			}
			e.data('rules', rules);
		}

		var id = e.attr('id'),
			v = e.val(),
			clean = v.replace(/\s+/g, ' ').replace(/^ +| +$/, ''),
			error = false;

		if (!id) {
			id = String((new Date()).getTime()).replace(/\D/gi, '');
			e.attr('id', id);
		}

		if ('max' in rules && v.length > rules.max)
			error = 'max ' + rules.max + ' characters';
		else if ('min' in rules && v.length < rules.min)
			error = 'min ' + rules.min + ' characters';

		if (minimal || error) { // bypass extended validation
			error ? doError(id, error) : undoError(id);
			return error === false;
		}

		if (clean.length == 0) {
			if (rules.required == 'yes')
				error = 'required';
			error ? doError(id, error) : undoError(id);
			return error === false;
		}

		switch (rules.type) {
			case 'email': // http://www.hm2k.com/posts/what-is-a-valid-email-address
				if (!v.match(/^[\w!#$%&'*+\/=?^`{|}~.-]+@(?:[a-z\d][a-z\d-]*(?:\.[a-z\d][a-z\d-]*)?)+\.(?:[a-z][a-z\d-]+)$/i))
					error = 'invalid email';
				break;
			case 'url': // http://projects.scottsplayground.com
				if (!v.match(/^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i))
					error = 'invalid URL';
				break;
			case 'telephone':
				if (!v.match(/[0-9]/) || v.match(/[^0-9 \+,\(\)-]/)) // digits+,()-
					error = 'invalid telephone';
				break;
			case 'postcode': // http://en.wikipedia.org/wiki/UK_postcode - UK and overseas territories only - loose interpretation
				v = clean.toUpperCase().replace(' ', '');
				if (v.match(/^BFPO[0-9]{1,4}$/))
					v = 'BFPO ' + v.replace(/[^0-9]+/, ''); // British Forces Post Office
				else if (v == 'AI-2640')
					v = 'AI-2640'; // Anguilla
				else {
					var incode  = v.substr(v.length - 3, 3);
					var outcode = v.substr(0, v.length - incode.length);
					v = outcode + ' ' + incode;
					if (!v.match(/^[A-Z][A-Z0-9][A-Z0-9]?[A-Z0-9]? ([0-9][ABD-HJLNP-UW-Z]{2}|[0-9]{1,4})$/))
						error = 'invalid UK postcode';
				}
				// e.val(v); // a bit offputting whilst typing postcode
				break;
			case 'alphabetic':
				if (v.match(/[^a-z]/i))
					error = 'alphabet only';
				break;
			case 'numeric':
				if (!v.match(/[^0-9]/))
					error = 'numbers only';
				break;
			case 'alphanumeric':
				if (v.match(/[^0-9a-z]/i))
					error = 'alphabet and numbers only';
				break;
			case 'simple':
				if (v.match(/[^0-9a-z_-]/i))
					error = 'alphanumerics, underscore and hyphens only';
				break;
			case '_verification':
				var q = $('label[for=' + id + ']').text().match(/sum of ([a-z]+) and ([a-z]+)/i);
				if (!q.length)
					break;
				var trans = {zero: 0, one: 1, two: 2, three: 3, four: 4, five: 5, six: 6, seven: 7, eight: 8, nine: 9, ten: 10};
				if (typeof trans[q[1]] == 'undefined' || typeof trans[q[2]] == 'undefined')
					break; // bail
				var total = trans[q[1]] + trans[q[2]];
				var check = v in trans ? trans[v] : v; // in case answer was spelt
				if (check != total)
					error = 'sorry, wrong answer';
		}

		error ? doError(id, error) : undoError(id);
		return error === false;
	}

	$(':input.validate').each(function() {
		$(this)
			.keyup(function() {
				validateInput(this, true);
			})
			.focus(function() {
				$(this).closest('.field').addClass('focused');
			})
			.blur(function() {
				$(this).closest('.field').removeClass('focused');
				if (!validateInput(this))
					$(this).unbind('keyup').keyup(function() {
						validateInput(this);
					});
			});
	});

	$('form').submit(function() {
		var log = new Array();
		$(':input.validate', this).each(function() {
			if (validateInput(this))
				return true;
			var e = $(this);
			log.push(e.attr('id'));
			e.unbind('keyup').keyup(function() {
				validateInput(this);
			});
		});
		if (log.length > 0) {
			$('#' + log[0]).focus();
			return false;
		}
	});
});