﻿/// <reference path="jquery-1.3.2-vsdoc2.js"/>

/*
jQuery jVal Library v1.0
http://jval.xhedra.com/

Copyright (c) 2009 xHedra
Dual licensed under the MIT and GPL licenses.

Date: 2009-04-06
*/

/*
* ->  not implemented
Used trought classes: jVal [Req] { [ValidationType { [Range] }] | [Selector] }
    
ValidationType = [ Int | Decimal | *Percentage | *Email | *Phone | *PostalCode ]
    
Selector = [ *SelOne | *SelSome]
    
For Decimal -> must have jValDecimal ="18|2"
For Range   -> must have jValRange   ="0.25|99.5"
    
on page load search all tags with jVal class and add a blur event to validate the field (required/or not + type) 
and if at leat one jVal is present in the page add validateAll on submit
    
* If an error group is needed, specify the group name with jValGroup attribute and use jValMsg to specify the message for this field
*/

/*
CssClass="jVal[Req][ValidationType][Range]" jValName="" jValGroup="" jValCtrlGroup="" jValDecimal="" jValRange="" jValMsg="The abbrev is required"
*/

function jValCalendarExtenderFix(sender, args) {
    $('#' + sender._textbox.get_id().replace('$TextBoxWrapper', '')).removeClass('cValError');
}

var errors = [];
function pushError(ctrl, msg, type) {
    for (var i = 0; i < errors.length; i++) {
        if (errors[i]['id'] == ctrl.id || /* for pwd compare (display only once)*/errors[i]['message'] == msg) {
            return true;
        }
    }

    if (ctrl.id.endsWith('_From')) {
        msg = msg.replace('{name}', $(ctrl).attr('jValName').toLowerCase() + ' (1)');
    }
    else if (ctrl.id.endsWith('_To')) {
        msg = msg.replace('{name}', $(ctrl).attr('jValName').toLowerCase() + ' (2)');
    }
    else {
        msg = msg.replace('{name}', $(ctrl).attr('jValName').toLowerCase());
    }

    var range = $(ctrl).attr('jValRange');
    if (range != null) {
        range = range.split('|')
        if (range.length == 2) {
            if (type != 'date') {
                msg = msg.replace('{from}', range[0]);
                msg = msg.replace('{to}', range[1]);
            }
            else {
                msg = jValRangeMsgFormat(range, msg);
            }
        }
    }

    var dec = $(ctrl).attr('jValDecimal');
    if (dec != null) {
        dec = dec.split('|')
        if (dec.length == 2) {
            msg = msg.replace('{before}', parseInt(dec[0]) - parseInt(dec[1]));
            msg = msg.replace('{after}', dec[1]);
        }
    }

    switch (type) {
        case 'phone':
            msg = msg.replace('{format}', '(888) 321-4321');
            break;
        case 'postalcodeca':
            msg = msg.replace('{format}', 'A3A 3A3');
            break;
        case 'postalcodeus':
            msg = jValPostalCodeUSFormatMsg(msg);
            break;
        case 'email':
            msg = msg.replace('{format}', 'name@domain.com');
            break;
        case 'date':
            msg = jValDateFormatMsg(msg);
            break;
        case 'file':
            msg = msg.replace('{format}', 'C:\\folderName\\fileName.txt');
            break;
        case 'commoncreditcard':
            msg = msg.replace('{format}', '1111 1111 1111 1111');
            break;
        case 'guid':
            msg = msg.replace('{format}', '11111111-1111-1111-1111-111111111111');
            break;
    }
    errors.push({ id: ctrl.id, message: msg });

    //if ($.inArray(errors[i]['message'], errorMessages) == -1) {
    //    errorMessages.push(errors[i]['message']);
    //}
}

