	
// base class for other validators
var validatorBase = new Class(
{
    validate: function(el)
    {
        console.log("override this method to validate value " + el.value);
    },

    getMessage: function(el)
    {
        return 'this is the message if it fails';
    },

    proceedWithValidation: function(el)
    {
        return true;
    }
		
		
});

/**
 * Submit check
 */
var SubmitCheck = new Class({
        
    Extends: validatorBase,
    message: 'submit',

    validate: function(el) {
        return true;
    },

    getMessage: function(el)
    {
        return '';
    }

});

//
// Validator which checks a regex and reports the given message if it
// doesn't match
var RegexValidator = new Class({
    Extends: validatorBase,
    message: '',
    initialize: function(regex,msg)
    {
        this.pattern = regex;
        this.message = msg;
    },

    validate: function(el) {
        return (el.value.match(this.pattern));
    },

    getMessage: function( el )
    {
        return this.message;
    }

});

//
// Validator which checks a regex and reports the given message if it
// doesn't match
var StrongPasswordCheck = new Class({
    Extends: validatorBase,
    message: '',
    initialize: function(regex,msg)
    {
        this.pattern = regex;
        this.message = msg;
    },

    validate: function(el) {
        return (el.value.match(/[A-Z]/)&& el.value.match(/[a-z]/)&&el.value.match(/[0-9]/));
    },

    getMessage: function( el )
    {
        return "This must contain lowercase (a-z), uppercase(A-Z) and digits(0-9) to be a strong password.";
    }

});

// These classes take specific args like range values and so must be
// individually instantiated
// as required.

// Confirm that the value is in a given range
var range_chk = new Class({
    Extends: validatorBase,
    initialize: function(low,high){
        this.low = parseInt(low);
        this.high = parseInt(high);
    },

    validate: function(el) {
        var val = parseInt( el.value );
        return ( (val>=this.low) && (val<=this.high) );
    },
	
    getMessage: function(el)
    {
        return "The value must be between "+this.low+" and "+this.high;
    }


});

// Confirm that the value is different to another field
var different_chk = new Class({
    Extends: validatorBase,
    initialize: function(otherId){
        this.otherEl = $(otherId);
    },

    validate: function(el)
    {
        return ( el.value != this.otherEl.value );
    },
	
    getMessage: function(el)
    {
        return "The value of " + el.name + " must be different to the value of " + this.otherEl.name;
    }
});

var is_optional_chk = new Class({
    Extends: validatorBase,
    initialize: function()
    {
    },

    proceedWithValidation: function( el )
    {
        var value = el.getPropertyValue('value');

        return value.match(/^.+$/);
    },
    validate: function( el )
    {
        return true;
    }

});



// Place this first in the list of validators to skip validation if it is
// not relevent (based on the value of another item)
var skip_unless = new Class({
    Extends: validatorBase,
    initialize: function(otherId, enabledWhen)
    {
        this.otherId = otherId;
        this.enabledWhen = enabledWhen;
    },

    proceedWithValidation: function( el )
    {
        var controlElement = $$('input[checked],[name=' + this.otherId + ']')[0];

        if( typeof(controlElement) != "undefined" )
        {
            return controlElement.defaultValue == this.enabledWhen;
        }

        controlElement = $$('input[name=' + this.otherId + ']')[0];
        return controlElement.value == this.enabledWhen;
        
    },
    validate: function( el )
    {
        return true;
    }

});


// Confirm that the value is matches another field
var confirm_chk = new Class({
    Extends: validatorBase,
    initialize: function(otherId){
        this.otherEl = $(otherId);
    },

    validate: function(el) {
        return (el.value==this.otherEl.value);
    },
	
    getMessage: function(el)
    {
        return "The following two values must match. Please retype them";
    }

});

// Confirm that the value length is in a range
var length_range_chk = new Class({
    Extends: validatorBase,
    initialize: function(minLen,maxLen){
        this.minLen = minLen;
        this.maxLen = maxLen;
    },

    validate: function(el) {
        var len = el.value.length;
        return (len>this.minLen && len<this.maxLen);
    },
	
    getMessage: function(el)
    {
        return "The length of "+el.name+" must be between " + this.minLen + " and " + this.maxLen;
    }

});

// Confirm that the value length is at least some value
var length_min_chk = new Class({
    Extends: validatorBase,
    initialize: function(minLen){
        this.minLen = minLen;
    },

    validate: function(el) {
        var len = el.value.length;
        return (len>=this.minLen );
    },
	
    getMessage: function(el)
    {
        return "The length of "+el.name+" must be greater than " + this.minLen;
    }

});


