//
//  Class:
//      VdfValidator
//
//  Contians all code needed for the validation. The class is separated in 
//  four different files: this, Adjustment, Prevention, Validation. This 
//  file contains the code that is needed initialize the validation using an
//  form object. 
//
//  Since:
//      10-12-2005
//  Changed:
//      31-03-2006 Harm Wibier
//          Complete restructure of the validation methods
//  Version:
//      0.9
//  Creator:
//      Data Access Europe (Ruud Tuitert)
//


//  Tab key
var KEY_CODE_TAB = 9;
var KEY_CODE_NON_EDIT = {37:1, 38:1, 39:1, 40:1, 35:1, 36:1, 9:1};

//  Special keys
var KEY_CODE_SPECIAL = {37:1, 38:1, 39:1, 40:1, 35:1, 36:1, 46:1, 8:1, 9:1};
//  37, 38, 39, 40 cursor keys
//  35  end
//  36  home
//  46  delete
//  8   backspace
//  9   tab


/*
Validates the form by search for the VdfValidator object and calling the 
validate method.

Params:
    eForm   Reference to the <form element.
*/
function VdfValidateForm(eForm){
    if(eForm.oVdfValidator != null){
        return eForm.oVdfValidator.validate();
    }else{
        alert("Validator niet gevonden!");
    }
}

/*
Validates the field by searching for the VdfValidator object and calling 
the validateField method.

Params:
    eField  Reference to the field element.
*/
function VdfValidateField(eField){
    var oValidator = VdfValidatorFind(eField);
    
    if(oValidator != null && eField.oVdfField != null){
        return oValidator.validateField(eField.oVdfField);
    }else{
        alert("Validator niet gevonden!");
    }
}

/*
 Initilizes the validator for the form.

Params:
    eForm   Reference to the form element.
Returns:
    Reference to the VdfValidator object.
*/
function VdfValidateInitForm(eForm){
    var oValidator = null;
    
    if(eForm.oVdfValidator == null){
        oValidator = new VdfValidator(eForm);
        oValidator.init();
    }
    
    return oValidator;
}

function VdfValidateClearForm(eForm){
    if(eForm.oVdfValidator != null){
        eForm.oVdfValidator.clear();
    }
}


/*
Params:
    eElement    Reference to an element inside a form that is initialized for 
                validation.
Returns:
    The VdfValidat object that belongs to the element (null if not found).
*/
function VdfValidatorFind(eElement){

     var eForm = browser.dom.searchParent(eElement, 'form');

     if(eForm == null)
         return null;

     return eForm.oVdfValidator;
}


/*
Constructor of the VdfValidator object.

Params:
    eForm   Reference to the form element.
*/
function VdfValidator(eForm){
    this.eForm      = eForm;
    
    this.bOnSubmit  = true;
    
    this.oFields    = {};
}

/*
Initializes the validator by scanning for fields and initializing the 
validation for these fields.
*/
VdfValidator.prototype.init = function(){
    var sField;
    
    this.scanForFields(this.eForm);
    
    for(sField in this.oFields){
        if(typeof(this.oFields[sField] == "object")){
            this.initField(this.oFields[sField]);
        }
    }
    
    this.eForm.oVdfValidator = this;
    
    if(this.bOnSubmit){
        browser.events.addGenericListener("submit", this.eForm, this.onSubmit);
    }
}

/*
Recursive method that scans for field elements (input, select, textarea) and 
creates a VdfField object for them. All found fields are stored by their name 
in this.oFields.

Params:
    eElement The element to scan.
*/
VdfValidator.prototype.scanForFields = function(eElement){
    var iChild, oField, sDataBinding;
    
    //  Detect and add fields directly
    sDataBinding = browser.dom.getVdfAttribute(eElement, "sDataBinding", null);
    if(sDataBinding != null || (eElement.tagName == "INPUT" && eElement.type != "button") || eElement.tagName == "SELECT" || eElement.tagName == "TEXTAREA"){
        if(sDataBinding == null){
            sDataBinding = eElement.name;
        }
        sDataBinding = sDataBinding.toLowerCase();
        
        //  Create VdfField element
        if(eElement.type != null && eElement.type.toLowerCase() == "radio"){
            if(this.oFields[sDataBinding] != null){
                oField = this.oFields[sDataBinding];
                oField.addElement(eElement);
            }else{
                oField = new VdfField(eElement, null, sDataBinding);
            }
        }else{
            oField = new VdfField(eElement, null, sDataBinding);
        }
        
        this.oFields[sDataBinding] = oField;
    }
    
    //  Scan child elements
    for(iChild = 0; iChild < eElement.childNodes.length; iChild++){
        if(eElement.childNodes[iChild].nodeType != 3 && eElement.childNodes[iChild].nodeType != 8){
            this.scanForFields(eElement.childNodes[iChild]);
        }
    }
}