function jValidateForm(mode, group) {
    /*
    if mode
    0 = in page
    1 = alert
    else
    no summary
    */
    errors = [];
    var selector = '[class*=jVal]:not([disabled=true])';
    var dotnetFixSelector = 'span[class*=cValError]';

    if (typeof (group) == 'string') {
        var unselector;
        var groups = group.split(',');
        var count = groups.length ;
        if (count > 1) {
            selector = '[jValGroup=' + groups[0] + '][class*=jVal]:not([disabled=true])';

            unselector = '[class*=jVal]:not([disabled=true]):not([jValGroup=' + groups[0] + '])';

            for (var i = 1; i < count; i++) {
                selector += ',[jValGroup=' + groups[i] + '][class*=jVal]:not([disabled=true])';

                unselector += ',[class*=jVal]:not([disabled=true]):not([jValGroup=' + groups[0] + '])';
            }

            // Remove any other cValError class outside of the current groups
            $(unselector).removeClass('cValError');
        }
        else {
            selector = '[jValGroup=' + group + '][class*=jVal]:not([disabled=true])';

            // Remove any other cValError class outside of the current group
            $('[class*=jVal]:not([disabled=true]):not([jValGroup=' + group + '])').removeClass('cValError');
        }
    }

    if ($(selector).blur().hasClass('cValError') || $(dotnetFixSelector).hasClass('cValError')) {
        var summary = $('#jValSummary');
        if (summary != null) {

            switch (mode) {
                case 0:
                    var errorMessages = [];
                    for (var i = 0; i < errors.length; i++) {
                        errorMessages.push('<li id=\"err_' + errors[i]['id'] + '\">' + errors[i]['message'] + '</li>');
                    }

                    var msg = '<div id=\"jValSummaryTitle\" style=\"height:14px;padding-top:2px;\"><b>' +
                        summary.attr('jValTitle').toString().format('<span id=\"jValErrorCount\">' +
                        errorMessages.length + '</span>') + '</b> - <a id=\"jValSummaryToggle\" style=\"cursor:pointer;font-weight:normal;\">' +
                        summary.attr('jValShow') + '</a></div>\n';

                    summary.find('td:nth-child(2)').html(msg + '<ul>' + errorMessages.join('\n') + '</ul>')
                    summary.find('#jValSummaryToggle').click(function() {
                        $(this).parent().next().toggle();
                        if ($(this).text() == summary.attr('jValShow')) {
                            $(this).text(summary.attr('jValHide'));
                        }
                        else { $(this).text(summary.attr('jValShow')); }
                    });
                    summary.show();
                    break;

                case 1:
                    var errorMessages = [];
                    for (var i = 0; i < errors.length; i++) {
                        errorMessages.push(errors[i]['message']);
                    }

                    var msg = summary.attr('jValTitle').toString().format(errorMessages.length) + '\n\n';
                    alert(msg + errorMessages.join('\n'));
                    break;

                default:
                    break;
            }
        }
        return false;
    }
    return true;
}

$(function() {
    _dotnetFix();
    
    if (document.location.toString().toLowerCase().indexOf('xhedradebug') > -1) {
        validatePageValidators();
        displayConsole();
    }
    else if (document.location.host.toString().indexOf('localhost') > -1) {
        validatePageValidators();
    }

    jValBind('[class*=jVal]');
});

