﻿ErrorDisplay = function() {
    // this can be set to any sufficiently big number
    var zIndex = 200000;

    // this is the ID of the client section of the control (the underscore is the seperator)
    var clientSideInformationID = "_popErrorDisplay_ClientSideErrorInformation";

    // this is the ID of the server section of the control (the underscore is the seperator)
    var serverSideInformationID = "_popErrorDisplay_ServerSideErrorInformation"

    // this will only get called once (if needed) and will create the overlay mask
    // used each time any ErrorDisplay is shown
    var createMask = function(el) {
        iframe = document.createElement("iframe");
        iframe.style.display = "none"
        iframe.style.position = "absolute";
        iframe.style.top = "0";
        iframe.style.left = "0";
        iframe.style.width = "100%";
        iframe.style.border = "0";
        iframe.style.opacity = "0";
        iframe.style.filter = "progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)";
        iframe.style.zIndex = zIndex++;

        mask = document.createElement("div");
        mask.style.display = "none";
        mask.style.position = "absolute";
        mask.style.top = "0";
        mask.style.left = "0";
        mask.style.width = "100%";
        mask.style.border = "0";
        mask.style.zIndex = zIndex++;

        // DONT use document.body here since it may not be ready yet
        el.parentNode.appendChild(iframe);
        el.parentNode.appendChild(mask);

        ErrorDisplay.iframe = iframe;
        ErrorDisplay.mask = mask;
    }

    // shows the overlay mask (creating it if needed)
    var showMask = function(el) {
        if (!ErrorDisplay.iframe && !ErrorDisplay.mask) createMask(el);
        var maskWidth = Common.getViewportWidth();
        var maskHeight = Common.getDocumentHeight();
        if (maskHeight < document.body.scrollHeight) maskHeight = document.body.scrollHeight;
        ErrorDisplay.iframe.style.height = maskHeight + "px";
        ErrorDisplay.mask.style.height = maskHeight + "px";
        ErrorDisplay.mask.className = el.maskClassName;
        ErrorDisplay.mask.onclick = function() { ErrorDisplay.close(el.id, false); };
        ErrorDisplay.iframe.style.display = "";
        ErrorDisplay.mask.style.display = "";
    }

    // hides the overlay mask (creating it if needed)
    var hideMask = function() {
        if (!ErrorDisplay.iframe && !ErrorDisplay.mask) createMask();
        ErrorDisplay.iframe.style.display = "none";
        ErrorDisplay.mask.style.display = "none";
    }

    // copy the content of the validation summaries to the correct location in the DOM (child of the ed.vsp node)
    // (we cant actually move the elements because that messes up updatepanels who expected the DOM to look a certain way)
    var copyValidationSummaries = function(ed) {
        if (Page_ValidationSummaries) {
            var sums, summary;
            for (sums = 0; sums < Page_ValidationSummaries.length; sums++) {
                summary = Page_ValidationSummaries[sums];
                summary.style.position = "absolute";
                summary.style.visibility = "hidden";
                summary.style.display = "none";
                summary.style.zIndex = "-1";
                if (summary.isservererror && summary.isservererror == "True") {
                    ed.sep.innerHTML += summary.innerHTML;
                    summary.isservererror = false;
                }
                else {
                    ed.vsp.innerHTML += summary.innerHTML;
                }
                summary.innerHTML = "";
            }
        }
    }

    // handle the fact that IE doesnt support Array.indexOf()
    if (!Array.indexOf) {
        Array.prototype.indexOf = function(obj) {
            for (var i = 0; i < this.length; i++) {
                if (this[i] == obj) {
                    return i;
                }
            }
            return -1;
        }
    }

    // this returns the public javascript interface for the ErrorDisplay object
    return {
        // registers an ErrorDisplay control with the page
        register: function(id, shouldDoValidation, invalidClassName, maskClassName) {
            var el = document.getElementById(id);
            if (el) {
                if (!el.alreadyRegistered) {
                    el.validationGroup = [];
                    el.shouldDoValidation = shouldDoValidation;
                    el.invalidClassName = invalidClassName;
                    el.maskClassName = maskClassName;
                    el.alreadyRegistered = true;
                    el.vsp = document.getElementById(el.id + "_vsp");
                    el.sep = document.getElementById(el.id + "_sep");
                }
            }
        },
        // registers an ErrorDisplayConnector control with the appropriate ErrorDisplay
        registerConnector: function(id, vg) {
            var el = document.getElementById(id);
            if (el && el.alreadyRegistered) {
                var i = el.validationGroup.indexOf(vg);
                if (i == -1) {
                    el.validationGroup.push(vg)
                }
                copyValidationSummaries(el);
            }
        },
        // shows the specified ErrorDisplay, handling the mask and and form field highlighting
        show: function(el, validationGroup, isvalid, isServerError, delay) {

            // handle any delay
            if (delay && delay > 0) {
                window.setTimeout(function() { ErrorDisplay.show(el, validationGroup, isvalid, isServerError); }, delay);
                return;
            }


            // unless this is a server error, we always run the highlight script so that 
            // fields that used to be invalid but are now valid are updated properly
            var clientInfo = document.getElementById(el.id + clientSideInformationID);
            var serverInfo = document.getElementById(el.id + serverSideInformationID);
            if (!isServerError) {
                // if this is a client error, we dont want to show the server stuff
                if (clientInfo) clientInfo.style.display = "";
                if (serverInfo) serverInfo.style.display = "none";

                var invalidClassName = (el ? el.invalidClassName : null);
                if (typeof (Page_Validators) != "undefined") {
                    var i;
                    // loop through once to set a value on each control to indicate if it already failed
                    // (this is to handle the case where multiple validators are hooked to a single control and a latter one is valid)
                    for (i = 0; i < Page_Validators.length; i++) {
                        var validator = Page_Validators[i];
                        var control = null;
                        if (validator.controltohighlight) control = document.getElementById(validator.controltohighlight);
                        if (!control && validator.controltovalidate) control = document.getElementById(validator.controltovalidate);
                        if (control) control.alreadyFailed = false;
                    }
                    // now loop through to handle the highlighting
                    for (i = 0; i < Page_Validators.length; i++) {
                        var validator = Page_Validators[i];
                        ErrorDisplay.highlightValidationError(validator, validationGroup, invalidClassName);
                    }
                }
            }
            else {
                // if this is a server error, we dont want to show the client stuff
                if (clientInfo) clientInfo.style.display = "none";
                if (serverInfo) serverInfo.style.display = "";
            }

            // if the control is invalid, show it
            if (el && !isvalid) {
                showMask(el);
                var maskWidth = Common.getViewportWidth();
                var top = window.pageYOffset || document.documentElement.scrollTop || 0;
                top += 100
                el.style.position = "absolute";
                el.style.zIndex = zIndex++;
                el.style.top = top + "px";
                el.style.display = "block";
                el.style.left = ((maskWidth / 2) - (el.clientWidth / 2)) + "px";
            }
        },
        // hides the ErrorDisplay control
        hide: function(el) {
            el.style.display = "none";
            hideMask();

            // if the ErrorDisplay was showing a server-side error, wipe
            // that out when the display is closed (since this control may end
            // up showing some unrelated client-side validation errors later on
            // the same page).
            el.sep.innerHTML = "";
        },
        // closes the ErrorDisplay control
        close: function(id, setFocus) {
            var el = document.getElementById(id);
            ErrorDisplay.hide(el);
            if (setFocus && ErrorDisplay.controlToFocus) {
                try
                {
                    ErrorDisplay.controlToFocus.focus();
                }
                catch(e)
                {
                    // TODO: Check for way to disable focus on individual validation controls instead of globally
                }
            }
            return false;
        },
        // highlights the invalid fields (and un-highlights them if they were previously invalid but now valid)
        highlightValidationError: function(validator, validationGroup, invalidClassName) {
            if (validator && validator.parentNode) {
                var sameGroup = false;
                if (!validator.validationGroup && validationGroup == "" || validator.validationGroup == validationGroup)
                    sameGroup = true;

                // see if our associated control already failed
                var control;
                var control = null;
                if (validator.controltohighlight) control = document.getElementById(validator.controltohighlight);
                if (!control && validator.controltovalidate) control = document.getElementById(validator.controltovalidate);
                if (control && control.alreadyFailed) return;

                if (validator.isvalid == "False") validator.isvalid = false;
                var isvalid = !sameGroup || validator.isvalid;
                if (control && !isvalid) control.alreadyFailed = true;

                var h = [];
                var u = [];
                var l, c, p;
                // handle the case where the validator explicitly sets the label and control to highlight
                if (validator.labeltohighlight != undefined && validator.controltohighlight != undefined) {
                    if (validator.labeltohighlight != "") l = document.getElementById(validator.labeltohighlight);
                    if (validator.controltohighlight != "") c = document.getElementById(validator.controltohighlight);
                    if (l) h.push(l);
                    if (c) h.push(c);
                }
                else {
                    // handle the case where the validator defaults to highlighting its parent
                    p = validator.parentNode;
                    h.push(p);
                }

                // handle unhighlight
                if (validator.labeltounhighlight && (!l || l.id != validator.labeltounhighlight.id)) u.push(validator.labeltounhighlight);
                if (validator.controltounhighlight && (!c || c.id != validator.controltounhighlight.id)) u.push(validator.controltounhighlight);
                if (validator.parenttounhighlight && (!p || p.id != validator.parenttounhighlight.id)) u.push(validator.parenttounhighlight);
                validator.labeltounhighlight = l;
                validator.controltounhighlight = c;
                validator.parenttounhighlight = p;

                for (var i = 0; i < u.length; i++) {
                    var node = u[i];
                    if (node) {
                        var className = (node.className ? node.className + " " : "");
                        if (node.previousInvalidClassName) {
                            className = className.replace(node.previousInvalidClassName, "");
                            node.previousInvalidClassName = null;
                            node.className = className;
                        }
                    }
                }

                for (var i = 0; i < h.length; i++) {
                    var node = h[i];
                    if (node) {
                        var className = (node.className ? node.className + " " : "");
                        var previousInvalidClassName = null;
                        var changed = false;
                        if (isvalid && node.previousInvalidClassName) {
                            className = className.replace(node.previousInvalidClassName, "");
                            previousInvalidClassName = null;
                            changed = true;
                        }
                        else if (!isvalid && !node.previousInvalidClassName) {
                            className += invalidClassName;
                            previousInvalidClassName = invalidClassName;
                            changed = true;
                        }
                        if (changed) {
                            node.previousInvalidClassName = previousInvalidClassName;
                            node.className = className;
                        }
                    }
                }
            }
        },
        // the only way we can hook into the built-in .NET client-side validation is to 
        // override the Page_ClientValidate method. this is not the greatest thing to do
        // since the method could change, but it should be relatively safe. we also have 
        // to override a few other helper functions in order to achieve the functionality
        // that we desire
        overridePage_ClientValidate: function() {
            if (window.Page_ClientValidate) {
                ErrorDisplay.internalPage_ClientValidate = Page_ClientValidate;
                Page_ClientValidate = ErrorDisplay.Page_ClientValidate;
                ErrorDisplay.internal_ValidatorSetFocus = ValidatorSetFocus;
                ValidatorSetFocus = ErrorDisplay.ValidatorSetFocus;
            }
        },
        // this is our custom version of Page_ClientValidate. if we need to do any extra processing,
        // that is handled here. in any case, the original method is called when it is required as well
        Page_ClientValidate: function(validationGroup) {
            var isValid = true;

            if (typeof (Page_ErrorDisplays) == "undefined")
                return isValid;

            // determine if we are doing validation on an ErrorDisplay or a normal validation
            var errorDisplay = null;
            var ed, eds, s;
            var vg, vgs;
            for (eds = 0; eds < Page_ErrorDisplays.length; eds++) {
                ed = Page_ErrorDisplays[eds];
                if (ed && ed.validationGroup && ed.validationGroup.length) {
                    for (vgs = 0; vgs < ed.validationGroup.length; vgs++) {
                        vg = ed.validationGroup[vgs];
                        if (vg == validationGroup) {
                            errorDisplay = ed;
                            break;
                        }
                    }
                }
            }

            // do the actual validation, if required
            if (!errorDisplay || errorDisplay.shouldDoValidation) {
                // temporarily override some functions since we cant modify them directly
                var scrollToOriginal = window.scrollTo;
                window.scrollTo = function() { }; //this is so the call to window.scrollTo(0,0) wont scroll us to the top of the page

                // do the validation
                ErrorDisplay.controlToFocus = null;
                isValid = ErrorDisplay.internalPage_ClientValidate.apply(this, arguments);
                ErrorDisplay.controlToFocus = Page_InvalidControlToBeFocused;

                // restore overridden functions
                window.scrollTo = scrollToOriginal;

                // if this is an ErrorDisplay-enabled page, handle the validation message text and show the summary
                if (errorDisplay) {
                    errorDisplay.vsp.innerHTML = "";
                    copyValidationSummaries(errorDisplay);

                    // handle showing the summary and highlighting any invalid fields
                    ErrorDisplay.show(errorDisplay, validationGroup, isValid);
                }
            }

            return isValid;
        },
        // this is our custom version of ValidatorSetFocus. we do all of this to override 
        // the internal behavior of setting the focus to the invalid control upon validation.
        // we dont want to set focus until the user clicks the 'close' button.
        // (we cant just set SetFocusOnError=false since we still need Page_InvalidControlToBeFocused
        // to be set properly)
        ValidatorSetFocus: function(val, event) {
            var ctrl;
            var focusOriginal;
            if (event) ctrl = (event.srcElement ? event.srcElement : event.target);
            if (!ctrl) ctrl = document.getElementById(val.controltovalidate);
            if (ctrl) {
                focusOriginal = ctrl.focus;
                ctrl.focus = function() { };
            }
            ErrorDisplay.internal_ValidatorSetFocus(val, event);
            if (focusOriginal) ctrl.focus = focusOriginal;
        },
        // shows a server-side exception message from javascript
        showError: function(ex) {
            if (Page_ErrorDisplays && Page_ErrorDisplays.length > 0) {
                var ed = Page_ErrorDisplays[0];
                ed.sep.innerHTML = ex.getMessage();
                ErrorDisplay.show(ed, "[SERVER]", false, true);
            }
        }
    }
} ();

