Validator = new function()
{

  return{
	
    Validate: function(html)
		{
		  try{
			
			  var errors = GetErrors(html);

				if(errors.length == 0)
				  return true;
					
				var table = ErrorTable(errors);
				
				ShowErrors(table, html);
				
				return false;
			
  		} catch(err){ Log.Add("Validator.Validate", err, LogType.Error);}	
		}	
	
	} // <-- end return block
	
	
	
	// validates all controls and returns the ValidationPacks of invalid controls  
	function GetErrors(html)
	{
	  try{
		
		  var errors = new Array();
			
			var arr = new Array();

			var ser = Utilities.Serialize(html);
		
			$(html).find(".component:has(>span.required)").each(function(){
			
			  var ref = $(this).attr('ref');
				
				var span = $(this).find(">span");

				var inp;			
				
				var em = null;				
				
				switch(ref){

				  case "EditorText":
					  inp = $(this).find("input");

						if(Utilities.Trim(inp.val()).length == 0)
							em =  "You must enter the field marked '" + span.text() + "'";

					  break;
					
					
					
					case "EditorMemo":
					  inp = $(this).find("textarea");
					
						if(Utilities.Trim(inp.val()).length == 0)
							em =  "You must enter the field marked '" + span.text() + "'";

					  break;
					
					
					
					
					case "EditorDropDown":
					  inp = $(this).find("select");

						if(inp.val() == "-1")
							em =  "You must select from the dropdown marked '" + span.text() + "'";

					  break;
					
					
					
					
					case "EditorRadio":
  					var name = $(this).find("input").attr("name");
						inp = $(this).find("input");
						
  					if(ser.indexOf(name + "=") == -1)
  					  em = "You must choose one of the radios '" + span.text() + "'";

					  break;
						



					case "EditorCheckBox":
					  var inp = $(this).find("input");
											
  				  if( !inp[0].checked)
  					  em = "You must check the box named '" + span.text() + "'";
				
					  break;
						
				}//<-- end switch statement

				


				if(em != null && !inp.attr("disabled") && !inp.attr("readonly"))
				{
				  var ctrl = Helper.GetEditorComponent(this);
					
					ctrl.ErrorStatus(true);
					
				  var err = new ValidationError(em, ctrl);
					
					errors.push(err);
				}
	
			});
			

			return errors;

		} catch(err){ Log.Add("Validator.GetErrors", err, LogType.Error);}	
	}
	
	
	function ErrorTable(errors)
	{
	  try{
		  
			var table = $("<table class='ValidationErrors' />");
			
			table.append($("<tr><th>#</th><th>message</th></tr>"));
			
	    for(var i = 0; i<errors.length; i++)
			{
			  var tr = $("<tr/>");

				var td1 = $("<td/>");
				td1.text(i);
				tr.append(td1);

				var td2 = $("<td/>");
				td2.text(errors[i].Message);
				td2.click(errors[i].Control.SetFocus);
				td2.css("cursor", "pointer");
				tr.append(td2);

				table.append(tr);
			}
			
			return table;
			
		} catch(err){ Log.Add("Validator.ErrorTable", err, LogType.Error);}		
	}
	
  function ShowErrors(table, html)
	{
	  try{
			
			var c = $(".ValidationContainer");
			
			if(c.length == 0)
			  Log.Add("Validation.ShowErrors", "ValidationContainer could not be found", LogType.Error);
			
	    var ctrl = Helper.GetEditorComponent(c);
		
  		ctrl.Show(table);
			
		} catch(err){ Log.Add("Validator.ShowErrors", err, LogType.Error);}		
	}	
	
	function ClearErrors(html)
	{
	  try{
  	  var ctrl = Helper.GetEditorComponent($(html).find(".ValidationContainer")[0]);	
		
	  	ctrl.Hide();
		} catch(err){ Log.Add("Validator.ClearErrors", err, LogType.Error);}
	}
}//<-- end Validator



function ValidationError(message, control)
{
  this.Message = message;
	this.Control = control;
}







