// Validator.js
//
//    @author kcowan
//
//    
//    Validates forms
//    Dependencies: bmi_pagemaker.js
//    Supports the following types of validation:
//      1) Required
//      2) Pattern
//      3) Expression
//      4) Number
//      5) NumberLength
//      6) Selected
//      7) HTML (cleans brackets)
//  
//
//******************************************************************************
/* EXAMPLES
//******************************************************************************

		//addValidationElement(id, name, type, patternToMatch, displayMsgBegin, displayMsgEnd)
		
		addValidationElement("user.personName.firstName","First Name", "Required", null, "The Field ", " is required");
		addValidationElement("user.personName.lastName","Last Name", "Required", null, "The Field ", " is required");
		addValidationElement("user.email","Email", "Pattern", "@", "The Field ", " is required");
		addValidationElement("user.voiceNumber.areaCode","Area Code", "Number", null,"The Field ", " is required");
		addValidationElement("user.voiceNumber.number","Voice Number", "NumberLength", "7","The Field ", " is required");
		addValidationElement("user.alertsPersistence","Alerts Persistance", "Expression", "regExp string foo", "The Field ", " is required");


		Example element event methods:
		<form  onsubmit="return validateAndSubmit()">
		<input onblur="validateElement(this.name)" onchange="validateElement(this.name)" >

*/


//******************************************************************************
// GLOBAL DEFINITIONS
//******************************************************************************

var ALERT_OUT = "alert";
var PAGE_OUT  = "page";
var PAGE_OUT_ID = "valErrors";
var NO_SELECTION = "noSelection";

//var ERROR_IMAGE = "<IMG src='../images/errorIcon.gif' border=0>&nbsp;";
var ERROR_IMAGE = "<IMG src='../images/icon_constraint_violation.gif' border=0>&nbsp;";
var SUCCESS_IMAGE = "<IMG src='../images/icon_check.gif' border=0>&nbsp;";
var INFO_IMAGE    = "<IMG src='../images/icon_message.gif' border=0>&nbsp;";
var FAIL = "fail";
var PASS = "pass";


var _buffer = ""; // global output buffer



//******************************************************************************
// OBJECT DEFINTIONS
//******************************************************************************

function ValidationManager(){}
function ValidationElement(){}
function ISOCharacter(){}
function ISOManager(){}

//******************************************************************************
// GET/SET METHODS
//******************************************************************************
function getValidatorElementById(eleId){

		for(i=0;i<valMgr.validations.length; i++){

			if(valMgr.validations[i].id == eleId){
				return valMgr.validations[i];
			}
		}
		return null;
}

function setValidations(vals){
	valMgr.validations = vals;
}
function getValidations(){
	return valMgr.validations;
}
function setButtons(buts){
	valMgr.buttons = buts;
}
function getButtons(){
	return valMgr.buttons;
}
function setOutputMethod(stdOut){ // should be either 'alert' or 'page'
	valMgr.outputMethod = stdOut;
}
function getOutputMethod(){
	return valMgr.outputMethod;
}
function getOutputLayer(){
	elm = document.getElementById(PAGE_OUT_ID);
	return elm;
}

function getValidationIcon(valElement){

		if(valElement.hasPassed){
			return SUCCESS_IMAGE;
		} else {
			return ERROR_IMAGE;
		}

}

function setStyleActive(itemId){

	var elm = document.getElementById(itemId);
		elm.style.backgroundColor = "006666";
		elm.style.color = "white";
}

function setStyleInactive(itemId){

	var elm = document.getElementById(itemId);
	elm.style.backgroundColor = "silver";
	elm.style.color = "gray";
	


}

//******************************************************************************
// ACTION METHODS
//******************************************************************************

// VALIDATE ELEMENT
// method called to validate an Element
// e.g. onblur="validateElement(this.name)"
//------------------------------------------------------
function validateElement(elementId){
 
	try{
	if(elementId){
      valElement = getValidatorElementById(elementId);
	  valElement.hasPassed = false;
	 
	  if(valElement.isPresent){
	  var evalThis = eval("check"+valElement.type+"('"+valElement.id+"')");

		if(!evalThis){
			//alert("validation failed..");
			doNotifyValidationError(valElement);
		} else {
			//alert("test passed!");

			valMgr.validations[i].hasPassed = true;
			doNotifyValidationSuccess(valElement);
			//valMgr.validations[i].hasPassed = false;
			
		}

	  }
		
	}
	
	 checkElements();
	}catch(anErr){}
 

}

// VALIDATE
// Global validate function.  
// runs through all validator elements
// e.g.  onclick="validate()"
//--------------------------------------------------------