function jValBind(selector) {
    var i, ctrl, sClasses, tagName, required, select, range, validationType, sClass, bBlurSet;

    $(selector).each(function() {
        ctrl = $(this);
        tagName = this.tagName.toLowerCase();
        sClasses = ctrl.attr('class').toLowerCase().split(' ');

        for (i = 0; i < sClasses.length; i++) {

            if (sClasses[i].indexOf('jval') == 0) {
                sClass = sClasses[i].replace('jval', '');

                required = (sClass.indexOf('req') == 0);
                if (required) {
                    sClass = sClass.replace('req', '');
                }

                select = 0;
                var selPos = sClass.indexOf('sel');
                if (selPos == 0) {
                    if (sClass == 'selone') {
                        select = 1;
                        sClass = sClass.replace('selone', '');
                    }
                    if (sClass == 'selsome') {
                        select = 2;
                        sClass = sClass.replace('selsome', '');
                    }
                }

                range = (sClass.indexOf('range') > -1);
                if (range) {
                    sClass = sClass.replace('range', '');
                }

                validationType = sClass;
            }
        }

        bBlurSet = false;
        if (tagName == 'input') {
            var ctrlType = this.type.toLowerCase();
            if (ctrlType == 'text') {
                switch (validationType) {
                    // Int | Decimal | *Percentage | Email | Phone | PostalCode                                    
                    case 'int':
                        var maxlength = ctrl.attr('maxlength');

                        if (maxlength == null || maxlength > 10) {
                            ctrl.attr('maxlength', 10);
                        }

                        if (required && range) {
                            ctrl.blur(function() { if (_validateRequired(this)) { _validateIntRange(this); } });
                        }
                        else if (range) {
                            ctrl.blur(function() { _validateIntRange(this); });
                        }
                        else if (required) {
                            ctrl.blur(function() { _validateRequired(this); });
                        }
                        ctrl.keypress(function() { return blockNonNumbers(this, event, false, $(this).attr('jValAllowNegative') === 'true'); });
                        break;

                    case 'decimal':
                        if ($(ctrl).attr('jValTime') === 'true') {
                            ctrl.css('textAlign', 'right');
                        }
                        
                        if (required && range) {
                            ctrl.blur(function() { if (_validateRequired(this)) { if (_validateDecimalFormat(this)) { if (_validateDecimalRange(this)) { _validateTimeFormat(this); } } } });
                        }
                        else if (range) {
                            ctrl.blur(function() { if (_validateDecimalFormat(this)) { if (_validateDecimalRange(this)) { _validateTimeFormat(this); } } });
                        }
                        else if (required) {
                            ctrl.blur(function() { if (_validateRequired(this)) { if (_validateDecimalFormat(this)) { _validateTimeFormat(this); } } });
                        }
                        else {
                            ctrl.blur(function() { if (_validateDecimalFormat(this)) { _validateTimeFormat(this); } });
                        }
                        ctrl.keypress(function() { return blockNonNumbers(this, event, true, $(this).attr('jValAllowNegative') === 'true'); });
                        break;

                    // TODO:                             
                    //case 'percentage':                                            
                    //    break;        

                    case 'date':
                        /* Use _From and _To at the and of the control id to validate that the second date is before the first date */
                        if (required && range) {
                            ctrl.blur(function() { if (_validateRequired(this)) { if (_validateDate(this, true)) { _validateDateRange(this); } } });
                        }
                        else if (range) {
                            ctrl.blur(function() { if (_validateDate(this, false)) { _validateDateRange(this); } });
                        }
                        else if (required) {
                            ctrl.blur(function() { if (_validateRequired(this)) { _validateDate(this, true); } });
                        }
                        else {
                            ctrl.blur(function() { _validateDate(this, false); });
                        }
                        break;

                    case 'email':
                        if (required) {
                            ctrl.blur(function() { if (_validateRequired(this)) { _validateEmail(this, true); } });
                        }
                        else {
                            ctrl.blur(function() { _validateEmail(this, false); });
                        }
                        break;

                    case 'phone':
                        ctrl.attr('maxlength', 16)

                        if (required) {
                            ctrl.blur(function() { if (_validateRequired(this)) { _validatePhone(this, true); } });
                        }
                        else {
                            ctrl.blur(function() { _validatePhone(this, false); });
                        }
                        break;

                    case 'postalcode':
                    case 'postalcodeca':
                        ctrl
                            .attr('maxlength', 7)
                            .css('textTransform', 'uppercase');

                        if (required) {
                            ctrl.blur(function() { if (_validateRequired(this)) { _validateCAPostalCode(this, true); } });
                        }
                        else {
                            ctrl.blur(function() { _validateCAPostalCode(this, false); });
                        }
                        break;

                    case 'postalcodeus':
                        ctrl.attr('maxlength', 10);

                        if (required) {
                            ctrl.blur(function() { if (_validateRequired(this)) { _validateUSPostalCode(this, true) } });
                        }
                        else {
                            ctrl.blur(function() { _validateUSPostalCode(this, false); });
                        }
                        ctrl.keypress(function() { return blockNonNumbers(this, event, false, false); });
                        break;
                    case 'commoncreditcard':
                        ctrl.attr('maxlength', 19);

                        if (required) {
                            ctrl.blur(function() { if (_validateRequired(this)) { _validateCreditCard(this, true) } });
                        }
                        else {
                            ctrl.blur(function() { _validateCreditCard(this, true); });
                        }
                        ctrl.keypress(function() { return blockNonNumbers(this, event, false, false); });
                    case 'guid':
                        ctrl.attr('maxlength', 36)

                        if (required) {
                            ctrl.blur(function () { if (_validateRequired(this)) { _validateGUID(this, true); } });
                        }
                        else {
                            ctrl.blur(function () { _validateGUID(this, false); });
                        }
                        break;
                    default:
                        if (ctrl.attr('class').toLowerCase().indexOf('file') > -1) {
                            if (required) {
                                ctrl.blur(function() { if (_validateRequired(this)) { _validateFile(this); } });
                            }
                            else {
                                ctrl.blur(function() { _validateFile(this); });
                            }
                        }
                        else if (required) {
                            ctrl.blur(function() { _validateRequired(this); });
                        }
                        break;
                }
                bBlurSet = true;
            }
            else if (ctrlType == 'checkbox') {
                var x = select == 1 ? 1 : select == 2 ? 2 : 0;
                if (required) {
                    ctrl.blur(function() { _validateCheckBox(this, true, x); });
                    ctrl.click(function() { _validateCheckBox(this, true, x); });
                }
                else {
                    ctrl.blur(function() { _validateCheckBox(this, false, x); });
                    ctrl.click(function() { _validateCheckBox(this, false, x); });
                }
                bBlurSet = true;
            }
            else if (ctrlType == 'radio') {
                var x = select == 1 ? 1 : select == 2 ? 2 : 0;
                if (required) {
                    ctrl.blur(function() { _validateRadioButton(this, true, x); });
                    ctrl.click(function() { _validateRadioButton(this, true, x); });
                }
                else {
                    ctrl.blur(function() { _validateRadioButton(this, false, x); });
                    ctrl.click(function() { _validateRadioButton(this, false, x); });
                }
                bBlurSet = true;
            }
            else if (ctrlType == 'password') {
                if (required) {
                    ctrl.blur(function() { _validateRequired(this); });
                }
                bBlurSet = true;
            }
            else if (ctrlType == 'file') {
                if (required) {
                    ctrl.blur(function() { if (_validateRequired(this)) { _validateFile(this); } });
                }
                else {
                    ctrl.blur(function() { _validateFile(this); });
                }
                bBlurSet = true;
            }
        }
        else if (tagName == 'select') {
            // DropDownListManager.cs has DropDownListFilter.SelectOne wich is value equal -8 and is not a permitted value
            if (required) {
                ctrl.blur(function() { _validateRequired(this, true); });
            }
            bBlurSet = true;
        }
        else if (tagName == 'textarea') {
            ctrl.blur(function() { _validateRequired(this); });
            bBlurSet = true;
        }

        // Apply custom function
        if (ctrl.attr('jValFunc') != null) {
            ctrl.blur(function() { _customFunc(this); });
            bBlurSet = true;
        }

        if (!bBlurSet) {
            ctrl.blur(function() { alert('jVal.js: Unprocessed ' + tagName + ' tag - validateField(ctrl=' + ctrl.id + ', required=' + required + ', validationType=' + validationType + ')'); });
        }
    });
}