/*
Validates the form by looping through the fields calling validateField.

Returns:
    True if no validation errors occurred.
*/
VdfValidator.prototype.validate = function(){
    var bResult = true, sField;

    for(sField in this.oFields){
        if(typeof(this.oFields[sField] == "object")){
            bResult = (this.validateField(this.oFields[sField]) && bResult);
        }
    }
    
    return bResult;
}

/*
Clears the displayed field errors by calling VdfErrorsClearField for all the
fields.
*/
VdfValidator.prototype.clear = function(){
    var sField;

    for(sField in this.oFields){
        if(typeof(this.oFields[sField] == "object")){
            VdfErrorsClearField(this.oFields[sField]);
        }
    }
}





//
//  Initializes field by attaching the nessacary events and setting the 
//  nessacary attributes.
//
//  Params:
//      oField  VdfField object
//
VdfValidator.prototype.initField = function(oField){
    var sType = oField.getVdfAttribute("sDataType", "ascii");

    var iDataLength = oField.getVdfAttribute("iDataLength");

    if(oField.getVdfAttribute("bValidatePrevent", true)){
        this.preventField(oField, sType);
    } 
    
    if(oField.getVdfAttribute("bValidateAdjust", true)){
        this.adjustField(oField, sType);
    }
    
    if(oField.getVdfAttribute("bValidateClient", true)){
        oField.addKeyListener(this.onValidateField);
    }
}

//
//  Attaches the (key)events for the prevention methods.
//
//  Params:
//      oField  Field to prevent
//      oVdfForm Form that owns the field
//      sType   Typ of the field
//
VdfValidator.prototype.preventField = function(oField, sType){
    var iMaxLength = 0, sDateMask = null, iDataLength, iPrecision, sDecimalSeparator;
    
    //  Display only
    if(oField.getVdfAttribute("bDisplayOnly")){
        oField.addGenericListener("keypress", this.preventDisplayOnly);
    }
    
    //  No enter
    if(oField.getVdfAttribute("bNoEnter")){
        oField.addGenericListener("keypress", this.preventNoEnter);
    }
    
    //  Type prevention
    if(sType == "bcd"){
        //  Make sure the decimal separator is set
        sDecimalSeparator = oField.getVdfAttribute("sDecimalSeparator", ",");
        oField.setVdfAttribute("sDecimalSeparator", sDecimalSeparator);
        
        oField.addGenericListener("keypress", this.preventNumeric);
    }else if(sType == "date"){
        sDateMask = oField.getVdfAttribute("sDateMask", "DD-MM-YYYY");
        oField.setVdfAttribute("sDateSeparator", this.getDateSeparator(sDateMask));
        oField.addGenericListener("keypress", this.preventDate);
    }
    
    //  Maximum length
    //  Determine
    if(sType == "ascii" || sType == "text"){
        iMaxLength = oField.getVdfAttribute("iDataLength");
    }else if(sType == "bcd"){
        iPrecision = parseInt(oField.getVdfAttribute("iPrecision", 0));
        iDataLength = oField.getVdfAttribute("iDataLength", 0);
        
        if(iDataLength > 0 || iPrecision > 0){
            iMaxLength = oField.getVdfAttribute("iDataLength");
    
            if(parseInt(oField.getVdfAttribute("iPrecision")) > 0){
                iMaxLength++;
            }
            iMaxLength++;
        }
    }else if(sType == "date"){
        iMaxLength = sDateMask.length;
    }

    //  Set
    if(iMaxLength > 0){
        if(oField.sType == "textarea"){
            oField.setVdfAttribute("iMaxLength", iMaxLength);
            oField.addGenericListener("keypress", this.preventMaxLength);
        }else{
            oField.setAttribute("maxLength", iMaxLength);
        }
    }
 }
 
