/*
 * ClientSideValidation Framework
 *
 * Distributable under LGPL.
 * See terms of license at opensource.org
 *
 * Dependent on cross browser library (see www.cross-browser.org) and
 * validation.js file.
 *
 * Author: Matt Baldree
 * Date: 2-22-03
 */

/////////////////////////// modify here ///////////////////////////////////////////////////////////////
//div id that will be looked for and html will be placed between its tags.
var csvValidationErrorMessageMarker = 'errMsg';
//error table message class
var csvValidationErrorMessageTableClass = 'errMsgTable';
//error table class
var csvValidationErrorTableClass = 'errTable';
//message to display at top of error box
var csvValidationErrorMessageInstruction = 'Please correct the following error(s):';
//width for 1 column in error box
var csvValidationErrorColumnWidth = 315;
//max rows for message box
var csvValidationErrorRoxMax = 3;
//label error style
var csvValidationLabelErrorStyle = 'clsLabelErrors';
//input element error style
var csvValidationInputErrorStyle = 'clsCSErrors';
//label style
var csvValidationLabelStyle = 'clsLabel';
//input element style
var csvValidationInputStyle = '';
//array of serverity gifs
var csvValidationSeverityGifs = new Array;
csvValidationSeverityGifs['info'] = 'images/Info.gif';
csvValidationSeverityGifs['warn'] = 'images/Warn.gif';
csvValidationSeverityGifs['critical'] = 'images/Critical.gif';


/*
 * array of check functions. You should order this array from most likely
 * to be a restraint to the least.
 *
 * --> Modify this array to add new restraints. Don't forget to modify
 * hasValidaitonRestraint().
 *
 */
var csvCheckArray = new Array;
csvCheckArray[0] = new CheckFunction(/^r?int_/, 'Must be a numeric value', 'csvIsInteger');
csvCheckArray[1] = new CheckFunction(/^r?dat_/, 'Invalid Date', 'csvIsDate');
csvCheckArray[2] = new CheckFunction(/^r?mny_/, 'Not in an acceptable format', 'csvIsMoney');
csvCheckArray[3] = new CheckFunction(/^r?alp_/, 'Invalid Alpha', 'csvIsAlpha');
csvCheckArray[4] = new CheckFunction(/^r?aln_/, 'Must not be blank', 'csvIsAlphaNum');
csvCheckArray[5] = new CheckFunction(/^r?eml_/, 'Invalid Email Address format', 'csvIsEmail');
csvCheckArray[6] = new CheckFunction(/^r?dbl_/, 'Invalid Double', 'csvIsReal');
csvCheckArray[7] = new CheckFunction(/^r?zip_/, 'Invalid Zipcode', 'csvIsZip');
csvCheckArray[8] = new CheckFunction(/^r?ssn_/, 'Invalid SSN', 'csvIsSSN');


/*
 * Determine if el is restrained by its id value.
 * It looks for r???_???... 'r' may be optional.
 * ??? is the restraint prefix. see filter below.
 */
function csvHasValidationRestraint(el) {
    var filter=/^(?:r?(?:ssn|int|alp|zip|aln|dat|eml|mny|dbl)|r)_/;
    if (!csvIsNullOrSpace(el.id) && filter.test(el.id)) {
        return true;
    }
    else {
        if (csvValidationDebug) alert('element id='+el.id+' does not have validation restaints.');
        return false;

    }
}

//////////////////////////////////////////////////////////////////////////////////////////////
//global variables
var csvValidationDebug = false;
var csvValidationErrors = null;
var csvValidationSelectElement = true;
var csvValidationDisplayWithMarker = true;
var csvValidationSeverity = 'critical';
var csvValidationAllowOverride = false;
var csvValidationErrorAtLabel = false;
var csvValidationErrorsOld = null;

/*
 * Validate a form's input fields. It will gather all input form elements and validate their fields.
 * If override is allowed, then it will compare new errors with old and if they are
 * the same and none of the errors are required, user can choose to still submit the form.
 *
 * frm - Form element id string
 * severity - severity of error ('warn', 'critical', 'info')
 * debug - boolean, if true, then alert statements will be produced.
 * displayWithMarker - if true, displays error message using marker; otherwise,
 *      display where labels are
 * selectElement - if true, when person selects error link, it will focus and display
 * allowOverride - if true, user can override errors and submit the form
 * showErrorsInElement - if true, error message will be in input element
 * btnArary - button array you want disabled while processing
 */