/*----------------------------------------------------------------------------------------------------*/

function _customFunc(ctrl) {

    var func = $(ctrl).attr('jValFunc');

    //if (!func.endsWith(');') && !func.endsWith(')')) {
    //    func += '()';
    //}

    var isCustomValidated = new Function('return ' + func + ';');

    if (!isCustomValidated()) {
        $(ctrl).addClass('cValError');
        pushError(ctrl, $(ctrl).attr('jValMsg'), 'custom');
    }
    else {
        if ($(ctrl).attr('jValCtrlGroup') != null) {
            $('[jValCtrlGroup=' + $(ctrl).attr('jValCtrlGroup') + ']').removeClass('cValError');
        }
        else {
            $(ctrl).removeClass('cValError');
        }
        _updateErrorSummary(ctrl);
    }
}

/*----------------------------------------------------------------------------------------------------*/

function _updateErrorSummary(ctrl) {
    if ($(ctrl).attr('jValCtrlGroup') != null) {
        $('[jValCtrlGroup=' + $(ctrl).attr('jValCtrlGroup') + ']')
            .each(function() {
                $('#err_' + this.id).remove();
            });
    }
    else {
        $('#err_' + ctrl.id).remove();
    }

    var size = $('[id^=err_]').size();

    if (size == 0) {
        $('#jValSummary').hide();
    }
    else {
        $('#jValErrorCount').text(size);
    }
}

function _validateRequired(ctrl, invalidValue) {

    if (ctrl.value == '' || (invalidValue === true && parseInt(ctrl.value) <= 0)) {
        $(ctrl).addClass('cValError');
        pushError(ctrl, $('#jValSummary').attr('jValMsgReq'), null);
        return false;
    }
    $(ctrl).removeClass('cValError');
    _updateErrorSummary(ctrl);
    return true;
}

/*----------------------------------------------------------------------------------------------------*/

function _validateIntRange(ctrl) {

    //TODO:
    /*
    c# Int32.MinValue = -2147483648
    c# Int32.MaxValue =  2147483647
    */

    // alert([Number.MAX_VALUE, Number.MIN_VALUE]);
    /*
    js Number.MIN_VALUE =                  5e-324
    js Number.MAX_VALUE = 1.7976931348623157e+308
    */

    if (ctrl.value != '') {
        var range = $(ctrl).attr('jValRange').split('|');
        if (parseInt(ctrl.value) < parseInt(range[0]) || parseInt(ctrl.value) > parseInt(range[1])) {
            $(ctrl).addClass('cValError');
            pushError(ctrl, $('#jValSummary').attr('jValMsgRange'), 'int');
            return false;
        }
    }
    $(ctrl).removeClass('cValError');
    _updateErrorSummary(ctrl);
    return true;
}

function _validateDecimalRange(ctrl) {

    if (ctrl.value != '') {
        var range = $(ctrl).attr('jValRange').split('|');
        if (parseFloat(ctrl.value) < parseFloat(range[0]) || parseFloat(ctrl.value) > parseFloat(range[1])) {
            $(ctrl).addClass('cValError');
            pushError(ctrl, $('#jValSummary').attr('jValMsgRange'), 'decimal');
            return false;
        }
    }
    $(ctrl).removeClass('cValError');
    _updateErrorSummary(ctrl);
    return true;
}

function _validateDateRange(ctrl) {

    if (ctrl.value != '') {
        var value = jValDateToComparableInt(ctrl.value);

        var range = $(ctrl).attr('jValRange').split('|');
        // isNaN(value) || 
        if (parseInt(value) < parseInt(range[0]) || parseInt(value) > parseInt(range[1])) {
            $(ctrl).addClass('cValError');
            pushError(ctrl, $('#jValSummary').attr('jValMsgRange'), 'date');
            return false;
        }
        else {
            if (ctrl.id.indexOf('_To') > -1) {
                var from = $('#' + ctrl.id.replace('_To', '_From')).val();
                var to = $('#' + ctrl.id).val();

                from = jValDateToComparableInt(from);
                to = jValDateToComparableInt(to);

                if ($(ctrl).attr('jValAllowSameDay') === 'true')
                {
                    if (parseInt(from) > parseInt(to)) {
                        $(ctrl).addClass('cValError');
                        pushError(ctrl, $('#jValSummary').attr('jValMsgDate'), 'date');
                        return false;
                    }
                }
                else
                {
                    if (parseInt(from) >= parseInt(to)) {
                        $(ctrl).addClass('cValError');
                        pushError(ctrl, $('#jValSummary').attr('jValMsgDate'), 'date');
                        return false;
                    }
                }
            }
        }
    }
    $(ctrl).removeClass('cValError');
    _updateErrorSummary(ctrl);
    return true;
}