function validate(){

	try{

		valMgr.passedTests = new Array();
		var hasPassed = true;
		
		//alert("validating "+valMgr.validations.length+" elements");

	for(i=0; i<valMgr.validations.length; i++){

		// do a check and return true or false
		
		var type = valMgr.validations[i].type;
		
         if(valMgr.validations[i].isPresent){
	         valElement = valMgr.validations[i];
	         valElement.hasPassed = false;
		     var evalThis = eval("check"+type+"('"+valMgr.validations[i].id+"')");
			     if(!evalThis){
				     //alert(" validation fail: "+valMgr.validations[i].name);
				     valMgr.passedTests.push(FAIL);
				     valMgr.validations[i].hasPassed = false;
				     //doNotifyValidationError(valElement);
				     hasPassed = false;
			     }else{
				     //alert(" validation success: "+valMgr.validations[i].name);
				     valMgr.validations[i].hasPassed = true;
				     valMgr.passedTests.push(PASS);
				     //doNotifyValidationSuccess(valElement);
			     }

	       } // end if present

	    } // end for
	
	   var allTestsPassed = checkElements();
	   if(hasPassed){
		  // alert("tests passed");
		  //enableButtons();
	   } else {
		//alert("tests failed");
		doNotifyValidationError();
		//disableButtons();
	    }

	return hasPassed;
	}catch(anErr){
	  //alert("an error occured while validating "+anErr.message);
	}
	
}

// DO NOTIFY VALIDATION ERROR
// renders/returns validation status error
//-----------------------------------------------------
function doNotifyValidationError(valElement){

		
		if(getOutputMethod() == PAGE_OUT){
			elm = getOutputLayer();
			elm.innerHTML = renderReport();
		}else{
			alert(renderReportPlainText());
		}
		return;
}

// DO NOTIFY VALIDATION SUCCESS
// renders /returns validation status success
//-------------------------------------------------------
function doNotifyValidationSuccess(valElement){

		
		if(getOutputMethod() == PAGE_OUT){
			elm = getOutputLayer();
			elm.innerHTML = renderReport();
		}
		return;
}

// DO NOTIFICATION
// Global notification method
// e.g. diaplay("some message to user");
//-------------------------------------------------------
function doNotification(display){

	if(getOutputMethod() == PAGE_OUT){
			elm = getOutputLayer();
			elm.innerHTML = "<div id=notify class=message>"+INFO_IMAGE+"&nbsp;"+display+"</div> ";
		} else {
			alert(display);
		}
		return;
}

// DISABLE BUTTONS
//-------------------------------------------------
function disableButtons(){

		for(i=0; i<valMgr.buttons.length; i++){
			disableThis(valMgr.buttons[i]);

		}
		return;
}

// ENABLE BUTTONS
//---------------------------------------------------
function enableButtons(){
		//alert("enable buttons");
		doNotification("All fields have validated");
		//valMgr.testsComplete = true;
		//alert(valMgr.buttons.length);

		for(i=0; i<valMgr.buttons.length; i++){
			//alert("getting: "+valMgr.buttons[i]);
			elm = document.getElementById(valMgr.buttons[i]);
			//alert("enable "+elm.id);
			elm.style.backgroundColor = "006666";
	        elm.style.color = "white";
			elm.disabled = false;
			elm.focus();
		}

		return;
}
// DISABLE THIS
// disables a button
//---------------------------------------------------------
function disableThis(elmId){
	elm = document.getElementById(elmId);
	
	elm.style.backgroundColor = "silver";
	elm.style.color = "white";
	elm.disabled = true;
	return;

}

// ENABLE THIS
// enables a button
//---------------------------------------------------------
function enableThis(elmId){
	elm = document.getElementById(elmId);
	
	elm.style.backgroundColor = "000066";
	elm.style.color = "white";
	elm.disabled = false;
	return;

}

function validateAndSubmit(){

	var testsPassed = validate();
	//alert("return "+testsPassed);
	
	
	if(!testsPassed){
		return false;
	} else {
		return true;
	}
	
}

//******************************************************************************
// VALIDATE METHODS
//******************************************************************************
//
//  These methods are called via eval of the valElement.type 
//  returns true if test passes false if test fails
//  each method begins with the "check" prefix couple with a valElement.type


// CHECK REQUIRED
// returns true if value is set / false if value is null or empty
//---------------------------------------------------------------

function checkSelected(valElementId){
		//alert(" check "+valElement.type);
		valElement = getValidatorElementById(valElementId);
		elm = document.getElementById(valElement.id);
		
		if(elm.checked == true || elm.selected == true ){
			//alert("Selected"+elm.value);
			return true;
		}else {
			return false;
			
		}

		return false;
}