// Confirm that the value length is at most some value
var length_max_chk = new Class({
    Extends: validatorBase,
    initialize: function(maxLen){
        this.maxLen = maxLen;
    },

    validate: function(el) {
        var len = el.value.length;
        return (len<=this.maxLen );
    },
	
    getMessage: function(el)
    {
        return "The length of "+el.name+" must be less than " + this.maxLen;
    }

});

// Confirm that the value length is exactly some value
var length_match_chk = new Class({
    Extends: validatorBase,
    initialize: function(matchLen){
        this.matchLen = matchLen;
    },

    validate: function(el) {
        var len = el.value.length;
        return (len==this.matchLen );
    },
	
    getMessage: function(el)
    {
        return "The length of "+el.name+" must be " + this.matchLen;
    }

});

var word_count_base_chk = new Class({
    Extends: validatorBase,
    getWordCount: function(str)
    {
        var words = str.replace(/[ \t\v\n\r\f\p]/m, ' ').replace(
            /[,.;:]/g, ' ').clean().split(' ');
        return words.length;
    }

});

var word_count_min_chk = new Class({
    Extends: word_count_base_chk,
    initialize: function(minLen){
        this.minLen = minLen;
    },

    validate: function(el) {
        var len = this.getWordCount(el.value);
        return (len>this.minLen );
    },
	
    getMessage: function(el)
    {
        return "This field must contain at least "+this.minLen+" words." ;
    }

});

var word_count_max_chk = new Class({
    Extends: word_count_base_chk,
    initialize: function(maxLen){
        this.maxLen = maxLen;
    },

    validate: function(el) {
        var len = this.getWordCount(el.value);
        return (len<this.maxLen );
    },
	
    getMessage: function()
    {
        return "This field must contain at most "+this.maxLen+" words." ;
    }

});

var word_count_range_chk = new Class({
    Extends: word_count_base_chk,
    initialize: function(minLen,maxLen){
        this.minLen = minLen;
        this.maxLen = maxLen;
    },

    validate: function(el) {
        var len = this.getWordCount(el.value);
        return (len>=this.minLen && len<=this.maxLen );
    },
	
    getMessage: function(el)
    {
        return "This field must contain between "+this.minLen+" and "+this.maxLen+" words." ;
    }

});



//Confirm that the value length is exactly some value
var checkbox_chk = new Class({
    Extends: validatorBase,

    validate: function(el) {
        return el.checked;
    },
	
    getMessage: function(el)
    {
        return "This item must be checked to continue.";
    }

});

function getRadioButtonSelection( form, elementName )
{
    var buttonGroup = form[ elementName ];

    for ( var i = 0; i < buttonGroup.length; i++)
    {
        if (buttonGroup[i].checked)
        {
            return buttonGroup[i].value;
        }
    }

    return "";

}

var radiobox_chk = new Class({
    Extends: validatorBase,

    validate: function(el) {

        var nlButtonGroup = this.form[el.getProperty("name")];
        el.group = nlButtonGroup;
        var cbCheckeds = false;

        for ( var i = 0; i < nlButtonGroup.length; i++)
        {
            if (nlButtonGroup[i].checked)
            {
                cbCheckeds = true;
            }
        }
        return cbCheckeds;
		
    },
	
    getMessage: function(el)
    {
        return "Please select an option";
    }

});
		
var select_chk = new Class({
    Extends: validatorBase,

    validate: function(el) {

        return el.selectedIndex > 0;
			
    },
		
    getMessage: function()
    {
        return "Please choose a value";
    }

});


var credit_card_chk = new Class({
    Extends: validatorBase,

    validate: function(el)
    {
        return this.isValidCardNumber(el.value );
    },

    isDigit: function(c)
    {
        var strAllowed = "1234567890";
        return (strAllowed.indexOf (c) != -1);
    },

    getMessage: function(el)
    {
        return "This is not a valid Credit Card number.<br>(" + el.value+")";
    },

    isValidCardNumber: function (strNum)
    {
        var nCheck = 0;
        var nDigit = 0;
        var bEven = false;
        for ( n = strNum.length - 1; n >= 0; n-- )
        {
            var cDigit = strNum.charAt ( n );
            if (this.isDigit( cDigit ))
            {
                nDigit = parseInt(cDigit, 10);
                if (bEven)
                {
                    if ((nDigit *= 2) > 9)
                        nDigit -= 9;
                }
                nCheck += nDigit;
                bEven = ! bEven;
            } else
            { //if (cDigit != ' ' && cDigit != '.' && cDigit != '-') {
                return false;
            }
        }
        return ((nCheck % 10) == 0) && (strNum.length>0);
    }



});