/*----------------------------------------------------------------------------------------------------*/

function _validateDecimalFormat(ctrl) {

    if (ctrl.value != '') {
        var bef, aft, dec = $(ctrl).attr('jValDecimal').split('|');
        var isValid = false;

        if (ctrl.value.indexOf('.') > -1) {
            var val = ctrl.value.split('.');

            bef = val[0] != null ? val[0].toString() : '';
            aft = val[1] != null ? val[1].toString() : '';

            if (bef.length <= (parseInt(dec[0]) - parseInt(dec[1])) && aft.length <= parseInt(dec[1])) {
                isValid = true;
            }
        }
        else if (ctrl.value.length <= (parseInt(dec[0]) - parseInt(dec[1]))) {
            isValid = true;
        }

        if (!isValid) {
            $(ctrl).addClass('cValError');
            pushError(ctrl, $('#jValSummary').attr('jValMsgDecimal'), 'decimal');
            return false;
        }
    }
    $(ctrl).removeClass('cValError');
    _updateErrorSummary(ctrl);
    return true;
}
/*----------------------------------------------------------------------------------------------------*/

function _validateTimeFormat(ctrl) {

    if (ctrl.value != '' && $(ctrl).attr('jValTime') === 'true') {
        var aft;
        var isValid = true;

        if (ctrl.value.indexOf('.') > -1) {
            var val = ctrl.value.split('.');

            aft = val[1] != null ? val[1].toString() : '';

            isValid = aft == '' || (aft.length == 2 && (aft == '00' || aft == '25' || aft == '50' || aft == '75'));
        }

        if (!isValid) {
            $(ctrl).addClass('cValError');
            pushError(ctrl, $('#jValSummary').attr('jValMsgTime'), 'decimal');
            return false;
        }
    }
    $(ctrl).removeClass('cValError');
    _updateErrorSummary(ctrl);
    return true
}

/*----------------------------------------------------------------------------------------------------*/

function _validateDate(ctrl, req) {

    var isValid = req ? (ctrl.value != '' && isDate(ctrl.value)) : (ctrl.value == '' || isDate(ctrl.value));

    if (!isValid) {
        $(ctrl).addClass('cValError');
        pushError(ctrl, $('#jValSummary').attr('jValMsgFormat'), 'date');
        return false;
    }
    $(ctrl).removeClass('cValError');
    ctrl.value = toDate(ctrl.value);
    _updateErrorSummary(ctrl);
    return true;
}

function _validateEmail(ctrl, req) {

    var isValid = req ? (ctrl.value != '' && ctrl.value.isEmail()) : (ctrl.value == '' || ctrl.value.isEmail());

    if (!isValid) {
        $(ctrl).addClass('cValError');
        pushError(ctrl, $('#jValSummary').attr('jValMsgFormat'), 'email');
        return false;
    }
    $(ctrl).removeClass('cValError');
    _updateErrorSummary(ctrl);
    return true;
}

function _validatePhone(ctrl, req) {

    var isValid = req ? (ctrl.value != '' && ctrl.value.isPhone()) : (ctrl.value == '' || ctrl.value.isPhone());

    if (!isValid) {
        $(ctrl).addClass('cValError');
        pushError(ctrl, $('#jValSummary').attr('jValMsgFormat'), 'phone');
        return false;
    }
    $(ctrl).removeClass('cValError');
    ctrl.value = ctrl.value.toPhone();
    _updateErrorSummary(ctrl);
    return true;
}