function csvValidate(frm, severity, debug, displayWithMarker, selectElement,
    allowOverride, showErrorsInElement, aBtnArray) {
    //save validation errors
    if (csvValidationAllowOverride && csvValidationErrors && csvValidationErrors.length>0)
        csvValidationErrorsOld = csvValidationErrors.slice(0);

    // reset from previous check if applicable
    if (csvValidationErrors && csvValidationErrors.length>0) {
        if (csvValidationDisplayWithMarker)
            csvDisplayErrorMessageWithMarker(true, csvValidationLabelStyle, csvValidationInputStyle);
        else
            csvDisplayErrorMessageInline(true, csvValidationLabelStyle, csvValidationInputStyle, csvValidationErrorAtLabel);
    }

    //initialization stuff
    if (debug!=null)
        csvValidationDebug = debug;
    if (aBtnArray==null) {
        var aArray = new Array;
        aArray[0] = 'submit';
        aBtnArray = aArray;
    }
    if (selectElement!=null)
        csvValidationSelectElement = selectElement;
    if (displayWithMarker!=null)
        csvValidationDisplayWithMarker = displayWithMarker;
    if (severity!=null)
        csvValidationSeverity = severity;
    if (allowOverride!=null)
        csvValidationAllowOverride = allowOverride;
    if (showErrorsInElement!=null)
        csvValidationErrorAtLabel = !showErrorsInElement;
    csvValidationErrors = new Array;

    //////////// main routine below ////////////////////////////////////////////

	// Check all fields for validation errors
    var el = cbeGetFormByName(frm);
    if (el) {
        //loop through form elements
        for (i=0; i<el.elements.length; i++) {
            if (el.elements[i]) {
                var type = el.elements[i].type;
                //if input type
                if (type=="select-one" || type=="select-multiple" || type=="text" ||
                    type=="textarea" || type=="checkbox" || type=="radio" || type=="password")
                {
                    var err = csvValidateFormField(el.elements[i]);
                    if (err) {
                        k=csvValidationErrors.length;
                        csvValidationErrors[k]=err;
                    }
                }
            }
        }

        //if no validation errors
        if (csvValidationErrors.length==0) {
            //disable button array
            if (aBtnArray) {
                for (i=0; i<aBtnArray.length; i++) {
                    if (aBtnArray[i]) {
                        var el = cbeGetElementById(aBtnArray[i]);
                        if (el) {
                            el.disabled = true;
                        }
                    }
                }
            }
            if (csvValidationDebug) alert('Pause to validate that desired button array is disabled.\n'+
                "Click 'OK' to continue.");
            return true;
        }
        //show errors
        else {
            //alert validation errors if debug
            if (debug) {
                for (i=0; i<csvValidationErrors.length; i++) {
                    var err = csvValidationErrors[i];
                    alert(err);
                }
            }

            if (csvValidationDisplayWithMarker)
                csvDisplayErrorMessageWithMarker(false, csvValidationLabelErrorStyle, csvValidationInputErrorStyle);
            else
                csvDisplayErrorMessageInline(false, csvValidationLabelErrorStyle, csvValidationInputErrorStyle, csvValidationErrorAtLabel);

            //if allow override, see if the validation errors are the same. if so, display
            //confirm box to override
            if (csvValidationAllowOverride) {
                if (csvValidationErrorsOld && csvValidationErrorsOld.length==csvValidationErrors.length) {
                    for (i=0; i<csvValidationErrors.length; i++) {
                        var err = csvValidationErrors[i];
                        var oldErr = null;
                        //search through old validaiton error for the same element id
                        for (j=0; j<csvValidationErrorsOld.length; j++) {
                            if (csvValidationErrorsOld[j].element.id==err.element.id) {
                                oldErr = csvValidationErrorsOld[j];
                                break;
                            }
                        }
                        //if this element is not equal or we didn't find old err or it is required, we are done.
                        if (oldErr==null || !err.equals(oldErr) || csvIsRequired(err.element)) {
                            return false;
                        }
                    }
                    return confirm('Same errors were found. Do you wish to submit anyway?');
                } else
                    return false;
            }
            else
                return false;
        }
    }
    else {
        if (debug) alert('form is null');
        return false;
    }
}

/*
 * Removes error messages
 */
function csvResetForm(frm) {
    if (csvValidationDisplayWithMarker)
        csvDisplayErrorMessageWithMarker(true, csvValidationLabelStyle, csvValidationInputStyle);
    else
        csvDisplayErrorMessageInline(true, csvValidationLabelStyle, csvValidationInputStyle, csvValidationErrorAtLabel);
    csvValidationErrors = null;
    csvValidationErrorsOld = null;
    return true;
}

/*
 * set focus in id member
 */
function csvSetFocus(elId) {
    var el = cbeGetElementById(elId);
    if (el) {
        el.focus();
        if (csvValidationSelectElement)
            el.select();
    }
}

/*
 * dispaly error messages inline with label
 */