// checks that the type VISA etc matches the number supplied
var credit_card_type_chk = new Class({
    Extends: validatorBase,

    initialize: function( cardTypeFieldId )
    {
        this.cardTypeId = cardTypeFieldId;
        console.log(cardTypeFieldId);
    },

    validate: function(el)
    {
        var spec = '[name=' + this.cardTypeId + ']';
        var cardTypeEl = $$( spec )[0];
        
        if( typeof(cardTypeEl)=="undefined" )
        {
            this.cardType = getRadioButtonSelection( this.form, this.cardTypeId );
        }
        else
        {
            this.cardType = cardTypeEl.value;
        }

        if( ! this.isCardTypeCorrect(el.value, this.cardType ))
        {
            this.errorType = 1;
            return false;
        }

        return true;
    },

    isDigit: function(c)
    {
        var strAllowed = "1234567890";
        return (strAllowed.indexOf (c) != -1);
    },

    getMessage: function(el)
    {
        return "This Credit Card Number is not a valid " + this.cardType + " card number.";
    },

    isCardTypeCorrect : function (strNum, type)
    {
        var nLen = 0;
        for (n = 0; n < strNum.length; n++)
        {
            if (this.isDigit (strNum.substring (n,n+1)))
                ++nLen;
        }
        if (type == 'VISA')
        {
            return ((strNum.substring(0,1) == '4') &&
                (nLen == 13 || nLen == 16));
        }
        else if (type == 'AMEX')
        {
            return ((strNum.substring(0,2) == '34' ||
                strNum.substring(0,2) == '37') && (nLen == 15));
        }
        else if (type == 'MASTERCARD')
        {
            return ((strNum.substring(0,2) == '51' ||
                strNum.substring(0,2) == '52'
                || strNum.substring(0,2) == '53' ||
                strNum.substring(0,2) == '54'
                || strNum.substring(0,2) == '55') && (nLen == 16));
        }
        else if (type == 'DINERS')
        {
            var typeNum = parseInt(strNum.substring(0,3));
            return (((typeNum>=300 && typeNum <= 305) ||
                strNum.substring(0,2) == '36' ||
                strNum.substring(0,2) == '38') && nLen == 14)
        }
        else if (type == 'OTHER')
        {
            return true;
        }
        else
            return false;
    }

});


// These classes take no args and can be shared
var checks = {
    "required_chk": new RegexValidator(/[^.*]/, "This field is required."),
    "alpha_chk": new RegexValidator(/^[a-z ._-]+$/i, "This field accepts alphabetic characters only."),
    "alphanum_chk" : new RegexValidator(/^[a-z0-9 ._-]+$/i, "This field accepts alphanumeric characters only."),
    "nodigit_chk" : new RegexValidator(/^[^0-9]+$/, "No digits are accepted."),
    "number_chk" : new RegexValidator(/^[-+]?\d*\.?\d+$/, "Please enter a valid number."),
    "email_chk" : new RegexValidator(/^([a-zA-Z0-9_\.\-\+%])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/, "Please enter a valid email."),
    "image_chk" : new RegexValidator(/.(jpg|jpeg|png|gif|bmp)$/i, 'This field should only contain image types'),
    "phone_chk" : new RegexValidator(/^[\d\s ().-]+$/, "Please enter a valid phone."),
    "phone_inter_chk" : new RegexValidator(/^\+{0,1}[0-9 \(\)\.\-]+$/, "Please enter a valid international phone number."),
    "url_chk" : new RegexValidator( /^(http|https|ftp)\:\/\/[a-z0-9\-\.]+\.[a-z]{2,3}(:[a-z0-9]*)?\/?([a-z0-9\-\._\?\,\'\/\\\+&amp;%\$#\=~])*$/i
        , "Please enter a valid url."),
    "submit_chk":new SubmitCheck(),
    "credit_card_chk": new credit_card_chk(),
    "password_chk":new StrongPasswordCheck(),
    "checkbox_chk":new checkbox_chk(),
    "is_optional_chk": new is_optional_chk()
}

