﻿function ThrowIfParamIsAbsent(requiredNamedParams, namedParamsToCheck) {
    var absentParams = [];

    for (var i = 0; i < requiredNamedParams.length; i++)
        if (typeof namedParamsToCheck[requiredNamedParams[i]] == 'undefined')
        absentParams.push(requiredNamedParams[i]);

    if (absentParams.length > 0)
        throw "The following params are required: " + absentParams.join(", ");
}


function EscapeJQueryControlID(val) {
    return val.replace(/([\.\[\]])/g, "\\$1");
}

var ajaxInvocations = [];

function NhgbAjax(options) {
    var optionsUrl = options.url.toLowerCase();
    var whenDone = function() {
        delete ajaxInvocations[optionsUrl];
    };

    try {
        $.log("NhgbAjax beforeSend - " + optionsUrl);
        if (typeof ajaxInvocations[optionsUrl] != "undefined") {
            $.log("NhgbAjax request '" + optionsUrl + "' ignored");
            return;
        }
        ajaxInvocations[optionsUrl] = true;

        var completeCallback = (typeof options.complete != "undefined") ? options.complete : function(XMLHttpRequest, textStatus) { };
        options.complete = function(XMLHttpRequest, textStatus) {
            $.log("NhgbAjax complete - " + options.url);
            completeCallback(XMLHttpRequest, textStatus);
            whenDone();
        };
        var result = $.ajax(options);
    }
    catch (e) {
        whenDone();
    }
    finally {
        StartTimeoutCountdown();
    }
    return result;
}

function StartTimeoutCountdown() {
    ///<summary>Relies upon two global variables - TimeoutUrl and TimeoutInMilliseconds.  If either one is not defined, an exception is thrown.</summary>

    if (typeof TimeoutUrl == 'undefined')
        throw "StartTimeoutCountdown requires a TimeoutUrl to have been defined.";
    if (typeof TimeoutInMilliseconds == 'undefined')
        throw "StartTimeoutCountdown requires a TimeoutInMilliseconds to have been defined.";

    if (typeof timeoutID != 'undefined') {
        $.log('clearTimeout');
        clearTimeout(timeoutID);
    }
    $.log('setTimeout');
    
    // Maintain a global variable timeoutID so that we can clear it next time through.
    timeoutID = setTimeout(function() { window.location.href = TimeoutUrl; }, TimeoutInMilliseconds );
}