function csvDisplayErrorMessageInline(reset, labelStyle, inputStyle, atLabel)
{
    var html = '';

    //run thru error list
    for (i=0; i<csvValidationErrors.length; i++)
    {
        var err = csvValidationErrors[i];
        if (err)
        {
            //input style
            err.element.className = inputStyle;

            //at label
            if (atLabel) {
                //bind this element: note: cbe only binds div and spans by default
                cbeBindElement(new CrossBrowserElement(), cbeGetElementById(err.label()));

                //find associated label
                var elErrLabel = cbeGetElementById(err.label());
                if (elErrLabel)
                {
                    //add in error message
                    if (!reset) {
                        err.labelHtml = elErrLabel.innerText;

                        html = "<span id='"+
                            err.element.id+"_tmp'"+
                            " class='"+
                            labelStyle+
                            "' style='font-size:smaller;'><br/>"+
                            err.message+
                            "<br/><br/></span>";

                        elErrLabel.insertAdjacentHTML("BeforeEnd", html);
                    }
                    //reset label
                    else {
                        //only change back if we have the old label
                        if (err.labelHtml) {
                            elErrLabel.cbe.innerHtml(err.labelHtml);
                        }
                    }
                }
            }
            //in input elment
            else {
                if (!reset)
                    //replace what they typed in with message
                    err.element.value = err.message;
            }
        }
    }
}

/*
 * display error messages as table using marker.
 */
function csvDisplayErrorMessageWithMarker(reset, labelStyle, inputStyle) {
    var html = '&nbsp';
    if (!reset) {
        var severity = csvValidationSeverityGifs[csvValidationSeverity];

        var preHtml =
            "<table class='"+
            csvValidationErrorTableClass+
            "'><tr><td valign='center' width='50'><center><img src='"+
            severity+
            "'/></center></td>"+
            "<td><table class='"+
            csvValidationErrorMessageTableClass+
            "'><tr><td colspan='3'>"+
            "<b>"+csvValidationErrorMessageInstruction+"</b>"+
            "</td></tr>";

        var errorHtml = '';
        var rowCount = 0;
        var columns = csvGetDisplayErrorColumns();
        var columnWidth = Math.round(1/columns*100);
        for (i=0; i<csvValidationErrors.length; i++) {
            var err = csvValidationErrors[i];
            if (err) {
                //new row
                if (i%columns == 0) errorHtml += "<tr>";

                //cell
                errorHtml +=
                "<td width='"+
                columnWidth+
                "%'><a href='javascript:csvSetFocus(\""+
                err.element.id+
                "\")'>"+
                csvFormatLabelForDisplay(err.labelWithoutPrefix())+
                "<a> - "+
                err.message+
                "</td>";

                //close of row
                if (i%columns == columns-1) {
                    errorHtml += "</tr>";
                    rowCount++;
                }
            }
            //check to see if we are at max.
            if (rowCount==csvValidationErrorRoxMax) break;
        }

        var postHtml = "</table></td></tr></table>";
        html = preHtml+errorHtml+postHtml;
    }
    csvDisplayErrorMessage(html, labelStyle, inputStyle);

}

/*
 * Dispatch element to appropriate sub validation methods.
 * As soon as an error is detected it is returned. It first
 * checks to see if element is restrained before going forward.
 *
 * returns a ValidationError or null if none were found.
 */
function csvValidateFormField(el) {
	//if (csvValidationDebug) alert(csvElementMetaInfo(el));

	if (!csvHasValidationRestraint(el)) {
	    return null;
	}

    var err = csvCheckRequired(el);
    if (err){
        return err;
    }

    for (ci=0; ci<csvCheckArray.length; ci++) {
        err = csvCheckFx(el, csvCheckArray[ci]);
        if (err) return err;
    }
    return null;
}


/////////// objects /////////////////////////////////////////////////////////////
/*
 * CheckFunction object. Used by validateFormField
 */
function CheckFunction(regExp, errMsg, fxName){
    this.regExp = regExp;
    this.errMsg = errMsg;
    this.fxName = fxName;
}
CheckFunction.prototype.regExp = function(){return this.regExp};
CheckFunction.prototype.errMsg = function(){return this.errMsg};
CheckFunction.prototype.fxName = function(){return this.fxName};
CheckFunction.prototype.toString = function(){return 'RegExp='+this.regExp+
    '\nError Message='+this.errMsg+'\nFunction Name='+this.fxName};


/*
 *  Validation Error Object
 *  c'tor(element, message)
 *
 *  element - action form element that failed validation
 *  message - message associated with the failure
 */
function ValidationError(element, message){
    this.element = element;
    this.message = message;
};
ValidationError.prototype.element = function(){return this.element};
ValidationError.prototype.labelHtml = null;
ValidationError.prototype.message = function(){return this.message};
ValidationError.prototype.label = function() {
    var suffix = this.labelWithoutPrefix();
    return 'lbl_'+suffix;
};
ValidationError.prototype.labelWithoutPrefix = function() {
    if (this.element==null) {
        if (csvValidationDebug) alert('Unable to determine label. Field not found.');
        return '';
    }

    var idx = this.element.id.indexOf('_');
    if (idx == -1) {
        if (csvValidationDebug) alert('Element id must have _ in it');
        return '';
    }

    return this.element.id.slice(idx+1);
};

ValidationError.prototype.toString = function(){
    return "Validation Error:\n"+csvElementMetaInfo(this.element)+"\nmessage="+this.message;
};
ValidationError.prototype.equals = function(err) {
    //is this object a ValidationError?
    if (!ValidationError.prototype.isPrototypeOf(err))
        return false;

    return (this.element.id == err.element.id && this.message == err.message);
};

