/* 
 * jQuery form validator
 * 
 * Prevents form from submitting until fields validate.
 *
 * Copyright (c) 2010 Wade Shearer (anavidesign.com)
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * Version 1.0
 */
 
(function($) {
	$.fn.validator = function() {
		this.each(function() {
			// variables
			var tab_markup = '<div class="fvt"><div class="fvt_left"></div><div class="fvt_middle"></div><div class="fvt_right"></div></div>';
			var tab;
			var fields_validate = $(this).find('[data-validation]');
			var fields_required = $(this).find('[required]');
			
			// write in tabs
			$(fields_validate).after(tab_markup);
			
			// set up lister for form submission
			$(this).submit(function() {
				var form_valid = 0;
			
				// re-validate
				$(fields_required).each(function() {
					validate(this);
					
					if(!$(this).attr('valid')) {
						form_valid++;
					}
				});
				
				return form_valid > 0 ? false : true;
			});
			
			// listener for field (validate on blur, hide tag on focus)
			$(fields_validate)
				.blur(function() {
					if(!$(this).hasClass('picker_active')) {
						validate(this);
					}
				})
				
				.focus(function() {
					$(this).next('.fvt').hide();
				});
			
			// validate field
			function validate(field) {
				var x = $(field).position().left;
				var y = $(field).position().top;
				var w = $(field).width();
				var required = $(field).attr('required');
				var validation = $(field).attr('data-validation');
				var msg = 'Required';
				var result = false;
				var val = $(field).val();
				var exp;
				var call = $(field).attr('data-validation_call');
				var db = $(field).attr('data-validation_db');
				var origval = $(field).attr('data-validation_origval');
				var id = $(field).attr('data-validation_id');
				var name = $(field).attr('name');
				var listener = '/assets/plugins/validator/listener.php';
	
				// position tab
				tab = $(field).closest('.formitemoptions').children('.fvt');
				
				$(tab)
					.css('top', (y - 4) + 'px')
					.css('left', (x + w) + 'px');
				
				// validate
				if(val.length > 0) {
					switch(validation) {
						// password
						case 'password':
							// length
							result = val.length < 6 ? false : true;
							if(result == false) {
								msg = 'Must be at least 6 characters';
								break;
							}
							
							// must include a number and a lower letter and an upper letter
							//exp = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,}$/;
							
							// must include a number and a letter
							exp = /^(?=.*\d)(?=.*[a-zA-Z]).+$/;
							result = exp.test(val) == false ? false : true;
							if(result == false) {
								msg = 'Must include a number and a letter';
								break;
							}
							
							break;
							
						// markup
						case 'markup':
							// length
							result = val.length > 300000 ? false : true;
							if(result == false) {
								msg = 'Too much';
								break;
							}
							
							// php, CSS, javascript  --- remove 's' flag... what is it for?
							exp = /<(\?|script|style)/gim;
							result = exp.test(val) == false ? true : false;
							if(result == false) {
								msg = 'No PHP, CSS, or javascript';
								break;
							}
							
							break;
							
						// varchar (for varchar 255)
						case 'varchar':
							result = val.length > 255 ? false : true;
							if(result == false) {
								msg = 'Must be 255 characters or less (' + val.length + ')';
								break;
							}
							
							exp = /<(\?|script|style)/gim;
							result = exp.test(val) == false ? true : false;
							if(result == false) {
								msg = 'No PHP, CSS, or javascript';
								break;
							}
							break;
							
						// text (for 65535 chars)
						case 'text':
							result = val.length > 65535 ? false : true;
							if(result == false) {
								msg = 'Must be 65,535 characters or less (' + val.length + ')';
								break;
							}
							
							exp = /<(\?|script|style)/gim;
							result = exp.test(val) == false ? true : false;
							if(result == false) {
								msg = 'No PHP, CSS, or javascript';
								break;
							}
							
							break;
		
						// 4 chars long
						case '4chars':
							msg = 'Must be at least 4 characters';
							result = val.length > 3 ? false : true;
							break;
							
						// integer
						case 'integer':
							msg = 'Must be an integer';
							exp = /^([0-9]*)$/;
						  	result = exp.test(val) ? true : false;
							break;
							
						// number
						case 'number':
							msg = 'Must be an integer';
							exp = /^([0-9,\-\. /()]*)$/;
						  	result = exp.test(val) ? true : false;
							break;
							
						// word
						case 'word':
							msg = 'No spaces or special characters';
							exp = /^[\w]+$/;
						  	result = exp.test(val) ? true : false;
							break;
							
						// word
						case 'currency':
							if(required == undefined) {
								result = true;
							} else {
								result = val == '0.00' ? false : true;
							}
							break;
							
						// username
						case 'username':
							result = val.length < 6 ? false : true;
							if(result == false) {
								msg = 'Must be at least 6 characters';
								break;
							}
							
							exp = /^[\w]{4,}$/;
							result = exp.test(val) == false ? false : true;
							if(result == false) {
								msg = 'No spaces or special characters';
								break;
							}
							
							break;
							
						// yearmonth
						case 'yearmonth':
							if($(field).hasClass('hint') && $(field).hasClass('active')) {
								result = false;
							} else {
								msg = 'YYYY/MM';
								result = val.length == 7 ? true : false;
							}
							break;
							
						// date
						case 'date':
						case 'datetime':
							if($(field).hasClass('hint') && $(field).hasClass('active')) {
								result = required == 'required' ? false : true;
							} else {
								msg = 'YYYY/MM/DD';
								result = val.length == 10 ? true : false;
							}
							break;
							
						// email
						case 'email':
							msg = 'Must be a valid email address';
							exp = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
						  	result = exp.test(val) ? true : false;
							break;
							
						// required
						default:
							result = val == '' ? false : true;
					}
					
					// remote call
					if(result != false && call != '' && db != undefined) {
						switch(call) {
							case 'unique':
								if(origval != val) {
									$.post(listener, { call: 'unique', db: db, column: name, value: val }, 
										function(data) {
											if(data == 'match') {
												msg = 'Already used, please select another';
												result = false;
											} else {
												result = true;
											}
											
											action();
										}
									);
								} else {
									action();
								}
								break;
								
							case 'password_check':
								if(origval != val) {
									$.post(listener, { call: 'password_check', db: db, column: name, value: val, id: id }, 
										function(data) {
											if(data != 'match') {
												msg = 'Incorrect';
												result = false;
											} else {
												result = true;
											}
											
											action();
										}
									);
								} else {
									action();
								}
								break;
						}
					} else {
						action();
					}
				} else {
					if(required == undefined || required == false) {
						result = true;
					}
				
					action();
				}
				
				
				// action (show tag or change validation status)
				function action() {
					if(result == true) {
						$(field).attr('valid', 'valid');
					} else {
						$(field).removeAttr('valid');
						$(tab).children('.fvt_middle').text(msg);
						$(tab).width((msg.length * 7) + 60);
						$(tab).show();
					}
				}
			}
		});
	};
})(jQuery);