function _validateCAPostalCode(ctrl, req) {

    var isValid = req ? (ctrl.value != '' && ctrl.value.isCAPostalCode()) : (ctrl.value == '' || ctrl.value.isCAPostalCode());

    if (!isValid) {
        $(ctrl).addClass('cValError');
        pushError(ctrl, $('#jValSummary').attr('jValMsgFormat'), 'postalcodeca');
        return false;
    }
    $(ctrl).removeClass('cValError');
    ctrl.value = ctrl.value.toCAZipCode();
    _updateErrorSummary(ctrl);
    return true;
}
function _validateUSPostalCode(ctrl, req) {

    var isValid = req ? (ctrl.value != '' && ctrl.value.isUSPostalCode()) : (ctrl.value == '' || ctrl.value.isUSPostalCode());

    if (!isValid) {
        $(ctrl).addClass('cValError');
        pushError(ctrl, $('#jValSummary').attr('jValMsgFormat'), 'postalcodeus');
        return false;
    }
    $(ctrl).removeClass('cValError');
    _updateErrorSummary(ctrl);
    return true;
}
function _validateCreditCard(ctrl, req)
{
    var isValid = req ? (ctrl.value != '' && ctrl.value.isCommonCreditCard()) : (ctrl.value == '' || ctrl.value.isCommonCreditCard());
    
    if (!isValid){
        $(ctrl).addClass('cValError');
        pushError(ctrl, $('#jValSummary').attr('jValMsgFormat'),'commonCreditCard');
        return false;
    }
    
    $(ctrl).removeClass('cValError');
    ctrl.value = ctrl.value.toCommonCreditCard();
    _updateErrorSummary(ctrl);
    return true;
}
function _validateGUID(ctrl, req) {
    var isValid = req ? (ctrl.value != '' && ctrl.value.isGUID()) : (ctrl.value == '' || ctrl.value.isGUID());

    if (!isValid) {
        $(ctrl).addClass('cValError');
        pushError(ctrl, $('#jValSummary').attr('jValMsgFormat'), 'guid');
        return false;
    }

    $(ctrl).removeClass('cValError');
    //ctrl.value = ctrl.value.toGuid();
    _updateErrorSummary(ctrl);
    return true;
}
function _validateFile(ctrl) {
    var extLength = ctrl.value.lastIndexOf('.') > 0
                    ? ctrl.value.length - (ctrl.value.lastIndexOf('.') + 1)
                    : -1;

    var isValid = ctrl.value.indexOf(':\\') == 1 && (extLength > 0);

    if (!isValid) {
        $(ctrl).addClass('cValError');
        pushError(ctrl, $('#jValSummary').attr('jValMsgFormat'), 'file');
        return false;
    }
    $(ctrl).removeClass('cValError');
    _updateErrorSummary(ctrl);
    return true;
}
/*----------------------------------------------------------------------------------------------------*/

function _validateCheckBox(ctrl, req, select) {

    if (select != 0) {
        var group = $(ctrl).attr('jValCtrlGroup');

        if (group != null && group != '') {
            // CheckboxList
            var size = $('input[type=checkbox][checked=true][jValCtrlGroup=' + group + ']').size();

//            var ctrlGroupID = $(ctrl).parent().attr('id');
//
//            if (ctrlGroupID == '') {
//                // Hack for the permission control wich doesn't use the ASP.NET CheckboxList
//                ctrlGroupID = $(ctrl).parent().parent().parent().parent().parent().attr('id');
//            }
//            
//            var groupCtrl = document.getElementById(ctrlGroupID);

            var groupCtrl = document.getElementById($(ctrl).parent().attr('id'));
            
            if (select == 1) {
                if ((req && size != 1) || (!req && size > 1)) {
                    $(ctrl).parent().addClass('cValError');

                    pushError(groupCtrl, $('#jValSummary').attr('jValMsgReq'), 'checkbox');
                }
                else {
                    $(ctrl).parent().removeClass('cValError').children().removeClass('cValError'); //.filter('[disabled=true]').removeClass('cValError');
                    _updateErrorSummary(groupCtrl);
                }
            }
            else if (select == 2) {
                if (req && size == 0) {
                    $(ctrl).parent().addClass('cValError');

                    pushError(groupCtrl, $('#jValSummary').attr('jValMsgReq'), 'checkbox');
                }
                else {
                    $(ctrl).parent().removeClass('cValError').children().removeClass('cValError'); //.filter('[disabled=true]').removeClass('cValError');
                    _updateErrorSummary(groupCtrl);
                }
            }
        }
        else {
            // Single Checkbox
            if (req && !ctrl.checked) {
                $(ctrl).parent().addClass('cValError');

                pushError(ctrl, $('#jValSummary').attr('jValMsgReq'), 'checkbox');
            }
            else {
                $(ctrl).parent().removeClass('cValError');
                _updateErrorSummary(ctrl);
            }
        }
    }
    return true;
}

function _validateRadioButton(ctrl, req, select) {

    if (select != 0) {
        var group = $(ctrl).attr('jValCtrlGroup');

        if (group != null && group != '') {
            // RadioButtonList
            var size = $('input[type=radio][checked=true][jValCtrlGroup=' + group + ']').size();

            var groupCtrl = document.getElementById($(ctrl).parent().attr('id'));
            
            if (select == 1) {
                if ((req && size != 1) || (!req && size > 1)) {
                    $(ctrl).parent().addClass('cValError');

                    pushError(groupCtrl, $('#jValSummary').attr('jValMsgReq'), 'radio');
                }
                else {
                    $(ctrl).parent().removeClass('cValError').children().removeClass('cValError'); //.filter('[disabled=true]').removeClass('cValError');
                    _updateErrorSummary(groupCtrl);
                }
            }
            else if (select == 2) {
                if (req && size == 0) {
                    $(ctrl).parent().addClass('cValError');

                    pushError(groupCtrl, $('#jValSummary').attr('jValMsgReq'), 'radio');
                }
                else {
                    $(ctrl).parent().removeClass('cValError').children().removeClass('cValError'); //.filter('[disabled=true]').removeClass('cValError');
                    _updateErrorSummary(groupCtrl);
                }
            }
        }
        else {
            // Single RadioButton
            if (req && !ctrl.checked) {
                $(ctrl).parent().addClass('cValError');

                pushError(ctrl, $('#jValSummary').attr('jValMsgReq'), 'radio');
            }
            else {
                $(ctrl).parent().removeClass('cValError');
                _updateErrorSummary(ctrl);
            }
        }
    }
    return true;
}