ErrorDisplay.Exception = function(){
    this.header = null;
    this.messageLabel = null;
    this.messageText = null;
    this.resolutionLabel = null;
    this.resolutionText = null;
    this.referenceCodeLabel = null;
    this.referenceCodeText = null;
    this.timeOfErrorLabel = null;
    this.timeOfErrorText = null;
    this.errorCode = null;
    var me = this;
    
    this.getMessage = function(){
        var s = "<h4 class=\"red\"><span>" + me.header + "</span></h4><br><table width=\"100%\">";
        s += "<tr><td><span class=\"bold\">" + me.messageLabel + "</span><div><span>" + me.messageText + "</span></div><br></td></tr>";
        s += "<tr><td><span class=\"bold\">" + me.resolutionLabel + "</span><div><span>" + me.resolutionText + "</span></div><br></td></tr>";
        s += "<tr><td><span class=\"bold\">" + me.referenceCodeLabel + "</span> <span>" + me.referenceCodeText + " (" + me.errorCode + ")</span><br><span class=\"bold\">" + me.timeOfErrorLabel + "</span> <span>" + me.timeOfErrorText + "</span></td></tr>";
        s += "</table>";
        return s;
    }
}

Common = function(){
    return {
        getDocumentHeight : function() {
        	if (document.compatMode=='CSS1Compat') return document.documentElement.clientHeight;
        	if (document.body) return document.body.clientHeight;
        	if (window.innerHeight!=window.undefined) return window.innerHeight;
            return window.undefined;
        },
        getViewportWidth : function() {
        	var offset = 17;
        	var width = null;
        	if (window.innerWidth!=window.undefined) return window.innerWidth;
        	if (document.compatMode=='CSS1Compat') return document.documentElement.clientWidth;
        	if (document.body) return document.body.clientWidth;
        },
        getStyle : function getStyle(el, cssRule){
	        var val = "";
	        if(document.defaultView && document.defaultView.getComputedStyle){
		        val = document.defaultView.getComputedStyle(el, "").getPropertyValue(cssRule);
	        }
	        else if(el.currentStyle){
		        cssRule = cssRule.replace(/\-(\w)/g, function (match, p1){
			        return p1.toUpperCase();
		        });
		        val = el.currentStyle[cssRule];
	        }
	        return val;
        }
    }
}();