//
//  Attaches the events that handle the value adjustment of the field.
//
//  Params:
//      oField  Field to adjust
//      oVdfForm Form to wich the field belongs
//      sType   Type of the field
//
VdfValidator.prototype.adjustField = function(oField, sType){
    var sMask, sCheck, iPrecision, sDateMask = null, sDecimalSeparator = null, iDataLength;
    
    //  Autofind
    if(oField.getVdfAttribute("bAutoFind")){
        oField.addKeyListener(this.adjustAutoFind);
    }
    
    //  Autofind GE
    if(oField.getVdfAttribute("bAutoFind_GE")){
        oField.addKeyListener(this.adjustAutoFindGE);
    }
    
    //  Capslock
    if(oField.getVdfAttribute("bCapsLock")){
        if(browser.isIE || oField.getType() != "text"){
            oField.addGenericListener("keypress", this.adjustCapslockIE);
        }else{
            oField.getElement().style.textTransform = "uppercase";
        }
		oField.addGenericListener("blur", this.adjustCapslock);
    }  
    
    //  Date
    if(sType == "date"){
        sDateMask = oField.getVdfAttribute("sDateMask", "DD-MM-YYYY");
        oField.setVdfAttribute("sDateMask", sDateMask);
        oField.setVdfAttribute("sDateSeparator", this.getDateSeparator(sDateMask));
        oField.addGenericListener("keyup", this.adjustDate);
    }
    
    //  Numeric
    if(sType == "bcd"){
        iPrecision = parseInt(oField.getVdfAttribute("iPrecision", 0));
        sDecimalSeparator = oField.getVdfAttribute("sDecimalSeparator", ",");
        iDataLength = oField.getVdfAttribute("iDataLength", 0);
        if(iDataLength > 0 || iPrecision > 0){
            oField.setVdfAttribute("iDataLength", iDataLength);
            oField.setVdfAttribute("iPrecision", iPrecision);
            oField.setVdfAttribute("sDecimalSeparator", sDecimalSeparator);
            oField.addGenericListener("keyup", this.adjustNumeric);
        }
    }
    
    //  Mask
    sMask = oField.getVdfAttribute("sMask");
    if(sMask != null && sMask != ""){
        oField.setVdfAttribute("sMask", sMask);
        oField.addGenericListener("keyup", this.adjustMask);
    }
    
    //  Check
    sCheck = oField.getVdfAttribute("sCheck")
    if(sCheck != null && sCheck != ""){
        oField.setVdfAttribute("sCheck", sCheck);
        oField.addGenericListener("keyup", this.adjustCheck);
    }
}

//
//  Calls the clienside validation (if enabled) and if no client-side errors the
//  server-side validation (if enabled) is called.
//
//  Params:
//      oField          Field to validate
//      bValidateServer If false no server validation is done (optional, 
//                      default true)
//  Returns:
//      False if validation failed
// 
VdfValidator.prototype.validateField = function(oField){
    var bResult = true;
   
    if(oField.getVdfAttribute("bValidateClient", true)){
        bResult = (bResult && this.validateFieldClient(oField));
    }
    return bResult;
}