function checkRequired(valElementId){
		//alert(" check "+valElement.type);
		valElement = getValidatorElementById(valElementId);
		elm = document.getElementById(valElement.id);
		//alert("required: "+valElement.id);

		var elmValue = trim(elm.value);
		if(elmValue == "" || elm.value == null || elm.value == NO_SELECTION ){
			return false;
		}else {
			return true;
			
		}

		return false;
}


// CHECK PATTERN
// returns true if no matches found // false if matches found
//-----------------------------------------------------------
function checkPattern(valElementId){
		//alert(" check "+valElement.type);
		valElement = getValidatorElementById(valElementId);
		var pattern = new String(escape(valElement.patternToMatch));
		elm = document.getElementById(valElement.id);
		var value = elm.value;
		//alert(value);
		var checkString = new String(value);
		result = checkString.indexOf(new String(pattern));
		//alert("pattern: "+pattern+" result  "+result);
		if(result == -1){
			
			return false;
		} else {
			
			return true;
		}

     return false;
     
}

// CHECK EXPRESSION
// Takes a reqular expression and looks for matches in the string
//-----------------------------------------------------------------
function checkExpression(valElementId){
		//alert(" check "+valElement.type);
		valElement = getValidatorElementById(valElementId);
		regExp = new RegExp(new String(valElement.patternToMatch),"g");
		elm = document.getElementById(valElement.id);
		var value = new String(elm.value);
		//alert(value);
		result = value.match(regExp);
		
		if(result == null){
			
			return false;
		} else {
			
			return true;
		}

	return false;
}
// CHECK NUMBER
// returns true if is a number// false if NaN
//------------------------------------------------------------

function checkNumber(valElementId){
	//alert(" check "+valElement.type);
	valElement = getValidatorElementById(valElementId);
	elm = document.getElementById(valElement.id);
	var value = elm.value;
	if(value == "" || value == null){ return false; }

	if(Math.floor(value) >= 0 || Math.floor(value)<= 0){
		return true;
	} else {
		return false;
	}

	return false;
}

// CHECK NUMBER LENGTH
// checks if number, then checks digits
// returns true if ok/ false if test fails
//-------------------------------------------------------------

function checkNumberLength(valElementId){
	//alert(" check "+valElement.type);
	valElement = getValidatorElementById(valElementId);
	elm = document.getElementById(valElement.id);
	var value = elm.value;
	patternLength = valElement.patternToMatch;
	//alert(" check "+valElement.patternToMatch);

	var isNumber = checkNumber(valElementId);
	
	if(isNumber){
		var numString = new String(value);
		if(numString.length == patternLength){
			return true;
		} else {
			return false;
		}
	} else {
		//alert("apparently not a number");
	}

	return false;
}

// CHECK HTML
// checks field for html strings and replace with &lt; &gt;
//----------------------------------------------------------------
function checkHTML(valElement){

	elm = document.getElementById(valElement.id);
	var stringToClean = elm.value;

    cstring = "";
	var gt = ">";
	var lt = "<";

	 regExp1 = /lt/g;
	 targetChar1 = "&lt;";

	 cstring = stringToClean.replace(regExp1, targetChar1);

	  regExp1 = /gt/g;
	 targetChar1 = "&gt;";

	 var fstring = cstring.replace(regExp2, targetChar2);
	 elm.value = fstring;

	 return fstring;
	
}

// CHECK TESTS
// Checks the status of current test set.
//  returns true if all tests have passed
//----------------------------------------------------------------
function checkTests(){
    //alert("check tests "+valMgr.passedTests.length);
	var bool = "enable";
	for(i=0; i<valMgr.passedTests.length; i++){

	    if(valMgr.passedTests[i] == FAIL){
			bool = "disable";
		}
	}
	
	//alert(bool+" buttons");
	eval(bool+"Buttons()");

}

// CHECK ELEMENTS
// checks tests on elements
//------------------------------------------------
function checkElements(){

		var bool = true;
	for(i=0; i<valMgr.validations.length; i++){

		elm = document.getElementById(valMgr.validations[i].id);

		if(!valMgr.validations[i].hasPassed && valMgr.validations[i].isPresent){
			bool = false;
		}
		
	}

	if(bool){
		enableButtons();
		//alert("check elements passed");
	} else {
		//disableButtons();
		//alert("check element fail");
	}
	
	return bool;

}

function resetValidation(){

	for(i=0; valMgr.validations.length; i++){
		valMgr.validations[i].hasPassed = false;
	}
}

//******************************************************************************
// RENDERER METHODS
//******************************************************************************


// RENDER REPORT PLAIN TEXT
// Used for rendering alert status
//--------------------------------------------------------
function renderReportPlainText(){

        _buffer = "";

		for(i=0; i<valMgr.validations.length; i++){
			valElement = valMgr.validations[i];

			_buffer += renderValidationDisplay(valElement)+" \r";
			
		}

	return _buffer;

}