/*----------------------------------------------------------------------------------------------------*/

// Fix to apply cssClass on each checkbox/radio of a ASP.NET CheckBoxList/RadioButtonList Control 
function _dotnetFix() {
    $('span[class*=jVal]').each(function() {
        // CheckBox's
        var chk = $(this).find('input[type=checkbox]');
        if (chk.size() > 0) {
            if (chk.size() == 1) {

                if ($(this).attr('jValGroup') != null) {
                    chk.attr('jValGroup', $(this).attr('jValGroup'));
                }
                
                if ($(this).attr('jValName') != null) {
                    chk.attr('jValName', $(this).attr('jValName'));
                }

                if ($(this).attr('jValFunc') != null) {
                    chk.attr('jValFunc', $(this).attr('jValFunc'));
                }

                if ($(this).attr('jValMsg') != null) {
                    chk.attr('jValMsg', $(this).attr('jValMsg'));
                }

                chk.addClass($(this).attr('class'));

                $(this).removeAttr('class');
            }
            else {
                if ($(this).attr('jValCtrlGroup') == null) {
                    alert('jVal.js: checkbox group require\'s a jValCtrlGroup on ' + $(this).attr('id'));
                }
                else if ($(this).attr('class').toLowerCase().indexOf('sel') < 0) {
                    alert('jVal.js: checkbox group must specify SelOne|SelSome on ' + $(this).attr('id'));
                }
                else {

                    if ($(this).attr('jValGroup') != null) {
                        chk.attr('jValGroup', $(this).attr('jValGroup'));
                    }
                    
                    if ($(this).attr('jValName') != null) {
                        chk.attr('jValName', $(this).attr('jValName'));
                    }

                    if ($(this).attr('jValFunc') != null) {
                        chk.attr('jValFunc', $(this).attr('jValFunc'));
                    }

                    if ($(this).attr('jValMsg') != null) {
                        chk.attr('jValMsg', $(this).attr('jValMsg'));
                    }

                    chk.attr('jValCtrlGroup', $(this).attr('jValCtrlGroup')).addClass($(this).attr('class'));

                    $(this).removeAttr('jValCtrlGroup');
                    $(this).removeAttr('jValGroup');
                    $(this).removeAttr('class');
                }
            }
        }
        else {
            // RadioButton's
            var rad = $(this).find('input[type=radio]');

            if (rad.size() > 0) {
                if (rad.size() == 1) {

                    if ($(this).attr('jValGroup') != null) {
                        rad.attr('jValGroup', $(this).attr('jValGroup'));
                    }

                    if ($(this).attr('jValName') != null) {
                        rad.attr('jValName', $(this).attr('jValName'));
                    }

                    if ($(this).attr('jValFunc') != null) {
                        rad.attr('jValFunc', $(this).attr('jValFunc'));
                    }

                    if ($(this).attr('jValMsg') != null) {
                        rad.attr('jValMsg', $(this).attr('jValMsg'));
                    }

                    rad.addClass($(this).attr('class'));

                    $(this).removeAttr('class');
                }
                else {
                    if ($(this).attr('jValCtrlGroup') == null) {
                        alert('jVal.js: radio group require\'s a jValCtrlGroup on ' + $(this).attr('id'));
                    }
                    else if ($(this).attr('class').toLowerCase().indexOf('sel') < 0) {
                        alert('jVal.js: radio group must specify SelOne|SelSome on ' + $(this).attr('id'));
                    }
                    else {
                    
                        if ($(this).attr('jValGroup') != null) {
                            rad.attr('jValGroup', $(this).attr('jValGroup'));
                        }

                        if ($(this).attr('jValName') != null) {
                            rad.attr('jValName', $(this).attr('jValName'));
                        }

                        if ($(this).attr('jValFunc') != null) {
                            rad.attr('jValFunc', $(this).attr('jValFunc'));
                        }

                        if ($(this).attr('jValMsg') != null) {
                            rad.attr('jValMsg', $(this).attr('jValMsg'));
                        }
                        
                        rad.attr('jValCtrlGroup', $(this).attr('jValCtrlGroup')).addClass($(this).attr('class'));

                        $(this).removeAttr('jValCtrlGroup');
                        $(this).removeAttr('jValGroup');
                        $(this).removeAttr('class');
                    }
                }
            } 
        }
    });
}

/*----------------------------------------------------------------------------------------------------*/

