﻿/*

Quest Core jquery based javascript functionality 
    
Site level document.ready() functionaly is at the bottom of this script

*/


(function($) {

    $.quest = function() {

        // The 'traditional : true' property causes jQuery 1.4 to not include '[]' in the
        // parameter names for arrays when formatting data from a javascript object.
        // For instance an array like foo['a','b'] will be formatted as foo=a&foo=b
        // The non-traditional method would result in foo[]=a&foo[]=b which will not work with
        // the ASP.NET input parser.
        var process,

        baseOptions = {
            cache: false,
            dataType: 'json',
            async: true,
            traditional: true,
            doQueue: true,
            contentType: "application/json; charset=utf-8"
        },
        optionsForGet = $.extend({}, baseOptions, { type: 'GET' }),
        optionsForGetContent = $.extend({}, baseOptions, { type: 'GET', dataType: 'html' }),
        optionsForPost = $.extend({}, baseOptions, { type: 'POST' }),

        success = function(data, status, xhr, successCallback, errorCallback) {

            if (data === null) {

                // not sure what to do with this.  The only time I've seen data be null is when an ajax request has been aborted by
                // going to a new page.
                // For now, just return.  If this becomes an issue we can handle it differently as seems appropriate.

            } else if (typeof data === 'string') {

                if (successCallback) {
                    successCallback(data);
                }

            } else if (data.d) {    // response is from a Microsoft ASP.Net WebMethod
                var jData = $.parseJSON(data.d);
                if (jData.Status === 'OK') {
                    if (successCallback) {
                        successCallback(jData);
                    }
                } else {
                    if (errorCallback) {
                        errorCallback(jData.Message);
                    }
                }

            } else if (data.Status === 'OK') {

                if (successCallback) {
                    successCallback(data.Data);
                }

            } else if (errorCallback) {

                errorCallback(data.Data);

            } else {

                alert(data.Data);

            }
        },

        formatData = function(data, indent) {

            indent = indent || "";

            if (data === undefined || data === null) {
                return indent;
            }

            if (typeof data === "string") {
                return data;
            }

            var lines = [],
                line = "",
                result = "",
                newIndent = indent + '   ';

            if ($.isArray(data)) {

                result += "[\n";

                for (var i = 0, limit = data.length; i < limit; i++) {
                    lines.push(newIndent + formatData(data[i], newIndent));
                }
                result += lines.join(",\n") + "\n" + indent + "]";

                return result;
            }

            var prop,
                value;

            result += "{\n";

            for (prop in data) {

                if (data.hasOwnProperty(prop)) {

                    try {

                        value = data[prop];

                        if (typeof value !== "function") {

                            lines.push(newIndent + prop + ': ' + formatData(data[prop], newIndent));

                        }
                    }
                    catch (e) { }
                }
            }

            result += lines.join(",\n") + "\n" + indent + "}";

            return result;
        },

        error = function(xhr, status, e, callback, url, data) {

            var message = "There has been an error processing your request. The information below may help us to troubleshoot the problem.\n\n";
            message += status + ': ' + e + "\n";

            message += 'url: ' + url + "\n";
            message += 'data: ' + formatData(data);

            if (callback) {
                callback(message);
            } else {

                alert(message);
            }
        },

        buildOptions = function(base, options) {
            return $.extend({}, base, options, {
                error: function(xhr, status, e) {
                    error(xhr, status, e, options.error, options.url, options.data);
                },
                success: function(data, status, xhr) {
                    success(data, status, xhr, options.success, options.error);
                }
            });
        },

        doAjax = function(options) {
            if (options.data) {
                options.data = formatData(options.data);
            }
            return $.ajax(options);
        },

        queue = function() {

            var _queue = [],
                processing = false,
                wrapCallback, process;

            wrapCallback = function(options) {

                var innerSuccess = options.success;

                options.success = function(data, status, xhr) {
                    process();
                    innerSuccess(data, status, xhr);
                };

                var innerError = options.error;

                options.error = function(xhr, status, e) {
                    process();
                    innerError(xhr, status, e);
                };

            };

            process = function() {
                if (_queue.length === 0) {
                    processing = false;
                    return;
                }

                processing = true;

                var options = _queue.shift();

                wrapCallback(options);

                return doAjax(options);
            };

            return {

                add: function(options) {

                    _queue.push(options);

                    if (!processing) {
                        return process();
                    }

                    return null;
                }
            };
        } (),

        showProgress = function(options) {

            var pid = $.quest.progress.show(options.showProgress.target),
                innerSuccess = options.success,
                innerError = options.error;

            options.showProgress.pid = pid;

            options.success = function(data, status, xhr) {
                innerSuccess(data, status, xhr);
                $.quest.progress.hide(pid);
            };

            options.error = function(xhr, status, e) {
                innerError(xhr, status, e);
                $.quest.progress.hide(pid);
            };

        },

        doRequest = function(base, options) {

            var theOptions = buildOptions(base, options);

            if (theOptions.showProgress) {
                showProgress(theOptions);
            }

            if (theOptions.doQueue) {

                theOptions.async = true;
                return queue.add(theOptions);

            } else {

                return doAjax(theOptions);

            }
        };

        return {

            parseJson: function(data) {

                // Call the jquery method to convert a JSON string to an object.
                // throws an exception if the data is not valid JSON.
                return $.httpData({
                    getResponseHeader: function() {
                        return null;
                    },
                    responseText: data
                }, "json");
            },

            doPost: function(options) {
                return doRequest(optionsForPost, options);
            },

            doGet: function(options) {
                return doRequest(optionsForGet, options);
            },

            doGetContent: function(options) {
                return doRequest(optionsForGetContent, options);
            }
        };
    } ();




    $.quest.zorder = function() {

        var stack = [{ e: null, z: 1000, o: 1000}];

        var setZIndex = function(e, z) {

            var o = null;

            if (e.css) {

                o = e.css('z-index');
                e.css('z-index', z);

            } else if (e.style) {

                o = e.style.zIndex;
                e.style.zIndex = z;

            }

            return o;

        };

        var removeFromStack = function(e) {

            if (e === undefined || e === null) {
                return null;
            }

            var o = null;

            if (stack[stack.length - 1].e === e) {
                o = stack.pop().o;
            } else {

                var toRemove = null;

                for (var i = 0, limit = stack.length; i < limit; i++) {
                    if (stack[i].e === e) {
                        toRemove = i;
                        break;
                    }
                }

                if (toRemove !== null) {
                    o = stack[toRemove].o;
                    stack.splice(toRemove, 1);
                }
            }

            return o;

        };

        return {

            placeOnTop: function(e) {

                if (e === undefined || e === null) {
                    return;
                }

                var z = stack[stack.length - 1].z + 1;
                var o = setZIndex(e, z);

                if (o !== null) { // only complete the processing if there is a z-index to set.

                    removeFromStack(e);
                    stack.push({ e: e, z: z, o: o });

                }

            },

            remove: function(e) {
                var o = removeFromStack(e) || 'auto';
                setZIndex(e, o);
            }
        };
    } ();

    $.quest.progress = function() {

        var pid = 0,
            overlays = {};

        return {

            show: function(target) {

                target = target || $('body');

                var theOverlay = null;

                for (var testId in overlays) {

                    if (overlays.hasOwnProperty(testId)) {

                        if (overlays[testId].target === target) {
                            theOverlay = overlays[testId];
                            break;
                        }
                    }
                }

                if (theOverlay !== null) {
                    theOverlay.count++;
                    return theOverlay.id;
                }

                var id = ++pid + '',
                    wait = '<div class="thinking"><div class="shade"></div><table><tbody><tr><td><div class="bg-quest-common-thinking"></div></td></tr></tbody></table></div>',
                    element = $(wait).appendTo(target.offsetParent()).placeOnTop(),
                    image = element.find('.bg-quest-common-thinking').placeOnTop(),

                    setSize = function() {

                        var offset = target.position();

                        element.css({
                            top: offset.top,
                            left: offset.left,
                            width: (window.scrollMaxX && window.scrollMaxX > 0) ? target.width() + 17 : target.width(),
                            height: target.height()
                        });
                    };

                setSize();

                $(window).bind('resize', setSize);

                overlays[id] = {
                    id: id,
                    target: target,
                    count: 1,
                    element: element,
                    image: image,
                    resize: setSize
                };

                return id;
            },

            hide: function(id) {

                if (id === undefined || id === null) {
                    return;
                }

                var theOverlay = overlays[id];

                if (theOverlay === undefined || theOverlay === null) {
                    return;
                }

                theOverlay.count--;

                if (theOverlay.count === 0) {
                    theOverlay.image.removeFromTop();
                    theOverlay.element.removeFromTop().remove();
                    $(window).unbind('resize', theOverlay.resize);
                    delete overlays[id];
                }
            }
        };
    } ();

    $.quest.windowSize = function() {
        var h = 0, w = 0;
        if (!window.innerWidth) {
            if (!(document.documentElement.clientWidth == 0)) {
                w = document.documentElement.clientWidth;
                h = document.documentElement.clientHeight;
            } else {
                w = document.body.clientWidth;
                h = document.body.clientHeight;
            }
        } else {
            w = window.innerWidth;
            h = window.innerHeight;
        }
        return { width: w, height: h };
    };

    $.quest.cookie = function(name, value, options) {
        if (typeof value != 'undefined') { // name and value given, set cookie
            options = options || {};
            if (value === null) {
                value = '';
                options.expires = -1;
            }
            var expires = '';
            if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
                var date;
                if (typeof options.expires == 'number') {
                    date = new Date();
                    date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
                } else {
                    date = options.expires;
                }
                expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
            }
            // CAUTION: Needed to parenthesize options.path and options.domain
            // in the following expressions, otherwise they evaluate to undefined
            // in the packed version for some reason...
            var path = options.path ? '; path=' + (options.path) : '';
            var domain = options.domain ? '; domain=' + (options.domain) : '';
            var secure = options.secure ? '; secure' : '';
            document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
        } else { // only name given, get cookie
            var cookieValue = null;
            if (document.cookie && document.cookie != '') {
                var cookies = document.cookie.split(';');
                for (var i = 0; i < cookies.length; i++) {
                    var cookie = jQuery.trim(cookies[i]);
                    // Does this cookie string begin with the name we want?
                    if (cookie.substring(0, name.length + 1) == (name + '=')) {
                        cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                        break;
                    }
                }
            }
            return cookieValue;
        }
    };

    $.createId = function(base) {

        var i = 0,
            id = base + i;

        while (document.getElementById(id) !== null) {
            i++;
            id = base + i;
        }

        return id;
    };

    $.adjustHeaderHeight = function() {
        $('#main-content > .body').css('top', $('#main-content > .header').height() + 10);
    };

    $.createComboBox = function(options) {

        var item = $('<div class=""></div>'),
            content = $('<span class="selected-value truncated-text"></span>').appendTo(item);

        (options.width && content.css('width', options.width));

        item.wrapInContainer({ vertical: true, overlay: true, bodyTag: '<a></a>' });

        item.comboBox(options);

        return item;
    };

    // Creates a text input box.
    // options:
    //      maxLength - defaults to 200.
    //      name - the value of the name attribute.
    //      value - the current/default value for the textbox.
    //      size - the width in pixels
    $.createTextbox = function(options) {

        options = $.extend({}, { maxLength: 200 }, options);

        var item = $('<div class="group edit-box"></div>'),
            input = $('<input type="text"/>').attr('maxlength', options.maxLength).appendTo(item);

        (options.name && input.attr('name', options.name));
        (options.value && input.val(options.value));
        (options.size && input.attr('style', 'width:' + options.size + 'px;'));

        item.wrapInContainer({ vertical: true });

        return item;
    };

    $.createCheckbox = function(label) {
        return $.createCheckedInput('checkbox', label);
    };

    $.createRadioButton = function(label, name) {
        return $.createCheckedInput('radio', label, name);
    };

    $.handleInputItemClick = function(event, input, type) {

        if ($(event.target).attr('type') !== type) {

            event.stopImmediatePropagation();

            if (input.attr('disabled') === true) {
                return;
            }

            var isRadio = type === 'radio';

            // The jQuery trigger method has an inconsistency in that it fires bound event handlers before changing the state
            // of the control, while if the control is clicked directly, the state of the control changes before any bound
            // events are fired.
            // To handle this, we manually change the state before calling the trigger method.  Then the trigger method changes the
            // state back and we change it a third time to the final desired state.
            // This will fail if the jQuery behavior changes to be consistent with the control behavior.
            // This has been tested and appears to work in Firefox, IE 8 and IE 8 Compatibility View.

            var newState = !input.attr('checked');
            if (!isRadio || newState === true) {
                input.attr('checked', newState);
            }

            input.trigger('click');

            if (!isRadio || newState === true) {
                input.attr('checked', newState);
            }
        }

    };

    $.messageBox = function(options) {

        if (!options.content) {
            return;
        }

        if (options.isSmartHelp && !$.quest.smarthelp) {
            return;
        }

        var dialog = $('<div class="size-to-content"></div>');

        if (options.isSmartHelp) {
            options.content = options.content + '<div class="smart-help"><input type="checkbox" class="smart-help" />Turn off Smart Help</div>';
            $('input.smart-help').live('click', function() {

                $.quest.smarthelp = false;

                $.quest.doPost({

                    url: $('body').attr('data-smarthelpoffurl'),

                    error: function() {
                        // prevent an error message from displaying
                    }
                });
            });
        }

        var calcMaxWidth = function(length, threshold, maxWidth) {

            var lineHeight = 14;

            if (length < threshold) {
                return maxWidth;
            }

            // Attempt to approximate the golden ratio width to height
            if (length / threshold * lineHeight > maxWidth / 1.16) {
                return calcMaxWidth(length, threshold * 1.1, maxWidth * 1.1);
            }

            return maxWidth;

        };

        options.css = options.css || {};
        options.css.maxWidth = options.css.maxWidth || calcMaxWidth(options.content.length, 50, 350);

        dialog.append($('<div>' + options.content + '</div>'));

        (options.label && dialog.addClass('has-label'));

        dialog.dialog(options).dialog('show');

        return dialog;

    };

    // Displays a custom alert box. The alert box sizes itself to its contents.
    // Options are as follows:
    // {
    //      timeout - specifieds the number of milliseconds before the alert box hides itself.  Set to false to turn of auto-hide. Must be numeric or falsey.
    //      content - any string or HTML content to be displayed in the alert box. Experiment to get your desired look. 
    //      label - The text to be displayed for the label.  If falsey, no label is displayed. This can be any HTML. Experiment to get your desired look.
    //      okLabel - The text to display on the OK button.  If falsey, 'Ok' is displayed.
    // }
    $.alert = function(options) {

        var tid,

            defaultOptions = {
                isSmartHelp: false
            },

            overrideOptions = {
                showCancel: false,
                ok: function() {
                    (tid && clearTimeout(tid));
                }
            };

        options = $.extend({}, defaultOptions, options, overrideOptions);

        var duration = options.timeout,

            dialog = $.messageBox(options);

        if (duration) {
            tid = setTimeout(function() {
                dialog.dialog('hide');
            }, duration);
        }

        return dialog;

    };

    $.confirm = function(options) {

        var defaultOptions = {
            isSmartHelp: false
        },

            overrideOptions = {
                showCancel: true
            };

        options = $.extend({}, defaultOptions, options, overrideOptions);

        return $.messageBox(options);

    };

    $.createCheckedInput = function(type, label, name) {

        var item = $('<div></div>').addClass(type),
            input = $('<input />').attr('type', type).appendTo(item);

        (label !== undefined && item.append($('<label title="' + label + '">' + label + '</label>')));
        (name !== undefined && input.attr('name', name));

        item.bind('click', function(event) {
            $.handleInputItemClick(event, input, type);
        });

        return item;

    };

    $.fn.placeOnTop = function() {
        $.quest.zorder.placeOnTop(this);
        return this;
    };

    $.fn.removeFromTop = function() {
        $.quest.zorder.remove(this);
        return this;
    };

    $.fn.hasVerticalScrollbar = function() {
        var e = this.get(0);
        return e.scrollHeight > e.offsetHeight && (this.css('overflow') === 'auto' || this.css('overflow-y') === 'auto');
    };

    $.fn.hasHorizontalScrollbar = function() {
        var e = this.get(0);
        return e.scrollWidth > e.offsetWidth && (this.css('overflow') === 'auto' || this.css('overflow-x') === 'auto');
    };

    // Numeric only textbox control handler
    $.fn.numericOnly = function(allowDecimal, allowSign) {

        return this.each(function() {

            $(this).keydown(function(e) {

                var key = e.keyCode || e.charCode || 0,
                    ctrl = e.ctrlKey;
                // numbers,
                // keypad numbers
                // allow backspace, tab, page down, page up, end, home, insert, delete, arrows, numbers and keypad numbers
                // arrows,
                // ctrl-v, ctrl-c
                // optionally allow decimal (and keypad decimal)
                // optionally allow '-' for negative numbers
                return (
                    (key >= 48 && key <= 57) ||
                    (key >= 96 && key <= 105) ||
                    (key in { 8: 0, 9: 0, 33: 0, 34: 0, 35: 0, 36: 0, 45: 0, 46: 0 }) ||
                    (key >= 37 && key <= 40) ||
                    (ctrl === true && (key in { 86: 0, 67: 0 })) ||
                    (allowDecimal && (key in { 190: 0, 110: 0 })) ||
                    (allowSign && key === 109)

                );
            });
        });
    };

    $.fn.dataAttr = function(name) {
        return this.attr('data-' + name);
    };

    $.fn.dataAttrFromJson = function(name) {

        var attr = this.dataAttr(name);

        if (attr) {
            return $.quest.parseJson(attr);
        } else {
            return null;
        }
    };

    $.loadCss = function(url) {

        if (document.createStyleSheet) {

            document.createStyleSheet(url);

        } else {

            $('<link></link>').attr({
                rel: "stylesheet",
                type: "text/css",
                href: url
            }).appendTo($('head'));

        }
    };

    $.fn.wrapInContainer = function(options) {

        var defaultGroup = {
            className: null,
            bodyTag: '<div></div>',
            vertical: false,
            horizontal: false,
            corners: false,
            overlay: false,
            glare: false,
            useBody: true,
            forceBody: false
        };

        var o = $.extend({}, defaultGroup, options),
            childCount = this.children().length;

        if ((o.useBody || o.forceBody) && childCount > 0) {
            this.children().wrapAll($(o.bodyTag).addClass('body'));
        } else if (o.forceBody && childCount === 0) {
            this.append($(o.bodyTag).addClass('body'));
        }

        if (o.overlay || o.glare) {
            this.addBorders("overlay");
        }
        if (o.glare) {
            this.children('.overlay').addClass('glare');
        }
        if (o.vertical) {
            this.addBorders("east side", "west side");
        }
        if (o.horizontal) {
            this.addBorders("south topbottom", "north topbottom");
        }
        if (o.corners) {
            this.addBorders("nw corner", "ne corner", "sw corner", "se corner");
        }
        if (o.className) {
            this.addClass(o.className);
        }

        return this;
    };

    $.fn.addBorders = function() {
        var self = this;
        $.each(arguments, function(i, className) {
            self.prepend($('<div></div>').addClass(className));
        });
        return this;
    };

    // Returns the text contained inside an option element that has a value equal to the parameter.
    // If no option matches, null is returned.
    $.fn.getOptionText = function(value) {
        return $('option[value="' + value + '"]', this).text();
    };

    // For each element in the set of matched elements, sets the disabled attribute to the value of the option state parameter.
    // If the element is inside a container, a class of 'disabled' is added/removed on the container in addition to setting the disabled attr on the input.
    // If no parameter is passed, state is set to true.
    // For a container, all contained input elements are updated.
    $.fn.setDisabled = function(state) {

        for (var i = 0, l = this.length; i < l; i++) {

            var self = $(this[i]),
                tagName = self.get(0).tagName;
            element = tagName === 'INPUT' || tagName === 'BUTTON' ? self : self.find('input');

            if (state === undefined || state === null) {
                state = true;
            }

            element.attr('disabled', state);
            self.toggleClass('disabled', state);
        }
        return this;
    };

    // Adds or removes the 'highlighted' class based on state parameter.
    $.fn.setHighlighted = function(state) {

        for (var i = 0, l = this.length; i < l; i++) {

            var self = $(this[i]),
                tagName = self.get(0).tagName;
            element = tagName === 'INPUT' || tagName === 'BUTTON' ? self : self.find('input');

            if (state === undefined || state === null) {
                state = true;
            }
            self.toggleClass('highlighted', state);
        }
        return this;
    };

    // For each element in the set of match elements, sets the checked state to the value of the optional state parameter.
    // If no parameter is passed, the state is set to checked.
    // This method only works on a DOM structure where the input element is contained inside an element that has a class of 'checkbox' or 'radio'.
    // Either the input[type="checkbox"] or input[type="radio"] its container can be passed as the element.
    // Returns the set of matched elements.
    $.fn.setChecked = function(state) {

        for (var i = 0, l = this.length; i < l; i++) {

            var self = $(this[i]);
            self = self.attr('type') === 'checkbox' ? self.parents('.checkbox') : self;
            self = self.attr('type') === 'radio' ? self.parents('.radio') : self;

            if (!self.hasClass('checkbox') && !self.hasClass('radio')) {
                return;
            }
            if (state === undefined || state === null) {
                state = true;
            }

            self.find('input').attr('checked', state);
        }
        return this;
    };

    // For every element in the set of matched elements, reduces the size of the text content until it fits inside the width specified by the parameter.
    // returns the set of matched elements.
    // if the addToolTip parameter is true, the text is wrapped inside a span with the title set to the original text so that
    // when the user hovers over the text, a tooltip will display the full original text.
    // The original text inside each element is stored in the jquery data bucket and that text will be used if the method is called
    // more than once on the same element.
    $.fn.sizeTextToFit = function(addToolTip) {

        var s = document.documentElement.style,
            hasTextOverflow = ('textOverflow' in s || 'OTextOverflow' in s);

        var sizer = this.getTextSizer();

        sizer.empty();

        var width = 0,
            elem,
            original;

        for (var i = 0, l = this.length; i < l; i++) {

            elem = $(this[i]);
            original = elem.data('original');
            width = elem.outerWidth();

            if (width < 1) {
                continue;
            }

            if (sizer.outerWidth() >= width) {
                continue;
            }

            if (original === null) {
                original = elem.text();
                elem.data('original', original);
            }

            sizer.text(original);

            if (sizer.outerWidth() <= width) {
                elem.text(original);
                continue;
            }

            if (addToolTip === true) {
                elem.attr('title', original);
            }

            if (hasTextOverflow === true) {
                continue;
            }

            var charCount = width / sizer.charWidth() - 2,
                result = original.substr(0, charCount) + '...';

            sizer.text(result);

            while (sizer.outerWidth() > width) {
                charCount--;
                result = original.substr(0, charCount) + '...';
                sizer.text(result);
            }

            elem.text(result);
        }
        return this;
    };

    $.fn.charWidth = function() {
        return this.outerWidth() / this.text().length;
    };

    $.fn.averageCharWidth = function() {
        return this.innerWidth() / this.text().length;
    };

    $.fn.getTextSizer = function() {
        var sizer = $('#winTextSizer');
        if (sizer.length === 0) {
            sizer = $('<div id="winTextSizer" style="position:absolute;left:-99999px;top:-9999px;"></div>').appendTo('body');
        }
        sizer.css(this.extractWidthMetrics());
        return sizer;
    };

    // extracts the css attributes that effect width and returns them in a javascript object from the first element in the set of matched elements.
    $.fn.extractWidthMetrics = function() {
        if (this.length === 0) {
            return {};
        }
        var result = {},
            src = $(this),
            attrs = [
                'fontFamily',
                'fontSize',
                'fontStyle',
                'fontSizeAdjust',
                'fontVariant',
                'fontWeight',
                'paddingLeft',
                'paddingRight',
                'borderLeft',
                'borderRight',
                'marginLeft',
                'marginRight'
            ];
        $.each(attrs, function(i, attr) {
            result[attr] = src.css(attr);
        });
        return result;
    };

    // Checks a string to see if it in a valid date format
    // of (D)D/(M)M/(YY)YY and returns true/false
    $.fn.isValidDate = function(s) {
        // format D(D)/M(M)/(YY)YY
        var dateFormat = /^\d{1,4}[\.|\/|-]\d{1,2}[\.|\/|-]\d{1,4}$/;
        if (dateFormat.test(s)) {
            // remove any leading zeros from date values
            s = s.replace(/0*(\d*)/gi, "$1");
            var dateArray = s.split(/[\.|\/|-]/);
            // correct month value
            dateArray[1] = dateArray[1] - 1;
            // correct year value
            if (dateArray[2].length < 4) {
                // correct year value
                dateArray[2] = (parseInt(dateArray[2]) < 50) ? 2000 + parseInt(dateArray[2]) : 1900 + parseInt(dateArray[2]);
            }
            var testDate = new Date(dateArray[2], dateArray[1], dateArray[0]);
            if (testDate.getDate() != dateArray[0] || testDate.getMonth() != dateArray[1] || testDate.getFullYear() != dateArray[2]) {
                return false;
            } else {
                return true;
            }
        } else {
            return false;
        }
    };

    /** jQuery.toJSON( json-serializble )
    Converts the given argument into a JSON respresentation.

        If an object has a "toJSON" function, that will be used to get the representation.
    Non-integer/string keys are skipped in the object, as are keys that point to a function.

        json-serializble:
    The *thing* to be converted.
    **/
    $.toJSON = function(o) {
        if (typeof (JSON) == 'object' && JSON.stringify)
            return JSON.stringify(o).replace(/\/Date\((-?[0-9]+)\)\//g, "\\/Date($1)\\/");

        var type = typeof (o);

        if (o === null)
            return "null";

        if (type == "undefined")
            return undefined;

        if (type == "number" || type == "boolean")
            return o + "";

        if (type == "string")
            return $.quoteString(o);

        if (type == 'object') {
            if (typeof o.toJSON == "function")
                return $.toJSON(o.toJSON());

            if (o.constructor === Date) {
                var month = o.getUTCMonth() + 1;
                if (month < 10) month = '0' + month;

                var day = o.getUTCDate();
                if (day < 10) day = '0' + day;

                var year = o.getUTCFullYear();

                var hours = o.getUTCHours();
                if (hours < 10) hours = '0' + hours;

                var minutes = o.getUTCMinutes();
                if (minutes < 10) minutes = '0' + minutes;

                var seconds = o.getUTCSeconds();
                if (seconds < 10) seconds = '0' + seconds;

                var milli = o.getUTCMilliseconds();
                if (milli < 100) milli = '0' + milli;
                if (milli < 10) milli = '0' + milli;

                return '"' + year + '-' + month + '-' + day + 'T' +
                             hours + ':' + minutes + ':' + seconds +
                             '.' + milli + 'Z"';
            }

            if (o.constructor === Array) {
                var ret = [];
                for (var i = 0; i < o.length; i++)
                    ret.push($.toJSON(o[i]) || "null");

                return "[" + ret.join(",") + "]";
            }

            var pairs = [];
            for (var k in o) {
                var name;
                var type = typeof k;

                if (type == "number")
                    name = '"' + k + '"';
                else if (type == "string")
                    name = $.quoteString(k);
                else
                    continue;  //skip non-string or number keys

                if (typeof o[k] == "function")
                    continue;  //skip pairs where the value is a function.

                var val = $.toJSON(o[k]);

                pairs.push(name + ":" + val);
            }

            return "{" + pairs.join(", ") + "}";
        }
    };

    /** jQuery.evalJSON(src)
    Evaluates a given piece of json source.
    **/
    $.evalJSON = function(src) {
        if (typeof (JSON) == 'object' && JSON.parse)
            return JSON.parse(src);
        return eval("(" + src + ")");
    };

    /** jQuery.secureEvalJSON(src)
    Evals JSON in a way that is *more* secure.
    **/
    $.secureEvalJSON = function(src) {
        if (typeof (JSON) == 'object' && JSON.parse)
            return JSON.parse(src);

        var filtered = src;
        filtered = filtered.replace(/\\["\\\/bfnrtu]/g, '@');
        filtered = filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
        filtered = filtered.replace(/(?:^|:|,)(?:\s*\[)+/g, '');

        if (/^[\],:{}\s]*$/.test(filtered))
            return eval("(" + src + ")");
        else
            throw new SyntaxError("Error parsing JSON, source is not valid.");
    };

    /** jQuery.quoteString(string)
    Returns a string-repr of a string, escaping quotes intelligently.  
    Mostly a support function for toJSON.
    
    Examples:
    >>> jQuery.quoteString("apple")
    "apple"
        
    >>> jQuery.quoteString('"Where are we going?", she asked.')
    "\"Where are we going?\", she asked."
    **/
    $.quoteString = function(string) {
        if (string.match(_escapeable)) {
            return '"' + string.replace(_escapeable, function(a) {
                var c = _meta[a];
                if (typeof c === 'string') return c;
                c = a.charCodeAt();
                return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
            }) + '"';
        }
        return '"' + string + '"';
    };

    var _escapeable = /["\\\x00-\x1f\x7f-\x9f]/g;

    var _meta = {
        '\b': '\\b',
        '\t': '\\t',
        '\n': '\\n',
        '\f': '\\f',
        '\r': '\\r',
        '"': '\\"',
        '\\': '\\\\'
    };


    /*******************************/
    /* Begin UI Widget definitions */
    /*******************************/

    /*** aspButton Widget - used to stylize an asp:Button object
    *
    *   Note: To properly use this widget, the asp:Button must be wrapped in a <div>
    *
    *   <div class="homestyle">
    *      <asp:Button ID="btnPublicSearch" runat="server" Visible="true" ToolTip="Click here to begin a search." CssClass="homestyle" Text="Search Database" />   
    *   </div>
    *
    *   Usage:
    *
    *      $('div.homestyle').each(function() {
    *          $(this).aspButton({ CssClass: 'homestyle' }); 
    *      });
    *
    ***/

    $.widget("quest.aspButton", {

        options: {
            CssClass: ""
        },

        _init: function() {
            var e = this.element,
                o = this.options;
            e.wrapInContainer({
                vertical: true,
                horizontal: true,
                corners: true,
                className: o.CssClass,
                glare: false,
                forceBody: true
            });
        }

    });

    $.extend($.quest.aspButton, {
        version: "1.0.0"
    });


    /*** WaterMark Widget - Displays a water mark on input boxes
    *
    *   Usage: $('input').waterMark({ text: "Insert Search Criteria" });
    *
    ***/
    $.widget("quest.waterMark", {

        options: {
            text: "",
            color: "#ccc"
        },

        _init: function() {
            var self = this,
                e = self.element,
                o = self.options,
                text = o.text,
                color = o.color;

            // It is possible that this.element is a wrapper around the actual input element.
            if (e.get(0).tagName !== 'INPUT') {
                e = e.find('input');
            }

            var defaultColor = e.css("color");

            function clearMessage() {
                if (e.val() === text) {
                    e.val("");
                }
                e.css("color", defaultColor);
                e.css("font-style", "inherit");
            }

            function insertMessage() {
                if (e.val().length === 0 || e.val() === text) {
                    e.val(text);
                    e.css("color", color);
                    e.css("font-style", "italic");
                } else {
                    e.css("color", defaultColor);
                    e.css("font-style", "inherit");
                }
            }

            e.focus(clearMessage);
            e.blur(insertMessage);
            e.change(insertMessage);

            insertMessage();

        },

        getText: function() {
            var self = this,
                e = self.element,
                o = self.options,
                text = o.text;

            if (e.val() === text) {
                return "";
            } else {
                return e.val();
            }
        }
    });

    $.extend($.quest.waterMark, {
        version: "1.0.0",
        eventPrefix: "waterMark",
        defaults: {
            text: "",
            color: "#ccc"
        }
    });


    $.widget('quest.modalDialogPopup', {

        _init: function() {
            var e = this.element,
                o = this.options,
                overlay = $('<iframe class="overlay"></iframe>');

            this.overlay = overlay;
            this.contents = e.children();

            this.contents.wrapAll('<div class="modal-dialog-popup-content"></div>');

            e.wrapInContainer({ vertical: true, horizontal: true, corners: true, className: 'modalDialogPopup container', glare: true, forceBody: true });

            e.click(function(event) {
                if (event.target === e.get(0)) {
                    o.clickOff();
                }
            });

            if (o.className) {
                e.addClass(o.className);
            }

            overlay.click(o.clickOff);
            overlay.load(function() {
                $(overlay.get(0).contentWindow.document).bind('click', o.clickOff);
            });

            $('body').append(overlay);
        },

        destroy: function() {
            this.overlay.remove();
            this.element.hide().empty().append(this.contents).removeClass('container').removeClass('modalDialogPopup');
            if (this.options.className) {
                this.element.removeClass(this.options.className);
            }
        },

        show: function(css) {
            if (css) {
                this.element.css(css);
            }

            this.overlay.addClass(this.options.overlayStyle);
            this.element.show();

            this.overlay.placeOnTop();
            this.element.placeOnTop();
        },

        hide: function() {
            this.element.removeFromTop();
            this.overlay.removeFromTop();
            this.overlay.removeClass(this.options.overlayStyle);
            this.element.hide();
        }

    });

    $.extend($.quest.modalDialogPopup, {
        version: "1.0.0",
        eventPrefix: "modalDialogPopup",
        defaults: {
            clickOff: $.noop,
            overlayStyle: 'shaded'
        }
    });

})(jQuery);



$(document).ready(function() {

    var cookieOptions = { expires: 7, path: '/' },
        siteMenuCookie = 'siteMenuCookie';

    // working code for our site navigation menu to handle the slide downs for sub menu items
    $('.siteMenu li.container').each(function() {
        var self = this,
            linkText = $(this).children('a').html().replace(' ', '_'),
            cookieKey = siteMenuCookie + '-' + linkText,
            icon = $('<span></span>').addClass('icon small');
        // append our +/- icon container
        icon.prependTo($(this));
        // check our cookie to set our inital state
        var myCookie = $.quest.cookie(cookieKey);
        if (myCookie == null || myCookie == 'closed') { // no cookie or state set to closed
            icon.addClass('plus');
        } else {
            icon.addClass('minus');     // our state is set to opened
            $(this).addClass('over');
        }
        // setup our click handler for the LI's
        var clickHandler = function() {
            if ($(self).hasClass('over')) {
                icon.removeClass('minus').addClass('plus');
                $(self).find('ul').hide('blind');
                $(self).removeClass('over');
                $.quest.cookie(cookieKey, 'closed', cookieOptions);
            } else {
                icon.removeClass('plus').addClass('minus');
                $(self).find('ul').show('blind');
                $(self).addClass('over');
                $.quest.cookie(cookieKey, 'open', cookieOptions);
            }
            return false;
        };
        icon.click(function() {
            return clickHandler();
        });
        $(this).children('a').click(function() {
            return clickHandler();
        });
    });

    // Confirmation Code on page exit for menu links with the "public" CSS class (Should only be on the secure site)
    $('.siteMenu a.public').click(function() {
        var dlg = $('<div></div>').appendTo('body');
        $('<span></span>').addClass('ui-icon ui-icon-info dialog-icon').appendTo(dlg);
        $('<span></span>').addClass('text').html('By clicking this link, you are leaving your committee workspace. To reenter your workspace, click the Return to Secure Site button.').appendTo(dlg);
        var lnk = $(this).attr('href');
        dlg.dialog({
            title: "Confirm Exit",
            resizable: false,
            modal: true,
            height: 200,
            width: 420,
            buttons: [
                {
                    text: "Continue",
                    click: function() {
                        window.location = lnk;
                    }
                },
                {
                    text: "Cancel",
                    click: function() {
                        $(this).dialog("close");
                        $('body').remove(dlg);
                    }
                }
            ]
        });
        return false;
    });

});