// RENDER REPORT
// used for page out display
//-----------------------------------------------------------
function renderReport(){

        _buffer = "";

		for(i=0; i<valMgr.validations.length; i++){
			valElement = valMgr.validations[i];

			if(valElement.isPresent){
			_buffer += "<div id='"+valElement.id+"_layer' class=message>"+getValidationIcon(valElement)+"&nbsp;"+renderValidationDisplay(valElement)+"</div>";
			}
			
		}

	return _buffer;

}


// RENDER VALIDATION DISPLAY
// returns validatio display message
//-----------------------------------------------------------
function renderValidationDisplay(valElement){
    
	var disp = "";

	if(valElement.hasPassed){
       disp = " "+valElement.name+"&nbsp;passed validation.";
	} else {
	   disp = valElement.displayMsgBegin+"&nbsp;"+valElement.name+"&nbsp;"+valElement.displayMsgEnd;
	}
	return disp;
}



//******************************************************************************
// OBJECT INSTANTIATION/ ASSOCIATION METHODS
//******************************************************************************


// ADD VALIDATION ELEMENT
//--------------------------------------------------
// an example: ("elementIdFoo", "Pattern", false, true, false, "@", "Element", "must contain a @ sign"
function addValidationElement(id, name, type, patternToMatch, displayMsgBegin, displayMsgEnd){

	valEle = new ValidationElement();
	
	valEle.id = id;
	valEle.name = name;
	if(!type){
		var type = "Required";
	}

	valEle.type = type;
	valEle.patternToMatch = patternToMatch;

     if(!displayMsgBegin){
		var displayMsgBegin = "TheField ";
	 }
	 if(!displayMsgEnd){
		 displayMsgEnd = " is invalid type: "+type;
	 }

	 elm = document.getElementById(id);
	 if(elm){
		 valEle.isPresent = true;
		
	 }else {
		 valEle.isPresent = false;
	 }
	valEle.displayMsgBegin = displayMsgBegin;
	valEle.displayMsgEnd   = displayMsgEnd;
	valEle.hasPassed       = false;

	
	valMgr.validations.push(valEle);
	//alert("add element "+valEle.name+" to val mgr length: "+valMgr.validations.length);

}

// ADD BUTTON
// add button to disable until form passes
//--------------------------------------------------------------
function addButton(id){

	valMgr.buttons.push(id);
	return;
}

function addISOCharacter(character, ISOString){

	isoChar = new ISOCharacter();
	isoChar.id = isoMgr.isoChars.length+1;
	isoChar.character = character;
	isoChar.ISOString = ISOString;

	isoMgr.isoChars.push(isoChar);
}

function _iniISOManager(){

	this.isoChars = new Array();
}


//******************************************************************************
// INIT METHODS
//******************************************************************************


// INI VALIDATION MANAGER
// Called onload by default
// internal method to create valMgr
//---------------------------------------------------------------------
function _iniValidationManager(){

	this.validations = new Array();
	this.passedTests = new Array();
	this.outputMethod = PAGE_OUT;
	this.buttons      = new Array();
	this.report       = "";
	this.errors       = 0;
	this.testsComplete = false;
	// should reflect all calcuation methods available
	this.types = ["Required","Pattern", "Number", "NumberLength"];

	//alert("val manager ini okay");

}

// ISO CHARACTERS
// These are loaded into the ISOManager that will scan for all chars loaded and replace them with ISO strings
//**********************************************************************************************************

function loadISOCharacters(){

	//addISOCharacter(character, ISOString);
	addISOCharacter('"', "&quot;");
	addISOCharacter("'", "&rsquo;");
	addISOCharacter("<", "&lt;");
	addISOCharacter(">", "&gt;");

}

//******************************************************************************
// UTILITY METHODS
//******************************************************************************

// TRIM SPACES
//**********************************************************************************************************
function trim(strValue){
   var currentStr = strValue;
   var numChars = currentStr.length;
   var numSpaces =0;
   for(var i=numChars - 1 ; i>=0; i--){
    if(currentStr.charAt(i)== " "){
        numSpaces++;
    }else{
        break;
    }
   }
   var end = numChars - numSpaces;
   newStr = currentStr.substring(0, end);
   return newStr;
}

//******************************************************************************
// PROTOTYPE OBJECT DEFINTIONS
//******************************************************************************

ValidationManager.prototype.ini = _iniValidationManager;
ISOManager.prototype.ini        = _iniISOManager;

// ini validation manager
valMgr = new ValidationManager();
valMgr.ini();
// ini iso manager
isoMgr = new ISOManager();
isoMgr.ini();

//alert("val mgr loaded");

self.status = "validator loaded okay";

//******************************************************************************
// DEBUG METHODS
//******************************************************************************