function validatePageValidators() {
    var sInvalid;
    var sCtrlMsg = '';
    var bInvalid = false;
    $('[class*=jVal]').each(function() {

        var ctrl = $(this);

        sCtrlMsg += '<li>' + ctrl.attr('id') + '<ul>'; //<ul class="jValList">
        sInvalid = '';

        if (ctrl.attr('jValName') == null) {
            sInvalid += '<li>Missing jValName</li>';
            bInvalid = true;
        }

        var sClasses = ctrl.attr('class').toLowerCase().split(' ');

        var required, selector, range, validationType, sClass;
        for (var i = 0; i < sClasses.length; i++) {
            if (sClasses[i].indexOf('jval') == 0) {
                sClass = sClasses[i].replace('jval', '');

                required = (sClass.indexOf('req') == 0);
                if (required) {
                    sClass = sClass.replace('req', '');
                }

                var selPos = sClass.indexOf('sel');
                if ((selPos > -1 && !required && ((sClass != 'selone' && sClass != 'selsome')))) {
                    sInvalid += '<li>Illegal use of selector [SelOne or SelSome]</li>';
                    bInvalid = true;
                }

                selector = (selPos == 0);
                if (selector) {
                    sClass = sClass.replace('selone', '');
                    sClass = sClass.replace('selsome', '');
                }

                range = (sClass.indexOf('range') > -1);
                if (range) {
                    sClass = sClass.replace('range', '');
                }

                validationType = sClass;

                if (validationType == 'decimal' && ctrl.attr('jValDecimal') == null) {
                    sInvalid += '<li>Missing jValDecimal</li>';
                    bInvalid = true;
                }

                if (range) {
                    if (validationType != 'int' && validationType != 'decimal' && validationType != 'date') {
                        sInvalid += '<li>Range allowed only on ValidationType [Int|Decimal|Date]</li>';
                        bInvalid = true;
                    }
                    if (ctrl.attr('jValRange') == null) {
                        sInvalid += '<li>Missing jValRange</li>';
                        bInvalid = true;
                    }
                }

                if (validationType != '') {
                    if (this.tagName.toLowerCase() != 'input' || (this.tagName.toLowerCase() == 'input' && this.type.toLowerCase() != 'text')) {
                        sInvalid += '<li>Cannot use ValidationType on control tagName=' + this.tagName + (this.tagName == 'input' ? ' - type=' + this.type : '') + '</li>';
                        bInvalid = true;
                    }
                }
            }
        }

        sCtrlMsg += sInvalid + '</ul></li>';
    });

    if (bInvalid) {
        alert('jVal.js: Invalid validators - See bottom of the page for details');
        $('body').append('<br /><br />jVal.js Errors:<br /><ul>' + sCtrlMsg + '</ul>'); //<ul class="jValList">
    }
}

/*----------------------------------------------------------------------------------------------------*/

function displayConsole() {
    $('body').append('<a onclick=\"$(\'#jValConsole\').toggle();\" style=\"cursor:pointer;\">Toggle Validators</a><br /><table cellspacing=\"5\" id=\"jValConsole\" style=\"background-color:#fff;display:none;\"></table>');
    var console = $('#jValConsole');

    console.append('<tr><td><b>Control ID</b></td><td><b>Class</b></td><td><b>Field Name</b></td><td><b>Group</b></td><td><b>Decimal</b></td><td><b>Range</b></td><td><b>Message</b></td><tr>');
    $('[class*=jVal]').each(function() {
        var ctrl = $(this);
        console.append('<tr><td>' + ctrl.attr('id') + '</td><td>' + ctrl.attr('class') + '</td><td>' + ctrl.attr('jValName') + '</td><td>' + ctrl.attr('jValGroup') + '</td><td>' + ctrl.attr('jValCtrlGroup') + '</td><td>' + ctrl.attr('jValDecimal') + '</td><td>' + ctrl.attr('jValRange') + '</td><td>' + ctrl.attr('jValMsg') + '</td><tr>');
    });
}

/*----------------------------------------------------------------------------------------------------*/

/*    
In the future we should be able to get the collection of controls to validate on server-side
*/

//    Implement server-side validation
//
//    ParseControls(((ContentPlaceHolder)Page.Master.FindControl("cphContent")).Controls);
//
//    private void ParseControls(ControlCollection ctrlColl)
//    {
//        foreach (System.Web.UI.Control control in ctrlColl)
//        {
//            if (control is WebControl)
//            {
//                var ctrl =(WebControl)control;
//                if (ctrl.CssClass.Contains("jVal"))
//                {
//                    if (!string.IsNullOrEmpty(ctrl.Attributes["jValMsg"]))
//                    {
//                        Response.Write(ctrl.Attributes["jValMsg"] + "<br />");
//                    }
//                    else
//                    {
//                        if (ctrl.CssClass.Contains("jValReq"))
//                        {
//                            Response.Write("This field is required<br />");
//                        }
//                        if (ctrl.CssClass.Contains("jValReqPhone"))
//                        {

//                        }
//                    }
//                }
//            }

//            if (control.Controls != null && control.Controls.Count > 0)
//            {
//                ParseControls(control.Controls);
//            }
//        }
//    }
