	Languages = {
		english:	{
			error_msg: {
				ckvalid_heading : 'Error List : ',				
				default_name : 'This Field',				
				required : ' must be field in.',
				email : 'Invalid Email Address',
				numeric : ' must contact numeric numbers only',
				integer : ' must be an integer',
				minValue : ' must be at least ',
				maxValue : ' must not greater than',
				maxLength : ' exceeds maximum length ',
				equal : ' not match ',
				range : ' must within the range',
				valide_date : 'Not a valid date',
				valid_time : 'Not a valid time'
			}
		},
		zh_hk: {
			error_msg: {
				ckvalid_heading : '請更正以下錯誤 : ',				
				default_name : '此欄',				
				required : ' 必須填寫',
				email : '請填寫正確電郵',
				numeric : ' 必須是數字',
				integer : ' 必需為整數',
				minValue : ' 必須至少等於',
				maxValue : ' 不能大於',
				maxLength : ' 最大長度為 ',
				equal : ' 並不正確 ',
				range : ' 必須在此範圍內',
				valide_date : '不是正確的日期',
				valid_time : '不是正確的時間'
			}
		}
	};
	
	FormHandler = {
		form : null,
		action : '',
		form_elements : new Array(),
		find_form : true,
		
		ajax : null,
		
		lang : 'english',
		error_msg : {},
		error_target : '',
		error_tag : 'p',
		
		init : function( obj_elements, options ) {
			this.form_elements = obj_elements;
			
			if (options != undefined) {
				this.lang = (options.lang != undefined) ? options.lang : this.lang;		
			
				if (options.ajax != undefined) {
					this.action = 'ajax';
					
					this.ajax = options.ajax
				}
				
				if (options.find_form != undefined) {
					this.find_form = options.find_form;
				}
			}		
			
			this.error_msg = Languages[this.lang].error_msg;
		},
		
		set_error_msg: function( rules, msg ) {			
			this.error_msg[rules] = msg;
		},
		
		set_error_tag: function ( tagname ) {
			this.error_tag = tagname;
		},
		
		checkStep : function ( form_id, err_target ) {
			var step_ok = this.field_check(form_id, err_target);
			
			return step_ok;
		},
		
		reset : function ( form_id ) { 
			$('#'+form_id).find(':input:not(:button)').attr('value', '');
		},
		
		checkForm : function( form_id, err_target ) {
			var submitOK = this.field_check(form_id, err_target);
			
			if (submitOK) {				
				this.handle_post();
				return true;
			}
			else {
				if ( (err_target != undefined) && (err_target != '')) {
					var html = '';
					
					html += '<'+this.error_tag+' class="error head">';
						html += '<b><u>';
						html += this.error_msg['ckvalid_heading'];
						html += '</u></b>';
					html += '</'+this.errog_tag+'>';
					
					$(this.error_target).prepend(html);
				}	
			}
			
			return false;
		},
		
		field_check : function ( form_id, err_target ) {
			this.form = $('#'+form_id);
			
			if (err_target != undefined) {				
				this.error_target = err_target;
				$(this.error_target).html('');
			}
			else {				
				$(this.form).find( this.tag + '.error' ).empty();		
			}
			
			var thisOk = new Boolean;	
			var submitOK = true;
			var debug = '';
			
			for (var i = 0 ; i < this.form_elements.length ; i++) {
				thisOK = true;
								
				var field_obj = this.form_elements[i];
				
				if (this.find_form) {
					var dom_obj = $(this.form).find(':input[name='+field_obj.name+']');
				}
				else {					
					var dom_obj = $(':input[name='+field_obj.name+']');
				}				
				
				if (field_obj.rules.match(/required/) || ($(dom_obj).val() != '')) {					
					thisOk = this.checkError(dom_obj, field_obj);
				}
				
				/* debug = field_obj.name+' => '+thisOk+'<br/>';
				$('#debug').append(debug); */
				
				if (!thisOk) {
					submitOK = false;
				}
			}			
			
			return submitOK;
		},
		
		checkError : function( dom_obj, field_obj ) {
			var valueOK = true;
			var error = '';
			var arr_rules = '';
			var full_rules = '';
			var msg = '';
			var errorstr_prefix = '';
			var obj_value = '';
			var matches = new Array();
			
			arr_rules = field_obj.rules.split('|');
			if (field_obj.type == 'radio') {
				for (var i = 0 ; i < dom_obj.length ; i++) {
					if (dom_obj.eq(i).attr('checked')) {
						obj_value = dom_obj.eq(i).val();
					}
				}				
			}
			else {
				obj_value = $(dom_obj).val();
			}			

			for (var j = 0 ; j < arr_rules.length ; j++) {		
				full_rules = arr_rules[j];
				matches = full_rules.match(/\[(.*)\]/);
				
				if (field_obj.displayName != undefined) {
					errorstr_prefix = field_obj.displayName;
				}
				else {
					errorstr_prefix = this.error_msg['default_name'];
				}
				
				switch(arr_rules[j].replace(/\[.*\]/, '')) {
					case 'required':                                       
						if ( obj_value == '' ) {
							valueOK = false;						
							msg = (field_obj.error_msg == undefined) ?
									errorstr_prefix + this.error_msg['required'] :
									field_obj.error_msg;
							error = this.set_error(error, msg);
						}
						break;					
					case 'email':                                    
						if ( !( this.isEmail(obj_value) ) ) {
							valueOK = false;
							msg = (field_obj.error_msg == undefined) ?
									errorstr_prefix + ' : ' + this.error_msg['email'] :
									field_obj.error_msg;																
							error = this.set_error(error, msg);
						}
						break;
					case 'numeric':
						if ( !( this.isNumeric(obj_value) ) ) {
							valueOK = false;
							msg = (field_obj.error_msg == undefined) ?
									errorstr_prefix + this.error_msg['numeric'] :
									field_obj.error_msg;										
							error = this.set_error(error, msg);
						}
						break;
					case 'integer':
						if ( !( this.isInteger(obj_value) ) ) {
							valueOK = false;
							msg = (field_obj.error_msg == undefined) ?
									errorstr_prefix + this.error_msg['integer'] :
									field_obj.error_msg;										
							error = this.set_error(error, msg);
						}
						break;
					case 'minValue':					
						if (obj_value < parseInt(matches[1])) {
							valueOK = false;
							msg = (field_obj.error_msg == undefined) ?
									errorstr_prefix + this.error_msg['minValue'] + matches[1] :
									field_obj.error_msg;											
							error = this.set_error(error, msg);
						}						
						break;
					case 'maxValue':					
						if (obj_value > parseInt(matches[1])) {
							valueOK = false;
							msg = (field_obj.error_msg == undefined) ?
									errorstr_prefix + this.error_msg['maxValue'] + matches[1] :
									field_obj.error_msg;							
							error = this.set_error(error, msg);
						}						
						break;
					case 'maxLength':						
						if (obj_value.length > parseInt(matches[1])) {
							valueOK = false;
							msg = (field_obj.error_msg == undefined) ?
									errorstr_prefix + this.error_msg['maxLength'] + matches[1] :
									field_obj.error_msg;							
							error = this.set_error(error, msg);
						}
						break;
					case 'equal':
						if (obj_value != matches[1]) {
							valueOK = false;
							msg = (field_obj.error_msg == undefined) ?
									errorstr_prefix + this.error_msg['equal'] :
									field_obj.error_msg;							
							error = this.set_error(error, msg);
						}
						break;
					case 'range':
						var arr = matches[1].split('-');
						var greater = 0;
						var smaller = 0;
						
						if (arr[0] > arr[1]) {
							greater = arr[0];
							smaller = arr[1];
						}
						else {
							greater = arr[1];
							smaller = arr[0];
						}
						
						if ( (obj_value < smaller) && (obj_value > greater) ) {
							valueOK = false;
							msg = (field_obj.error_msg == undefined) ?
									errorstr_prefix + this.error_msg['range'] + '(' + smaller + '-' + greater + ')' :
									field_obj.error_msg;							
							error = this.set_error(error, msg);
						}						
						break;
					case 'valid_time':
						var arr_param = matches[1].split(',');
						var seperator = arr_param[1];
						
						var arr_format = arr_param[0].toString().split(seperator);
						var arr_value = obj_value.split(seperator);
						
						for (i = 0 ; i < arr_format.length ; i++) {
							if (arr_format[i].toUpperCase() == 'H') {								
								var hour = arr_value[i];
							}
							if (arr_format[i].toUpperCase() == 'I') {
								var min = arr_value[i];
							}
							if (arr_format[i].toUpperCase() == 'S') {
								var sec = arr_value[i];
							}							
						}
												
						if (hour != '') {
							valueOK = this.checktime(hour, min, year);
						}
						else {
							valueOK = false;
						}

						if (!valueOK) {
							msg = (field_obj.error_msg == undefined) ?
								this.error_msg['valid_time'] :
								field_obj.error_msg;						
							error = this.set_error(error, msg);
						}
						break;						
					case 'valid_date':						
						var arr_param = matches[1].split(',');
						var seperator = arr_param[1];

						var arr_format = arr_param[0].toString().split(seperator);
						var arr_value = obj_value.split(seperator);

						for (i = 0 ; i < arr_format.length ; i++) {
							if (arr_format[i].toUpperCase() == 'Y') {
								var year = arr_value[i];
							}
							if (arr_format[i].toUpperCase() == 'M') {
								var mth = arr_value[i];
							}
							if (arr_format[i].toUpperCase() == 'D') {
								var day = arr_value[i];
							}							
						}
						
						if ( (year != undefined) && (mth != undefined) && (day != undefined) ) {
							valueOK = this.checkdate(mth, day, year);						
						}
						else {
							valueOK = false;
						}
						
						if (!valueOK) {						
							msg = (field_obj.error_msg == undefined) ?
								this.error_msg['valide_date'] :
								field_obj.error_msg;										
							error = this.set_error(error, msg);
						}
						break;
					case 'call_back':
						var func_name = matches[1];					
						
						if ( !eval(func_name+'(dom_obj)') ) {
							valueOK = false;							
							msg = (field_obj.callback_msg == undefined) ? 
								  ( (field_obj.error_msg == undefined) ? 'Field Errors return from '+func_name+'()' : field_obj.error_msg) :
								  field_obj.callback_msg
							error = this.set_error(error, msg);
						}						
						break;
					default:
						valueOk = true;
						error = '';
						break;
				}
			}

			if (valueOK != false) {
				this.removeError( $(dom_obj).parent(), field_obj );
			}
			else {
				this.appendError( $(dom_obj).parent(), error, field_obj);                     
			}
			
			return valueOK;
		},
		
		appendError : function ( obj, error_msg, field_obj ) {
			if (this.error_target == '') {	
				obj.find( this.error_tag + '.error.'+field_obj.name).remove();			
				obj.append( '<' + this.error_tag + ' class="error ' + field_obj.name +'">'+error_msg+'</' + this.error_tag + '>' );
				obj.addClass('error');
			}
			else {
				$(this.error_target).append('<' + this.error_tag +' class="error">'+error_msg+'</' + this.error_tag + '>');
			}
		},
		
		removeError : function (obj, field_obj) {
			if (this.error_target == '') {		
				obj.find( this.error_tag + '.error.'+field_obj.name).remove();
				obj.removeClass('error');
			}			
		},
		
		set_error : function( org_error, new_error ) {
			if (org_error != '') {
				return org_error;
			}
			else {
				return new_error;
			}		
		},
		
		handle_post : function() {
			if (this.action == '') {
				this.form.submit();
			}
			else {
				var obj_ajax = this.ajax;
				var post_url = '';
			
				post_url = (obj_ajax.post_to == undefined) ? $(this.form).attr('action') : obj_ajax.post_to;
				
				if (obj_ajax.mode == 'post') {					
					$.post(post_url, $(this.form).find(':input').serializeArray(), function(data) {
						if (FormHandler.ajax.call_back != undefined) {							
							FormHandler.ajax.call_back(data);
						}										
					}, obj_ajax.format == undefined ? obj_ajax.format : '');
				}
				else {					
					$(obj_ajax.load_target).load(post_url, $(this.form).find(':input').serializeArray(), function(data) {						
						if (FormHandler.ajax.call_back != undefined) {							
							FormHandler.ajax.call_back(data);
						}
					}, obj_ajax.format == undefined ? obj_ajax.format : '');					
				}
			}
		},
			
		isEmail : function ( email ) {
			return (email.search(/^\w+[A-Za-z0-9._-]*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/) != -1); 
		},
		
		isNumeric : function ( value ) {
			return (value.search(/^[\-+]?[0-9]*\.?[0-9]+$/) != -1); 
		},
		
		isInteger : function ( value ) {
			return (value.search(/(^-?\d\d*$)/) != -1);
		},
		
		checktime : function (hour, min, sec) {
			var valid = true;
			
			if (min != undefined) {				
				if (parseInt(min) < 0 || parseInt(min) > 59) {
					valid = false;
				}
			}
			
			if (sec != undefined) {
				if (parseInt(sec) < 0 || parseInt(sec) > 59) {					
					valid = false;
				}
			}
			
			if (parseInt(hour) < 0 || parseInt(hour) > 23) {				
				valid = false;
			}
			
			return valid;
		},
		
		checkdate : function ( mth, day, year ) {			
			var valid = true;
			
			mth = parseInt(mth.replace(/^0/, ''));
			day = parseInt(day.replace(/^0/, ''));
						
			if (!FormHandler.isInteger(year)) {				
				valid = false;
			}			
			
			switch(mth) {
				case 2:
					if (year % 4 == 0) {
						if (day <= 0 || day > 29) {							
							valid = false;												
						}
					}
					else {
						if (day <= 0 || day > 28) {							
							valid = false;												
						}
					}
					break;
				case 4:
				case 6:
				case 9:
				case 11:
					if (day <= 0 || day > 30) {						
						valid = false;												
					}
					break;
				case 1:
				case 3:
				case 5:
				case 7:
				case 8:
				case 10:
				case 12:					
					if (day <= 0 || day > 31) {						
						valid = false;												
					}
					break;
				default:					
					valid = false;
					break;
			}
			
			return valid;
		},
		
		'dummy' : ''
	};