function DynamicListBoxPopulator(listBoxId) {
    /// <summary>Provides the dynamic population of a listbox.  Invoke Populate with the url that provides the JSON data,
    /// as well as an optional message that will be displayed if no results are returned. 
    /// </summary>
    /// <param name="listBoxId">This control will be dynamically populated and shown, or hidden if no data is returned.</param>

    if (typeof listBoxId != "string")
        throw "DynamicListBoxPopulator requires that listBoxId be a string.";

    var listBoxId = EscapeJQueryControlID(listBoxId);

    this.Populate = function(url, emptyResultsMessage)
    /// <summary>This will be dynamically populated and shown, or hidden if no data is returned.</summary>
    /// <param name="url">The url that provides the JSON data.</param>
    /// <param name="emptyResultsMessage">A message to be displayed if no data is returned by the provided url.</param>
    {
        return NhgbAjax(
        {
            type: "post",
            url: url,
            data: {},
            dataType: "json",
            success: function(list) {
                if (list.length == 0) {
                    if (typeof (emptyResultsMessage) == "undefined")
                        emptyResultsMessage = "No data found.";

                    alert(emptyResultsMessage);
                }

                var listBox = $("#" + listBoxId);
                if (listBox.length < 1) {
                    // could not find it - lets try to escape the id
                    listBox = $("#" + listBoxId);
                }

                if (listBox.length < 1)
                    throw "Could not find a listbox whose ID is '" + listBoxId + "'.";

                if (listBox.length != 1)
                    throw "Found more than one listbox whose ID is '" + listBoxId + "'.";

                listBox.children().remove();
                $.each(list, function(i, item) {
                    $("<option value='" + item.Id + "'>" + item.UserFriendlyDisplay + "</option>").appendTo("#" + listBoxId);
                });
                if (list.length > 0)
                    listBox.show();
                else
                    listBox.hide();
            },
            error: function(xmlRequest) {
                alert(xmlRequest.responseText);
            }
        });
    }
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// jQuery extension for validating HTML in a control
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

$(document).ready(function() {

BindToolTips();

    //hide grid_body after the first one
    $(".grid_list .grid_body:gt(0)").hide();
    $(".resetbutton2:gt(0)").hide();
    $(".savebutton2:gt(0)").hide();
    $(".sectionexpandbutton2:gt(0)").show();
    $(".sectionexpandbutton2:eq(0)").hide();

    $(".sectioncollapsebutton2:gt(0)").hide();
    $(".sectioncollapsebutton2:eq(0)").show();  
    
    //toggle grid_body
    $(".grid_head").click(function() {

        var isContentDirty = ($("*").hasClass("contentChanged")); 

        if (!isContentDirty) {
            $(".grid_body").hide();
            $(".resetbutton2").hide(); // hide all reset buttons
            $(".savebutton2").hide(); //hide all save buttons
            $(".sectionexpandbutton2").show();
            $(".sectioncollapsebutton2").hide();  
            $($(this).parents(".fbsectioncontent")[0]).children(".grid_body").toggle();

            var headerRow = $($(this).parents(".toolbarcontrols")[0]);
            headerRow.find(".resetbutton2").show();
            headerRow.find(".savebutton2").show();
            headerRow.find(".sectioncollapsebutton2").show();
            headerRow.find(".sectionexpandbutton2").hide();            
        }        
    });

    //collapse all grids
    $(".collpase_all_grids").click(function() {
        $(".grid_body").hide()
        return false;
    });


    //show all grids
    $(".show_all_grids").click(function() {
        $(this).hide()
        //$(".show_recent_only").show()
        $(".grid_list div:gt(4)").show()
        return false;
    });


    $.fn.validateHTML = function(options) {
        return this.each(function() {
            //------------------
            // take me
            var me = $(this);
            var me_this = $(this)[0];
            // test for supported text elements
            if (!me.is('input:text,input:password,textarea')) {
                return;
            }
            // check plugin enabled
            if (me.attr('jqhv') == 'on') {
                return;
            }
            else {
                // plugin on!
                me.attr('jqhv', 'on');
            }
            // default options
            options = $.extend({
                allowedTags: "p|b|i|u",
                attributesAllowed: false,
                replaceTagsWith: "[tags]"
            }, options);

            me.blur(function() { validate() });
            //me.keyup(keyUpHandler);
            me.keydown(keyDownHandler);
            //me.keypress(keyPressHandler);

            var RETURN = 13;
            var TAB = 9;
            function keyUpHandler(ev) {
                validate();
            }
            function keyDownHandler(ev) {
                switch (ev.which) {
                    case RETURN: case TAB:
                        validate();
                }

            }
            function keyPressHandler(ev) {
                validate();
            }

            function validate() {

                var val = me.val();
                //alert("validating " + val);
                var HtmlValidator = new HTMLValidatorClass(options.allowedTags, options.attributesAllowed);
                HtmlValidator.ReplaceTagsWith = options.replaceTagsWith;
                //me.text(HtmlValidator.Validate(val));
                if (!HtmlValidator.Validate(val)) {
                    me.val(HtmlValidator.DeleteBadTags(val));
                }
            }
        })
    };
});

function BindToolTips(Id) {
    var selector = Id;

    if (selector != null && selector != "")
        selector = "#" + selector + " a";  //used when the user expands a module. in this case we only need to search for anchor tags within the current module   
    else
        selector = "a"; //search all anchor tags for helpid attribute

    $(selector).each(
        function() {
            var helpId = $(this).attr("helpId");

            //alert(helpId);
            if (helpId != null)
                SetTooltipText(this, helpId)
        }
    )    
}

function PostalDataRetriever(namedParams) {

    if (typeof namedParams == 'undefined')
        throw "PostalDataRetriever requires a number of named parameters - refer to the documentation";

    ThrowIfParamIsAbsent(["postalListControlId", "postalDataRetrievalUrl"], namedParams);

    if (typeof namedParams.postalListControlId != "string")
        throw "PostalDataRetriever requires that postalListControlId be a string.";
    if (typeof namedParams.postalDataRetrievalUrl != "string")
        throw "PostalDataRetriever requires that postalDataRetrievalUrl be a string.";

    var postalListCtrlId = EscapeJQueryControlID(namedParams.postalListControlId);
    var postalDataRetrievalUrl = namedParams.postalDataRetrievalUrl;
    var dynamicListBoxPopulator = new DynamicListBoxPopulator(namedParams.postalListControlId);
    var mostRecentlyRetrievedZipCode;

    this.PopulatePostalData = function(zipCode) {
        if (zipCode.length == 5 && mostRecentlyRetrievedZipCode != zipCode) {
            dynamicListBoxPopulator.Populate(postalDataRetrievalUrl + zipCode, "No data was found for this zip code.");
            mostRecentlyRetrievedZipCode = zipCode;
        }
    }
}


function PhoneFormatKeyUp(phoneNumberControl, e) {
    if (window.event)
        formatPhone(window.event, phoneNumberControl);  // IE support
    else
        formatPhone(e, phoneNumberControl);  // others, such as FireFox
}

//Format Phone Number to (xxx)xxx-xxxx
function formatPhone(e, obj) {
    if (
        (e.keyCode && e.keyCode == 9) ||  // IE handling
        (e.which == 9)     // others
        )
        return;

    var validchars = '0123456789'; // define valid characters
    p = obj.value;

    for (var i = p.length; i >= 0; i--) {
        if (validchars.indexOf(p.charAt(i)) == -1) {
            p = p.replace(p.charAt(i), '');
        }
    }

    if (p.length > 1 && p.charAt(0) != "(")
        p = "(" + p;
    if (p.length > 4 && p.charAt(4) != ")")
        p = p.substring(0, 4) + ") " + p.substring(4);
    if (p.length > 5 && p.charAt(5) != " ")
        p = p.substring(0, 5) + " " + p.substring(5);
    if (p.length > 9 && p.charAt(9) != "-")
        p = p.substring(0, 9) + "-" + p.substring(9);

    for (var xPos = 0; xPos < p.length; xPos++) {
        if ((p.charAt(xPos) == "-") && (xPos != 9)) {
            p = p.substring(0, p.length - 1);
        }
    }

    if (p.length > 14) {
        p = p.substring(0, 14)
    }
    obj.value = p;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class to validate HTML for allowed tags and well-formed tags
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructor
function HTMLValidatorClass(allowedTags, allowAttributes) {
    this.AllowedTags = allowedTags;
    this.AllowAttributes = allowAttributes;
    this.ReplaceTagsWith = '';

    // create the regExp using the allowed-tag definition.  This regExp will
    // capture the outer-most tags of the string in index locations 1 and 3.
    // Index location 2 will have anything in between, including other tags.

    var _allowedTagsRegExpText;
    var _allowedSelfClosingTagsRegExpText;

    if (this.AllowAttributes) {
        _allowedTagsRegExpText = '<(' + this.AllowedTags + ')\\b[^>]*>(.*)<\/(' + this.AllowedTags + ')>';
        _allowedSelfClosingTagsRegExpText = '<(' + this.AllowedTags + ')(\\s+[^>]+)*\\s+(\/>)'
    }
    else {
        _allowedTagsRegExpText = '<(' + this.AllowedTags + ')>(.*)<\/(' + this.AllowedTags + ')>';
        _allowedSelfClosingTagsRegExpText = '<(' + this.AllowedTags + ')\\s+(\/>)'
    }

    var _allowedTagsRegExp = new RegExp(_allowedTagsRegExpText, 'i');
    var _allowedSelfClosingTagsRegExp = new RegExp(_allowedSelfClosingTagsRegExpText, 'i');

    // create the regExp that matches dissallowed tags (adds negation to allowed tag string)

    var _badOpenTagsRegExpText = '<(?!' + this.AllowedTags.replace(/\|/g, '[ >]|') + '[ >]|\/)';
    var _badCloseTagsRegExpText = '<\/(?!' + this.AllowedTags.replace(/\|/g, '>|') + '>)';

    var _badOpenTagsRegExp = new RegExp(_badOpenTagsRegExpText, 'i');
    var _badCloseTagsRegExp = new RegExp(_badCloseTagsRegExpText, 'i');


    // create the regExp used to replace any tags

    var _anyTagsRegExp = /<\w+\b[^>]*>|<\/?\w+>/;

    // Validation:
    // 1) outer tags (indexes 1 and 3) must match (case insensitive)
    // 2) if there are tags in index 2, recurse with the string in index 2.
    // 3) if there are no allowed tags, check if there are any tags at all.
    this.Validate = function(text) {
        var allowedMatches = _allowedTagsRegExp.exec(text);
        var allowedSelfClosingMatches = _allowedSelfClosingTagsRegExp.exec(text);
        var badOpenMatches = _badOpenTagsRegExp.exec(text);
        var badCloseMatches = _badCloseTagsRegExp.exec(text);
        var anyTags = _anyTagsRegExp.exec(text);

        var wellFormed = true;

        // check for allowed tag types
        if (badOpenMatches != null || badCloseMatches != null) {
            return false;
        }
        // check form of allowedMatched pairs
        else if (allowedMatches != null && allowedMatches.length == 4) {
            if (allowedMatches[1].toUpperCase() == allowedMatches[3].toUpperCase()) {
                wellFormed = wellFormed && true;
            }
            else {
                wellFormed = false;
            }

            wellFormed = wellFormed && this.Validate(allowedMatches[2]);
        }
        // check form of self-closing allowed matches
        else if (allowedSelfClosingMatches != null && allowedSelfClosingMatches.length == 4) {

            if (allowedSelfClosingMatches[3] == '/>') {
                wellFormed = wellFormed && true;
            }
            else {
                wellFormed = false;
            }
        }

        else if (anyTags != null) {
            wellFormed = false;
        }

        return wellFormed;
    }

    this.DeleteTags = function(text) {
        text = text.replace(_anyTagsRegExp, this.ReplaceTagsWith)
        return text;
    }
    this.DeleteBadTags = function(text) {
        var _badOpenTagsgRegExpText = '<(?!' + this.AllowedTags.replace(/\|/g, '[ >]|') + '[ >]|\/)[^>]*>';
        var _badCloseTagsgRegExpText = '<\/(?!' + this.AllowedTags.replace(/\|/g, '>|') + '>)[^>]*>';

        var _badOpenTagsgRegExp = new RegExp(_badOpenTagsgRegExpText, 'ig');
        var _badCloseTagsgRegExp = new RegExp(_badCloseTagsgRegExpText, 'ig');

        text = text.replace(_badOpenTagsgRegExp, this.ReplaceTagsWith);
        text = text.replace(_badCloseTagsgRegExp, this.ReplaceTagsWith);
        return text;
    }
}


function SetTooltipText(obj, toolTipKey) {
    $.ajax({
        type: "GET",
        url: "../../ToolTipsConfig.xml",
        dataType: "xml",
        cache: true,
        success: function(xml) {
            $(xml).find(toolTipKey).each(function() {
                var xmlText = $(this).attr('value')
                //alert(value_text);
                $(obj).replaceWith("<a href='javascript:void(0)' class='tooltip' title='" + xmlText + "' helpId='" + toolTipKey + "'></a>");
                tooltip();
                return;
            });
        },
        error: function(result, error) {
            $(obj).replaceWith("<a href='javascript:void(0)' class='tooltip' title='Unable to display Help.' helpId='" + toolTipKey + "'></a>");
            tooltip();
        }
    });
}