//
//  Performes client-side validation.
//
//  Params:
//      oField  Field to validate
//  Returns:
//      False if validation failed
//      
VdfValidator.prototype.validateFieldClient = function(oField){
    var sMask, sDateMask, sCheck, iMaxLength, sMinValue, sMaxValue, iDataLength, iPrecision;
    var oVdfForm = this.oVdfForm;
    var sType = oField.getVdfAttribute("sDataType");
    var bResult = true, bRequired = true;
    
    //  Clear all errors on the field
    VdfErrorsClearField(oField);
    
    //  Custom validation in onValidate event of VdfField
    bResult = (oField.onValidate(sType));
    
    //  Display only
    if(oField.getVdfAttribute("bDisplayOnly")){
        bResult = (this.validateDisplayOnly(oField) && bResult);
    } 

    //  Find required
    if(bRequired &&  oField.getVdfAttribute("bFindReq")){
        bRequired = this.validateFindRequired(oField, sType);
        
        bResult = (bRequired && bResult);
    }

    //  Required
    if(bRequired && oField.getVdfAttribute("bRequired")===true){
        bRequired = this.validateRequired(oField, sType);
        bResult = (bRequired && bResult);
    }	
    
	if(bRequired && oField.getVdfAttribute("bRequired")==="semi"){
        bRequired = this.validateSemiRequired(oField, sType);
        bResult = (bRequired && bResult);
    }
    
    //  Type validation
    if(sType == "bcd"){
        bResult = (this.validateNumeric(oField, oField.getVdfAttribute("sDecimalSeparator", ",")) && bResult);
    }else if(sType == "date"){
        sDateMask = oField.getVdfAttribute("sDateMask", "DD-MM-YYYY");
        bResult = (this.validateDate(oField, sDateMask, this.getDateSeparator(sDateMask)) && bResult);
    }
    
    //  Mask
//    sMask = oField.getVdfAttribute("sMask");
//    if(sMask != null && sMask != ""){
//        bResult = (this.validateMask(oField, sMask) && bResult);
//    }
    
    //  Check
    sCheck = oField.getVdfAttribute("sCheck");
    if(sCheck != null && sCheck != ""){
        bResult = (this.validateCheck(oField, sCheck) && bResult);
    }
    
    //  Maximum length
    if(sType == "bcd"){
        iDataLength = oField.getVdfAttribute("iDataLength", oField.getVdfAttribute("iMaxLength", -1));
        iPrecision =  oField.getVdfAttribute("iPrecision", -1);
        
        if(iDataLength >= 0 && iPrecision >= 0){
            bResult = (this.validateMaxLengthNum(oField, iDataLength, iPrecision, oField.getVdfAttribute("sDecimalSeparator", ",")) && bResult);
        }
    }else{
        if(sType == "date"){
            iMaxLength = sDateMask.length;
        }else{
            iMaxLength = oField.getVdfAttribute("iDataLength", -1);
        }
        
        if(iMaxLength >= 0){
            bResult = (this.validateMaxLength(oField, iMaxLength) && bResult);
        }
    }
    
    //  Range
    if(sType == "bcd"){
        sMinValue = oField.getVdfAttribute("sMinValue");
        if(sMinValue != null && sMinValue != ""){
            bResult = (this.validateMinValue(oField, sMinValue) && bResult);
        }

        sMaxValue = oField.getVdfAttribute("sMaxValue");
        if(sMaxValue != null && sMaxValue != ""){
            bResult = (this.validateMaxValue(oField, sMaxValue) && bResult);
        }
    }

    return bResult;
}

//
//  Gets the date mask separator from the mask
//
//  Params:
//      sMask   Mask
//  Returns:
//      Separator used in the mask
//
//  PRIVATE
VdfValidator.prototype.getDateSeparator = function(sMask){
    var iChar, sChar;
    
    for(iChar = 0; iChar < sMask.length; iChar++){
        sChar = sMask.toUpperCase().charAt(iChar);
        if(sChar != 'M' && sChar != 'D' && sChar != 'Y'){
            return sChar;
        }
    }
    
    return null;
}

//
//  Fetches onkeypres event from the form fields and validates if needed (on 
//  tab). Event is cancelled on validation errors.
//
//  Params:
//      e   Event object on some browsers
//
//  PRIVATE
VdfValidator.prototype.onValidateField = function(e){
    var oSource, oVdfValidator, oVdfField;
    
    if(!browser.events.canceled(e) && browser.events.getKeyCode(e) == 9 && !e.shiftKey){
        oSource = browser.events.getTarget(e);
        if(oSource == null) return false;
        
        oVdfField = oSource.oVdfField;
        if(oVdfField == null) return false;
        
        oVdfValidator = VdfValidatorFind(oSource);
    
    
        if(oVdfValidator != null && !oVdfValidator.validateField(oVdfField)){
            browser.events.stop(e);
            return false;
        }
    }
    
    return true;
}

VdfValidator.prototype.onSubmit = function(e){
    var oSource;
    
    if(!browser.events.canceled(e)){
        oSource = browser.events.getTarget(e);
        
        if(!VdfValidateForm(oSource)){
            browser.events.stop(e);
            return false;
        }
    }
    
    return true;
}