Filters = new function(){

  return{
	
		CUSTOMEXPRESSION: function()
		{
      try{

        this.Test = function(Value, dtype, param)
				{
				  var exp = param;
					var msg = "The information was not formatted correctly";
					
				  if(param.indexOf("|") > -1)
					{
				    exp = param.substring(0, param.indexOf("|"));
					  msg = param.substring(param.indexOf("|") + 1);
					}
					
					exp = new RegExp(exp);
				
				  if(exp.test(Value))
					  return Value;
					else
					  throw msg;
        }		
        
      }catch(err){Log.Add("Filters.CustomExpression", err, LogType.Error);}		  
		},	

		
    DATE: function(){
		  try{

	      this.Test = function(Value, dtype, param){
				
  			  var m, d, y;
					
					var val = Value.replace(/[^0-9]/g, "|"); // replace any separators with |
					
					val = Utilities.ReplaceAll(val, "||", "|"); // get rid of all double pipes
					
					if(val.indexOf("|")==-1)
					{
					  // 1103  -    1/1/03	 [1,2]
						// 31103 -    3/11/03	 [1,3]		
						// 111103-    11/11/03 [2,4]
						// 1112003 -  1/11/03  [1,3]						
						// 11112003 - 11/11/03 [2,4]
						switch(val.length)
						{
						  case 4:
								val = val.insert([1,2], "|");
							  break;
								
						  case 5:
								val = val.insert([1,3], "|");
							  break;
								
						  case 6:
								val = val.insert([2,4], "|");							  
							  break;	
								
						  case 7:
								val = val.insert([1,3], "|");							
							  break;									
								
						  case 8:
								val = val.insert([2,4], "|");									
							  break;
							
							default:
							  throw "The date could not be formatted";																						
						}
						
					}
					
					var n = val.split("|");
					
					if(n.length != 3)
					  throw "Dates must be in the following format 'MM/DD/YYYY'";
						
					m = parseInt(n[0], 10);
					 
					if(m > 12 || m < 1)
					  throw "The month must be between 0 and 12 - enter dates as 'MM/DD/YYYY'";
					
					if(m < 10)
					  m = "0" + m.toString();
					
					d = parseInt(n[1], 10);
					
					if(d > 31 || d < 1)
 					  throw "The day must be between 1 and 31 - enter dates as 'MM/DD/YYYY'";
						
					if(d < 10)
					  d = "0" + d.toString();						

					y = parseInt(n[2], 10)
						
					if(y < 100 && y >= 20)
					  y = 1900 + y;
						
					if(y < 20)
					  y = 2000 + y;
					
					if(y < 1000 || y > 9999)
  					throw "The year must be 4 digits long - enter dates as 'MM/DD/YYYY'";
						
					return m + "/" + d + "/" + y;
					
        }
	
	    }catch(err){Log.Add("Filters.Date", err, LogType.Error);}	
    },
		
	
    EMAIL: function(){
 		  try{

	      this.Test = function(Value, dtype, param){
				
				  var emailPattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
					
					if(emailPattern.test(Value))
					  return Value;
					else
					  throw "The email address is not valid";
				  
        }
	
	    }catch(err){Log.Add("Filters.Email", err, LogType.Error);}	
    },	
		

		
    EQUAL: function(){
      try{
			
        this.Test = function(Value, dtype, param)
				{

					var val = Convert(Value, dtype);

					var compare = Convert(param, dtype);
				
					if(val == compare)
					  return Value
					else
					  throw "The values were not equal"; 
          
        }
     
      }catch(err){Log.Add("Filters.Equal", err, LogType.Error);}	
    },
		
		
		FLOAT: function()
		{
		  try{

        this.Test = function(Value, dtype, param)
        {
				
          var val = Value.replace(/[^0-9\.]/g, ""); // replace any non-numeric characters

          var fl = Convert(val, "FLOAT");
					 
					var ret = fl.toString();
					
					if(ret.indexOf(".") == -1)
					  ret += ".0";
						
					return ret;
    		}
				
	    }catch(err){Log.Add("Filters.Float", err, LogType.Error);}				
		},			
				
		
    GREATERTHAN: function(){
      try{
			
        this.Test = function(Value, dtype, param)
				{

					var val = Convert(Value, dtype);

					var compare = Convert(param, dtype);
				
					if(val > compare)
					  return Value
					else
					  throw Value + " must be greater than " + param; 
          
        }
     
      }catch(err){Log.Add("Filters.GreaterThan", err, LogType.Error);}	
    },
		
		GREATERTHANEQUALS: function()
		{
      try{
			
        this.Test = function(Value, dtype, param)
				{

					var val = Convert(Value, dtype);

					var compare = Convert(param, dtype);
				
					if(val >= compare)
					  return Value
					else
					  throw Value + " must be greater than or equal to " + param; 
          
        }
     
      }catch(err){Log.Add("Filters.GreaterThanEquals", err, LogType.Error);}	

		},			
				
				
		INTEGER: function()
		{
		  try{

        this.Test = function(Value, dtype, param)
        {
				
          var val = Value.replace(/[^0-9\.]/g, ""); // replace any non-numeric characters

					if(val.length ==0)
					  throw "Only integer values are accepted";

          var fl = Convert(val, "INTEGER");
					 
					var ret = fl.toString();
						
					return ret;
    		}
				
	    }catch(err){Log.Add("Filters.Integer", err, LogType.Error);}				
		},		
				
				
				
    LESSTHAN: function(){
      try{
			
        this.Test = function(Value, dtype, param)
				{

					var val = Convert(Value, dtype);

					var compare = Convert(param, dtype);
				
					if(val < compare)
					  return Value
					else
					  throw Value + " must be less than " + param; 
          
        }
     
      }catch(err){Log.Add("Filters.LessThan", err, LogType.Error);}		
    },
		
    LESSTHANEQUALS: function(){
      try{
			
        this.Test = function(Value, dtype, param)
				{

					var val = Convert(Value, dtype);

					var compare = Convert(param, dtype);
				
					if(val <= compare)
					  return Value
					else
					  throw Value + " must be less than or equal to " + param; 
          
        }
     
      }catch(err){Log.Add("Filters.LessThanEquals", err, LogType.Error);}		
    },		
		
	
		
	  PHONE: function()
		{
 		  try{

	      this.Test = function(Value, dtype, param){
				
  			  Value = Value.replace(/x/g, "|"); // extensions will almost always contain the letter x, so replace x with |

					Value = Value.replace(/[^0-9|]/g, "");
					
					var ext = "";

					var i = Value.lastIndexOf("|");

					if(i > -1)
					{
					  ext = Value.substring(i+1);
					  Value = Value.substring(0, i);
					}
					
					switch(Value.length)
					{
					  case 7:
						  Value = Value.substring(0, 3) + "-" + Value.substring(3); 
						  break;
						
						case 10:
 						  Value = "(" + Value.substring(0, 3) + ") " + Value.substring(3, 6) + "-" + Value.substring(6);
						  break;
							
						case 11:
 						  Value = Value.substring(0,1) + " (" + Value.substring(1, 4) + ") " + Value.substring(4, 7) + "-" + Value.substring(7);
						  break;
							
						default:
						  throw "The Phone number is invalid";					
					}
					
					if(ext.length > 0)
  					Value += " x " + ext; 

					return Value;
				  
        }
	
	    }catch(err){Log.Add("Filters.Phone", err, LogType.Error);}	
		},			
		
		
    SSN: function(){
 		  try{

	      this.Test = function(Value, dtype, param){
				
				  var val = Value.replace(/[^0-9]/g, ""); // replace any non-numeric characters
					
					if(val.length == 9)
					  val = val.substring(0, 3) + "-" + val.substring(3, 5) + "-" + val.substring(5);
					
				  var ssnPattern = /^[0-9]{3}[\- ]?[0-9]{2}[\- ]?[0-9]{4}$/;					
					
					if(ssnPattern.test(val))
					  return val;
					else
					  throw "The social security number is not valid";
				  
        }
	
	    }catch(err){Log.Add("Filters.SSN", err, LogType.Error);}	
    },	
		
    STATE: function(){
 		  try{

	      this.Test = function(Value, dtype, param){
				
				  var _exp = /[a-zA-Z]{2}/g;
					
					if(!_exp.test(Value))
					  throw "The state code must be two letters";
						
					Value = Value.toUpperCase();

				  var states = "AL AK AZ AR CA CO CT DC DE FL GA HI ID IL IN IA KS KY LA ME MD MA MI MN MS MO MT NE NV NH NJ NM NY NC ND OH OK OR PA RI SC SD TN TX UT VT VA WA WV WI WY";
				
				  _exp = new RegExp(Value, "g");
					
					if(states.search(_exp) > -1)
					  return Value;
					else
					  throw "The state code entered was invalid";
				
        }
	
	    }catch(err){Log.Add("Filters.STATE", err, LogType.Error);}	
    },	
		
    TIME: function(){
 		  try{

	      this.Test = function(Value, dtype, param){
				
					var val = Value.toUpperCase();
					
					val = val.replace(/[^0-9AM:]/g, "");
					
					var end = null;
					
					if(val.indexOf("AM")>-1)
					  end = "AM";
					else if(val.indexOf("PM")>-1)
					  end = "PM";
						
					if(end == null)
					  throw "Times must include AM or PM";
						
					val = val.replace(/\s/g, "");
					
					// expression does not end with /g so that only the first match is returned, or null if not found
					var _exp = /\d{1,2}:\d{2}/;
					
					var ma = val.match(_exp);
					
					if(ma == null)
					  throw "Times must be formatted HH:MM AM/PM";
						
					if(typeof ma == "object")
  					ma = ma[0];

					var s = ma.split(":");
					
					var h = parseInt(s[0]);
					
					var m = parseInt(s[1]);
					
					if(h>12)
					  throw "The hour must be less than or equal to 12";
						
					if(h==0)
					  throw "The hour must be greater than 0";
						
					if(m>59)
					  throw "The minute must be less than 60";
						
					if(m<10)
					  m = "0" + m.toString();
					
					return h + ":" + m + " " + end;
					

					
				  
        }
	
	    }catch(err){Log.Add("Filters.SSN", err, LogType.Error);}	
    },					
		
    ZIPCODE: function(){
      try{
      
        this.Test = function(Value, dtype, param)
				{
				  var val = Value.replace(/[^0-9]/g, ""); // replace any non-numeric characters
					
					switch(val.length)
					{
					  case 5:
						  return val;
							break;
							
						case 9:
						  return val.substring(0, 5) + "-" + val.substring(5);
						  break;
							
						default:
						  throw "Zip codes must be 5 digits or 9 digits for zip + 4 codes";
					}
						
        }
				
      }catch(err){Log.Add("Filters.ZipCode", err, LogType.Error);}	
    }		
		
	} // <-- end return 
	
	
	
	
	
	
	
	
	function Convert(Value, dtype)
	{
	  try{
		
		  dtype = dtype.toUpperCase();
		
		  switch(dtype)
			{
			  case "DATE":
				  try{
					  
						return new Date(Value).getTime();
						 
					} catch(err){
					  throw "Could not convert '" + Value + "' to a date";
					}						  
				  break;			

			  case "FLOAT":
				  try{
					  
						return parseFloat(Value);
						 
					} catch(err){
					  throw "Could not convert '" + Value + "' to a floating decimal point number";
					}
				  break;
					
			  case "INTEGER":
				  try{
					  
						return parseInt(Value);
						 
					} catch(err){
					  throw "Could not convert '" + Value + "' to an integer";
					}						  
				  break;							

			  case "STRING":
				  return Value;
				  break;						
				
			}

    }catch(err){Log.Add("Filters.Convert", err, LogType.Error);}			
	}
	
	
} // <-- end Filters

