/* Minification failed. Returning unminified contents.
(13302,19-20): run-time error JS1010: Expected identifier: .
(13302,19-20): run-time error JS1195: Expected expression: .
(13307,19-20): run-time error JS1010: Expected identifier: .
(13307,19-20): run-time error JS1195: Expected expression: .
(13312,19-20): run-time error JS1010: Expected identifier: .
(13312,19-20): run-time error JS1195: Expected expression: .
(13317,19-20): run-time error JS1010: Expected identifier: .
(13317,19-20): run-time error JS1195: Expected expression: .
 */
window.UNGM = {
    autocompletes: [],
    initialised: false,
    isAuthenticated: false,
    isVendor: false,
    ungmNumber: null,
    isRtl: false,
    mobileTabWidth: 768,
    siteRoot: null, // this should be set by a razor view via config
    clipBoardToolBarItems: ['Cut', 'Copy', 'Paste', '-', 'Undo', 'Redo', 'RemoveFormat', '-', 'HorizontalRule', '-', 'Scayt'],
    styleToolBarItems: ['Format', 'Bold', 'Italic', '-', 'NumberedList', 'BulletedList', '-', 'Outdent', 'Indent'],
    sourceToolBarItems: ['-', 'Source'],
    linkToolBarItems: ['-', 'Link', 'Unlink'],
    tableToolBarItems: ['-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 'Table'],
    standardToolbar: null,
    standardToolbarWithSource: null,
    standardToolbarWithLinks: null,
    standardToolbarWithSourceLink: null,
    standardToolbarWithSourceLinkTable: null,
    init: function () {
        $.ajaxSetup({ cache: false }); // Disable caching of AJAX responses
        $(document).ajaxError(UNGM.ajaxErrorHandler);
        $(document).ajaxSend(UNGM.ajaxSendHandler);

        UNGM.highlightMenuItem();
        UNGM.highlightTreeMenuItem();

        UNGM.initDatePickers();
        UNGM.initTabs();
        UNGM.initFilters();
        UNGM.Component.FlyoutMenu();
        UNGM.initCollapsables();
        UNGM.initTextEditorToolBarItems();

        // Update the email count after a while to avoid the query to block other queries more important
        setTimeout(UNGM.updateInboxCount, 100);
        setTimeout(UNGM.updateUngmNumber, 100);

        UNGM.getUserLanguage();

        $(".language-dropdown").click(UNGM.languageSelectClicked);
        $("#nav-icon-top-bar").bind("click", UNGM.openOrCloseNavigation);
        $("#btnMyNote").bind("click", UNGM.UserNoteClick);
        $("#cmdEndImpersonation, #cmdEndReadOnlyImpersonation").bind("click", UNGM.EndImpersonation);
        $(".left-menu-expand-button, .left-menu-collapse-button").off("click").on("click", UNGM.toggleLeftMenu);
        $(".track-document-download").off("click").on("click", function (e) {
            UNGM.gaEvent("DocumentDownload", "download", $(e.currentTarget).data("document-name"));
        });

        $(".logoHolder").bind("click", function () {
            window.location.href = UNGM.siteRoot;
        });

        $(".numericOnly").on("keydown", UNGM.ensureNumeric); //move any filter advanced buttons down to after the basic div

        $(".filterExpandHolder").each(function (index, selector) {
            $(selector).insertAfter($(selector).siblings(".filterBasic"));
        });


        // bind to the dialog open and close event to prevent bg scrolling
        $(document).bind("dialogopen open", ".ui-dialog", function (event, ui) {
            $('body').css('overflow', 'hidden');

            try {
                // Include validation on hidden fields (for invalid data on non-active tab)
                $.validator.setDefaults({ ignore: '' });
                //Parse the ajax-loaded content for stuff to validate
                window.UNGM.Validation.init();
                $.validator.unobtrusive.parse($(".ui-dialog"));
            }
            catch (e) { }
        });
        $(document).on("dialogclose close", ".ui-dialog", function (event, ui) {
            // Verify that there are no dialogs opened
            if ($(".ui-dialog:visible").length == 0) {
                $('body').css('overflow', 'scroll');
            }
        });

        UNGM.initialised = true;
        // This should mark all required fields in forms with a star *
        UNGM.markRequiredFields();

        $("#toggleAccessibleThrobber").bind("click", UNGM.toggleAccessibleThrobber);
    },
    toggleLeftMenu: function () {
        $("#left").toggleClass("left-menu-collapsed");
        $("#left").children(".left-menu-content").fadeToggle(250, 'easeOutBounce');
        $("#centre").toggleClass("centre-expanded");
    },
    scrollToElement: function ($element) {
        $([document.documentElement, document.body]).animate({
            scrollTop: $element.offset().top - $(".top-bar").height() - 10
        }, 2000);
    },
    initTextEditorToolBarItems: function () {
        UNGM.standardToolbar = [UNGM.clipBoardToolBarItems, UNGM.styleToolBarItems];
        UNGM.standardToolbarWithSource = [UNGM.clipBoardToolBarItems.concat(UNGM.sourceToolBarItems), UNGM.styleToolBarItems];
        UNGM.standardToolbarWithLinks = [UNGM.clipBoardToolBarItems.concat(UNGM.linkToolBarItems), UNGM.styleToolBarItems];
        UNGM.standardToolbarWithSourceLink = [UNGM.clipBoardToolBarItems.concat(UNGM.sourceToolBarItems).concat(UNGM.linkToolBarItems), UNGM.styleToolBarItems];
        UNGM.standardToolbarWithSourceLinkTable = [UNGM.clipBoardToolBarItems.concat(UNGM.sourceToolBarItems).concat(UNGM.linkToolBarItems), UNGM.styleToolBarItems.concat(UNGM.tableToolBarItems)];
    },
    getDatepickerVal: function (selector) {
        var date = $(selector).datepicker("getDate");
        return $.datepicker.formatDate('yy-mm-dd', date);
    },
    parseLocalDateToDate: function (localDate) {
        var format = UNGM.currentuserCookieLanguage === 'zh' ? 'yy-mm-dd' : UNGM.currentuserCookieLanguage === 'ru' ? 'dd.mm.yy' : 'dd-M-yy';
        return $.datepicker.parseDate(format, localDate);
    },
    formatLocalDate: function (date) {
        var format = UNGM.currentuserCookieLanguage === 'zh' ? 'yy-mm-dd' : UNGM.currentuserCookieLanguage === 'ru' ? 'dd.mm.yy' : 'dd-M-yy';
        return $.datepicker.formatDate(format, date);
    },
    ensureNumeric: function (evt) {

        var character = String.fromCharCode(evt.which || evt.keyCode);
        var matches = character.match(/^[A-Z]+$/);

        if (matches && matches.length > 0 && !evt.shiftKey && !evt.ctrlKey && !evt.altKey) {
            evt.preventDefault();
            evt.stopPropagation();
            evt.cancel = true;
            return false;
        }
    },
    highlightMenuItem: function () {
        $("#left li a:not(.nav-content)").each(function () {
            var linkRef = $(this).attr("href");
            linkRef = linkRef.replace("/", "");
            if (UNGM.siteRoot + linkRef == window.location.href) {
                if ($(this).is("#my-tenders-link")) {
                    UNGM.loadLinksToEprocurementAppsForMyTenders();
                }
                $(this).addClass("current");
                if (UNGM.browsingWithInternetExplorer7()) {
                    // do the css stuff manually for the benefit of IE7
                    if ($(this).parent("li").children("ul.navLevel3").length > 0) {
                        // the selected item has a navlevel3 subdir
                        $(this).parent("li").children("ul.navLevel3").show();
                    } else if ($(this).parents("ul.navLevel3").length > 0) {
                        // the selected item is in a navlevel4 subdir
                        $(this).parents("ul.navLevel3").show();
                        $(this).parents("ul.navLevel4").show();
                        $(this).parent("li").children("ul.navLevel4").show();
                    }
                }
                // end of IE7 polyfill
                var l3parent = $(this).parents("ul.navLevel3:first");
                if (l3parent.length > 0) {
                    l3parent.prev().addClass("current");
                }

                var l4parent = $(this).parents("ul.navLevel4:first");
                if (l4parent.length > 0) {
                    l4parent.prev().addClass("current");
                }
            }
        });
    },
    highlightTreeMenuItem: function () {
        $("#left ul li.nav > a.nav-content").each(function () {
            var element = $(this);
            var link = UNGM.siteRoot + element.attr("href").replace("/", "");
            if (link == window.location.href) {
                element.parents(".nav").addClass("current");
            }
        });
    },
    loadLinksToEprocurementAppsForMyTenders: function () {
        UNGM.Throbber.Push();
        $.get("/Vendor/Menu/LinksToEprocurementAppsForMyTenders")
            .done(
                function (data) {
                    $("#my-tenders-link").next("ul").html(data);
                    UNGM.Throbber.Pop();
                });
    },
    EndImpersonation: function () {
        UNGM.throbOver($('body'));
        $.ajax({
            url: UNGM.siteRoot + 'Admin/Users/EndImpersonation',
            type: 'GET',
            success: UNGM.onImpersonationEnded
        });
    },
    onImpersonationEnded: function () {
        window.location.href = UNGM.siteRoot + '/Admin/Users';
    },
    UserNoteClick: function () {
        UNGM.throbOver($("#wholePage"));
        $.ajax({
            url: UNGM.siteRoot + 'UNUser/MyNote',
            type: 'GET',
            async: false,
            success: UNGM.onNoteDialogLoaded
        });
    },
    onNoteDialogLoaded: function (data) {
        $("#myNoteContent").html(data);
        $("#myNoteContent").dialog({
            open: function () {
                $(this).css("maxHeight", 600);
            },
            modal: true,
            width: '50%',
            hide: { effect: 'fade', duration: 100 },
            show: { effect: 'fade', duration: 100 },
            close: function () {
                UNGM.UserNotes.ckEditorLoaded = false;
                // destroy the edit dialog. Not sure why I have to do this, but if I do not, it's duplicated if I reopen the notes functionality
                if ($("#EditNote").hasClass('ui-dialog-content')) {
                    $("#EditNote").dialog("destroy").remove();
                }
            }
        });
        UNGM.hideThrobber();
    },
    ajaxErrorHandler: function (event, xhr, options, exc) {
        UNGM.hideThrobber();
        // xhr status is reset to zero on page unload, so this should stop the error message if the user has just navigated away from the page during an ajax request.
        // unfortunately, Chrome also resets the xhr status for a timeout, so also have to check the statusText.
        if (xhr.status != 0 || xhr.statusText == "timeout") {

            var error = {
                ThrownError: exc,
                Status: xhr.status,
                StatusText: xhr.statusText,
                RequestedPage: options.url
            };

            $.confirm(
                UNGM.ErrorDialogTitle,
                UNGM.ErrorDialogMessage,
                UNGM.ErrorDialogBtnSendFeedback,
                UNGM.ErrorDialogBtnCancel,
                function () {
                }, //"yes" callback
                400 // the minimum width of the model dialog
            );
        }
    },
    ajaxSendHandler: function (event, xhr, settings) {
        try {
            ga.push(['_trackPageview', settings.url]);
        }
        catch (ex) { }
    },
    throbOver: function (elem) {
        if (localStorage.getItem("accessibleThrobber") !== undefined && localStorage.getItem("accessibleThrobber")) {
            $(".throbber__inner").hide();
            $(".throbber__inner__alt").show();
        }
        // Per element... which means you have to get the right element 100 times
        /*var height = $(elem).outerHeight();
        var width = $(elem).outerWidth();
        var throbDiv = $("#mainThrobber");
        throbDiv.css("height", height + "px").css("width", width + "px");
        var position = $(elem).offset();
        throbDiv.css(position);
        throbDiv.show();*/

        // Or brute force... Whole page to make sure (note: CSS changes also required)
        $("#mainThrobber").fadeIn('fast');
    },
    hideThrobber: function () {
        $("#mainThrobber").fadeOut('fast');
    },
    toggleAccessibleThrobber: function () {
        if (localStorage.getItem("accessibleThrobber") !== undefined && localStorage.getItem("accessibleThrobber")) {
            localStorage.removeItem("accessibleThrobber");
            $(".throbber__inner").show();
            $(".throbber__inner__alt").hide();

        } else {
            localStorage.setItem("accessibleThrobber", "true");
            $(".throbber__inner").hide();
            $(".throbber__inner__alt").show();
        }
    },
    showPleaseWaitMessage: function () {
        $(".throbber__inner__pleasewait").fadeIn();
    },
    hidePleaseWaitMessage: function () {
        $(".throbber__inner__pleasewait").hide();
    },
    initDatePickers: function () {
        if ($.datepicker) {
            var dateFormat = UNGM.currentuserCookieLanguage === 'zh' ? 'yy-mm-dd' : UNGM.currentuserCookieLanguage === 'ru' ? 'dd.mm.yy' : 'dd-M-yy';
            $.datepicker.setDefaults($.datepicker.regional[$('html').attr('lang')]);
            $.datepicker.setDefaults({ dateFormat: dateFormat });
            $(".dateField").datepicker({
                onSelect: function () {
                    // Ensure the change event is fired on the underlying textbox
                    $(this).change();
                },
                changeYear: true,
                changeMonth: true
            });
        }
    },
    initDatePickersIn: function (container) {
        container.find(".dateField").datepicker({
            onSelect: function () {
                // Ensure the change event is fired on the underlying textbox
                $(this).change();
            },
            changeYear: true,
            changeMonth: true
        });
    },
    initTabs: function () {
        // if we're on a mobile device, change the ordering, so it goes tab - content - tab - content- etc, etc
        if ($(window).width() < UNGM.mobileTabWidth) {
            var numTabs = $(".tabHeader").length;
            for (var i = numTabs; i > 0; i--) {
                $(".tabBodies .tab:nth-child(" + i + ")").insertAfter(".tabHeaders .tabHeader:nth-child(" + i + ")");
            }
        }

        $(".tabHeader:not(.tabDisabled)").off("click").on("click", UNGM.tabHeaderClicked);
        $(".tabHeader:not(.tabDisabled)").off("keypress").on("keypress", UNGM.tabHeaderClicked);

        // Identify the tab to select by default
        var parameter = "#tab=";
        if (window.location.href.indexOf(parameter) !== -1) {
            // Index of parameter tab
            var index1 = window.location.href.indexOf(parameter) + parameter.length;

            // Index of next parameter, if any
            var index2 = window.location.href.indexOf("&", index1);
            if (index2 === -1) {
                // There are no more parameters, get the end of the URL
                index2 = window.location.href.length;
            }
            var tabId = window.location.href.substring(index1, index2);

            if (tabId.length) {
                var tabHeader;
                if (isNaN(tabId)) {
                    // The tab to select is an ID selector
                    tabHeader = $(".tabs .tabHeader#" + tabId);
                } else {
                    // The tab to select is the index of tabs
                    tabId = parseInt(tabId);
                    tabHeader = $(".tabs .tabHeader:nth-child(" + tabId + ")");
                }

                if (tabHeader.length) {
                    tabHeader.click();
                    return true;
                }
            }
        }

        $(".tabs").find(".tabHeader:first").click();
    },
    initTabsIn: function (container) {
        // if we're on a mobile device, change the ordering, so it goes tab - content - tab - content- etc, etc
        if ($(window).width() < UNGM.mobileTabWidth) {
            var numTabs = container.find(".tabHeader").length;
            for (var i = numTabs; i > 0; i--) {
                container.find(".tabBodies .tab:nth-child(" + i + ")").insertAfter(container.find(".tabHeaders .tabHeader:nth-child(" + i + ")"));
            }
        }
        container.off("click", ".tabHeader:not(.tabDisabled)", UNGM.tabHeaderClicked);
        container.on("click", ".tabHeader:not(.tabDisabled)", UNGM.tabHeaderClicked);
        container.on("keypress", ".tabHeader:not(.tabDisabled)", UNGM.tabHeaderClicked);
        container.find(".tabHeader:first").click();
    },
    tabHeaderClicked: function (evt) {
        var sender = $(evt.currentTarget);
        var parent = sender.closest(".tabs");
        var tabIndex = parent.find(".tabHeader").index(sender);

        var isMobileDevice = $(window).width() < UNGM.mobileTabWidth;
        //if we're on a mobile device, behave like an accordion
        if (isMobileDevice) {
            if (sender.hasClass("activeTab")) {
                sender.removeClass("activeTab");
                parent.find(".tab").eq(tabIndex).slideUp(400);
            }
            else {
                sender.addClass("activeTab");
                parent.find(".tab").eq(tabIndex).slideDown(400);
            }
        }
        else {
            var sender = $(evt.currentTarget);
            var parent = sender.closest(".tabs");
            parent.children(".tabHeaders").children(".activeTab").removeClass("activeTab");
            sender.addClass("activeTab");
            var tabIndex = parent.find(".tabHeader").index(sender);
            parent.children(".tabBodies").children(".tab").hide().eq(tabIndex).fadeIn('fast');
        }
        var jsName = parent.find(".tab").eq(tabIndex).find("#jsName").val();
        if (typeof jsName !== "undefined") {
            window["UNGM"][jsName]["init"]();
        }

        // Add GA on tab clicked
        var eventLabel = sender.data("galabel");
        var eventCategory = sender.parents(".tabs").data("gacategory");
        UNGM.gaEvent(eventCategory, "Tab click", eventLabel);

        // Second part: load content
        var tabElement;
        if (isMobileDevice) {
            tabElement = parent.find(".tab").eq(tabIndex);
        } else {
            tabElement = parent.children(".tabBodies").children(".tab").eq(tabIndex);
        }

        var url = tabElement.data("url");
        if (url === null || url === undefined || !url.length) {
            return true;
        }

        var reloadContent = tabElement.data("reload") === undefined || tabElement.data("reload") === true;
        if (!reloadContent) {
            return true;
        }
        tabElement.data("reload", false);
        UNGM.reloadTab(tabElement);
    },
    reloadTab: function (selector) {
        var tab = $(selector);
        UNGM.Throbber.Push();
        $.ajax({
            url: UNGM.siteRoot + tab.data('url'),
            type: 'GET',
            success: function (data) {
                tab.html(data);
                if (tab.find(".tabs").length) {
                    UNGM.initTabsIn(tab);
                }
                if (tab.find("form").length) {
                    UNGM.Validation.initForElement(tab.find("form"));
                    UNGM.markRequiredFields();
                }
                if (UNGM.tabContentReceivedCallback) {
                    UNGM.tabContentReceivedCallback(tab);
                }
            },
            complete: UNGM.Throbber.Pop
        });
    },
    gaEvent: function (eventCategory, eventName, eventLabel) {
        try {
            if (eventName !== undefined && eventName !== null && eventLabel !== undefined && eventLabel !== null && eventCategory !== undefined && eventCategory !== null) {
                gtag("event", eventName, {
                    'event_category': eventCategory,
                    'event_label': eventLabel
                });
            }
        }
        catch (ex) { }
    },
    getCookie: function (name) {
        var i, x, y, ARRcookies = document.cookie.split(";");
        for (i = 0; i < ARRcookies.length; i++) {
            x = ARRcookies[i].substr(0, ARRcookies[i].indexOf("="));
            y = ARRcookies[i].substr(ARRcookies[i].indexOf("=") + 1);
            x = x.replace(/^\s+|\s+$/g, "");
            if (x == name) {
                return unescape(y);
            }
        }
    },
    cookiesEnabled: function () {
        document.cookie = "cookietest=1";
        var enabled = document.cookie.indexOf("cookietest=") != -1;
        document.cookie = "cookietest=1; expires=Thu, 01-Jan-1970 00:00:01 GMT";

        return enabled;
    },
    setUserLanguage: function (preferredLanguage) {
        if (preferredLanguage !== UNGM.currentuserCookieLanguage) {
            var postObject = {
                PreferredLanguage: preferredLanguage
            };

            $.ajax({
                url: "/Account/UserSettings/PreferredLanguage",
                type: 'POST',
                contentType: 'application/json',
                data: JSON.stringify(postObject),
                complete: function () {
                    window.location.reload();
                }
            });
        }
    },
    getUserLanguage: function () {
        // Read cookie and set language
        if (UNGM.currentuserCookieLanguage != '' && UNGM.currentuserCookieLanguage != UNGM.defaultLanguage) {
            UNGM.setUserLanguage(UNGM.currentuserCookieLanguage);
        } else if (UNGM.currentuserCookieLanguage === '') {
            // If there isn't any cookie, set language according to the accept-language of the browser
            // but only if the browser accepts cookies
            if (!UNGM.cookiesEnabled()) {
                alert('You must activate cookies to use www.ungm.org properly.');
                return;
            }

            $.ajax({
                url: UNGM.siteRoot + 'Account/UserSettings/LanguageSuggestion',
                type: 'GET',
                success: UNGM.onGotLanguageSuggestion
            });
        }
    },
    onGotLanguageSuggestion: function (response) {
        if (response === "" || response === undefined) {
            return false;
        }

        $("<div>").attr("id", "languageSuggestionModal").html(response).dialog({
            modal: true,
            title: 'Language preferences',
            width: '66%',
            height: 200,
            hide: { effect: 'fade', duration: 100 },
            show: { effect: 'fade', duration: 100 },
            open: function () {
                $(".btnAcceptLanguageSuggestion").bind("click", UNGM.acceptLanguageSuggestionClicked);
                $(".btnCancelLanguageSuggestion").bind("click", UNGM.cancelLanguageSuggestionClicked);
                $("#englishMessage").bind("click", UNGM.englishMessageClicked);
            }
        });
    },
    acceptLanguageSuggestionClicked: function (evt) {
        UNGM.throbOver($('body'));
        var sender = $(evt.currentTarget);
        var preferredLanguage = sender.attr("userLanguage");
        UNGM.setUserLanguage(preferredLanguage);
        $("#languageSuggestionModal").dialog("close");
    },
    cancelLanguageSuggestionClicked: function () {
        $("#languageSuggestionModal").dialog("close");
    },
    englishMessageClicked: function () {
        $(".suggestionMsg, .enMsg").toggle();
        $(".englishMessage").hide();
    },
    languageSelectClicked: function (evt) {
        var sender = $(evt.target);
        var preferredLanguage = sender.data("language");

        if (preferredLanguage) {
            UNGM.throbOver($('body'));
            // Change dropdown list of user settings if it's visible
            if ($("#PreferredLanguage").length) {
                $("#PreferredLanguage").val(preferredLanguage);
            }

            UNGM.setUserLanguage(preferredLanguage);
        }
    },
    initFilters: function () {
        $(".expandFilter").off("click").on("click", UNGM.toggleAdvancedFilter);
        $(".expandAllFilter").off("click").on("click", UNGM.toggleAllFilter);
    },
    toggleAdvancedFilter: function (evt) {
        var sender = $(evt.currentTarget);
        var filter = sender.parents(".filter:first").find(".filterAdvanced");
        if (filter.is(":visible")) {
            filter.hide('fast');
            sender.attr("value", sender.data("invisibletext"));
        }
        else {
            filter.show('fast');
            sender.attr("value", sender.data("visibletext"));
        }
    },
    toggleAllFilter: function (evt) {
        var sender = $(evt.currentTarget);
        var filter = sender.parents(".filter:first").find(".filterAll");
        if (filter.is(":visible")) {
            filter.hide('fast');
            sender.attr("value", sender.data("invisibletext"));
        }
        else {
            filter.show('fast');
            sender.attr("value", sender.data("visibletext"));
        }
    },
    openMenu: function () {
        if (UNGM.isRtl) {
            $("#top").animate({
                right: "250px"
            }, { duration: 300, queue: false });
            $("#main").animate({
                right: "250px"
            }, { duration: 300, queue: false });
        } else {
            $("#top").animate({
                left: "250px"
            }, { duration: 300, queue: false });
            $("#main").animate({
                left: "250px"
            }, { duration: 300, queue: false });
        }
    },
    closeMenu: function () {
        if (UNGM.isRtl) {
            $("#top").animate({
                right: "0px"
            }, { duration: 180, queue: false });
            $("#main").animate({
                right: "0px"
            }, { duration: 180, queue: false });
        } else {
            $("#top").animate({
                left: "0px"
            }, { duration: 180, queue: false });
            $("#main").animate({
                left: "0px"
            }, { duration: 180, queue: false });
        }
    },
    openOrCloseNavigation: function (e) {
        e.preventDefault();
        var leftval = $("#main").css('left');

        if (leftval == "0px") {
            UNGM.openMenu();
        }
        else {
            UNGM.closeMenu();
        }
    },
    updateInboxCount: function () {
        if (UNGM.isAuthenticated === false) {
            return;
        }

        $.ajax({
            url: "/Account/Inbox/Count",
            type: 'GET',
            contentType: 'application/json',
            success: function (count) {
                if (count && count > 0) {
                    $("#inbox-count").css('visibility', 'visible').html(count);
                }
                else {
                    $("#inbox-count").css('visibility', 'hidden');
                }
            }
        });
    },
    updateUngmNumber: function () {
        if (UNGM.isVendor === false) {
            return;
        }

        if (UNGM.ungmNumber === null) {
            $.ajax({
                url: '/Account/Account/MyUngmNumber',
                cache: true,
                success: function (ungmNumber) {
                    UNGM.ungmNumber = ungmNumber;
                    $("#ungm-number-top-bar").html(UNGM.ungmNumber);
                }
            });
        }
    },
    getQueryStringParam: function (name) {
        var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
        return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
    },
    markRequiredFields: function () {
        $("form input[type='datetime'], input[type='text'], input[type='password'], select, textarea").each(function () {
            if ($(this).data("val-required")) {
                try {
                    var label = $(this).siblings("label");
                    if (label.html().indexOf("*") < 0) {
                        label.html(label.html() + "<span aria-hidden=\"true\">&nbsp*</span>");
                        $(this).attr("aria-required", true);
                    }
                }
                catch (ex) { }
            }
            else if ($(this).data("val-requiredif")) {
                try {
                    var dependentPropertyName = $(this).data("val-requiredif-propertyname");
                    var desiredValue = $(this).data("val-requiredif-desiredvalue");
                    var dependentProperty = $("[name=" + dependentPropertyName + "]");

                    var label = $(this).siblings("label");
                    if (dependentProperty.val() == desiredValue) {
                        if (label.html().indexOf("*") < 0) {
                            label.html(label.html() + "<span aria-hidden=\"true\">&nbsp*</span>");
                            $(this).attr("aria-required", true);
                        }
                    }
                }
                catch (ex) { }
            }
        });

        $("form input.DocumentId").each(function () {
            if ($(this).data("val-required")) {
                var name = $(this).attr("name");
                var label = $("label[for=" + name + "]");
                if (label.html().indexOf("*") < 0) {
                    label.html(label.html() + "<span aria-hidden=\"true\">&nbsp*</span>");
                    $(this).attr("aria-required", true);
                }
            }
        });

        $('.radio-button-list .radio-button-list-item input[type="radio"][data-val-required]').each(function () {
            var input = $(this);
            var label = input.closest('.radio-button-list').prev('label');
            if (label.html() && (label.html().indexOf('*') === -1)) {
                label.html(label.html() + '<span aria-hidden=\"true\">&nbsp*</span>');
                input.attr("aria-required", true);
            }
        });
    },
    markAsRequiredFields: function (elements) {
        $(elements).each(function () {
            try {
                var label = $(this).siblings("label");
                if (label.html().indexOf("*") < 0) {
                    label.html(label.html() + "<span aria-hidden=\"true\">&nbsp*</span>");
                    $(this).attr("aria-required", true);
                }
            }
            catch (ex) { }
        });
    },
    serializeIncludingDisabled: function (element) {
        // Find disabled inputs, and remove the "disabled" attribute
        var disabled = element.find(':input:disabled').removeAttr('disabled');

        // serialize the form
        var serialized = element.serialize();

        // re-disabled the set of inputs that you previously enabled
        disabled.attr('disabled', 'disabled');

        return serialized;
    },
    ieHackTableHeader: function () {
        // IE7 hack to convert display:table to a table
        if (UNGM.browsingWithInternetExplorer7()) {
            $(".tableCell").wrap("<td style='padding:0px;' />");
            $(".tableRow").wrap("<tr />");
            $(".tableHead").wrap("<thead />");
            $(".tableBody").wrap("<tbody />");
            $(".table").wrapInner("<table style='width:100%' />");
            $(".tableCell.header").css("width", "100%");
            $(".tableCell.header").css("padding-left", "0px");
            $(".tableCell.header").css("padding-right", "0px");
        }
    },
    ieHackTableCells: function () {
        // IE7 hack to convert display:table to a table
        if (UNGM.browsingWithInternetExplorer7()) {
            $(".tableCell:not(.header):not(.done)").wrap("<td style='padding:0px; margin:0px;' />").addClass("done");
            $(".tableRow:not(.done)").wrap("<tr style='padding:0px; margin:0px; border:0px' />").addClass("done");
            $(".tableCell:not(.header)").css("border", "0px");
        }
    },
    initCollapsables: function () {
        $("fieldset legend.expandable").off("click").on("click", function (evt) {
            var sender = $(evt.currentTarget);
            var parent = sender.parent();
            if (parent.hasClass('collapsed')) {
                parent.removeClass('collapsed');
                sender.addClass('expanded');
            }
            else {
                parent.addClass('collapsed');
                sender.removeClass('expanded');
            }
        });
    },
    onRemoveSuggestAssistedRegistrationClicked: function (evt) {
        var sender = $(evt.currentTarget);
        var parent = sender.closest("#lnkAssistedRegistration");
        parent.remove();
    },
    initJQueryUIDialogWithCKEDITOR: function () {
        //
        // There is an issue with jquery ui working with ckeditor.
        // This part of code is needed as a workaround.
        //
        // For more information: see http://bugs.jqueryui.com/ticket/9087#comment:30
        //
        $.widget("ui.dialog", $.ui.dialog, {
            /*! jQuery UI - v1.10.2 - 2013-12-12
             *  http://bugs.jqueryui.com/ticket/9087#comment:27 - bugfix
             *  http://bugs.jqueryui.com/ticket/4727#comment:23 - bugfix
             *  allowInteraction fix to accommodate windowed editors
             */
            _allowInteraction: function (event) {
                if (this._super(event)) {
                    return true;
                }
                // address interaction issues with general iframes with the dialog
                if (event.target.ownerDocument != this.document[0]) {
                    return true;
                }
                // address interaction issues with dialog window
                if ($(event.target).closest(".cke_dialog").length) {
                    return true;
                }
                // address interaction issues with iframe based drop downs in IE
                if ($(event.target).closest(".cke").length) {
                    return true;
                }
            },
            /*! jQuery UI - v1.10.2 - 2013-10-28
             *  http://dev.ckeditor.com/ticket/10269 - bugfix
             *  moveToTop fix to accommodate windowed editors
             */
            _moveToTop: function (event, silent) {
                if (!event || !this.options.modal) {
                    this._super(event, silent);
                }
            }
        });
    },
    browsingWithInternetExplorer7: function () {
        var BrowserDetect = {
            init: function () {
                this.browser = this.searchString(this.dataBrowser) || "Other";
                this.version = this.searchVersion(navigator.userAgent) || this.searchVersion(navigator.appVersion) || "Unknown";
            },
            searchString: function (data) {
                for (var i = 0; i < data.length; i++) {
                    var dataString = data[i].string;
                    this.versionSearchString = data[i].subString;

                    if (dataString.indexOf(data[i].subString) !== -1) {
                        return data[i].identity;
                    }
                }
            },
            searchVersion: function (dataString) {
                var index = dataString.indexOf(this.versionSearchString);
                if (index === -1) {
                    return;
                }

                var rv = dataString.indexOf("rv:");
                if (this.versionSearchString === "Trident" && rv !== -1) {
                    return parseFloat(dataString.substring(rv + 3));
                } else {
                    return parseFloat(dataString.substring(index + this.versionSearchString.length + 1));
                }
            },
            dataBrowser: [
                { string: navigator.userAgent, subString: "Edge", identity: "MS Edge" },
                { string: navigator.userAgent, subString: "MSIE", identity: "Explorer" },
                { string: navigator.userAgent, subString: "Trident", identity: "Explorer" },
                { string: navigator.userAgent, subString: "Firefox", identity: "Firefox" },
                { string: navigator.userAgent, subString: "Opera", identity: "Opera" },
                { string: navigator.userAgent, subString: "OPR", identity: "Opera" },
                { string: navigator.userAgent, subString: "Chrome", identity: "Chrome" },
                { string: navigator.userAgent, subString: "Safari", identity: "Safari" }
            ]
        };
        BrowserDetect.init();
        return BrowserDetect.browser == "Explorer" && BrowserDetect.version == 7;
    },
    markTabComplete: function (elementSelector, complete) {
        var element = $(elementSelector);
        if (element.length === 0) {
            return false;
        }
        element.removeClass("tabComplete tabIncomplete");
        complete ? element.addClass("tabComplete") : element.addClass("tabIncomplete");
        return true;
    },
    appendErrorTo: function (element, response) {
        if (element.length) {
            element.append("<div class='error'>" + response.Message + "</div>");
        }
    },
    removeError: function () {
        $("div.error").remove();
    }
};

$.extend({
    confirm: function (title, message, yesText, noText, yesCallback, width) {
        var btns = new Array();

        if (yesText.length != 0) {
            btns.push({
                text: yesText,
                id: "btnDialogOK",
                click: function () {
                    yesCallback();
                    $(this).dialog('close');
                }
            });
        }
        if (noText.length != 0) {
            btns.push({
                text: noText,
                id: "btnDialogNo",
                click: function () {
                    $(this).dialog('close');
                }
            });
        }
        if (width == 0 || width == undefined) {
            width = 500;
        }
        $("<div id='errorPopup'></div>").dialog({
            buttons: btns,
            minWidth: width,
            minHeight: 160,
            close: function (event, ui) { $(this).remove(); },
            resizable: false,
            title: title,
            modal: true
        }).html(message).parent().addClass("alert");
    }
});

$.extend({
    confirmWithNoCallback: function (title, message, yesText, noText, yesCallback, noCallback, width) {
        var btns = new Array();

        if (yesText.length != 0) {
            btns.push({
                text: yesText,
                id: "btnDialogOK",
                click: function () {
                    yesCallback();
                    $(this).dialog('close');
                }
            });
        }
        if (noText.length != 0) {
            btns.push({
                text: noText,
                id: "btnDialogNo",
                click: function () {
                    noCallback();
                    $(this).dialog('close');
                }
            });
        }
        if (width == 0 || width == undefined) {
            width = 500;
        }
        $("<div id='errorPopup'></div>").dialog({
            buttons: btns,
            minWidth: width,
            minHeight: 160,
            close: function (event, ui) { $(this).remove(); },
            resizable: false,
            title: title,
            modal: true
        }).html(message).parent().addClass("alert");
    }
});

$(document).ready(function () {
    if (!UNGM.initialised) {
        UNGM.init();
    }
    if (jQuery && jQuery.validator) {
        jQuery.validator.setDefaults({
            ignore: ""
        }); // In the library the default for this is :hidden. We still want to validate hidden inputs for, e.g., the country selector so don't ignore anything.
    }
});

;
window.UNGM.Validation = {
    init: function () {
        $(".formRow").on("focusin", "input", UNGM.Validation.elementGotFocus);
        $(".formRow").on("focusout", "input", UNGM.Validation.elementLostFocus);
        $(".formRow").on("focusin", "select", UNGM.Validation.elementGotFocus);
        $(".formRow").on("focusout", "select", UNGM.Validation.elementLostFocus);
        $(".formRow").on("focusin", "textarea", UNGM.Validation.elementGotFocus);
        $(".formRow").on("focusout", "textarea", UNGM.Validation.elementLostFocus);
        
        $(".emailValidated").bind("focusout", UNGM.Validation.validateEmail);

        if ($.validator) {
            $.validator.unobtrusive.adapters.addBool("PasswordStrengthValidation");
            $.validator.addMethod("PasswordStrengthValidation", function (value, element, param) {
                var strength = UNGM.ManageAccount.getPasswordStrength(value);
                if (strength > 1) {
                    return true;
                }
                else {
                    return false;
                }
            });

            $.validator.unobtrusive.adapters.addBool("bodyText");
            $.validator.addMethod("bodyText", function (value, element) {
                // We need 2 forms of validation. First time around we need to check if the CKEditors are active
                if (CKEDITOR.instances.txtEnglishBody) {
                    for (var instanceName in CKEDITOR.instances) {
                        var theText = CKEDITOR.instances[instanceName].getData();
                        if (theText.length > 0) {
                            // If the body has text, the corresponding subject must also have text
                            var subject = $(CKEDITOR.instances[instanceName].element.$).parents(".tab:first").find("input.subjectText");
                            if (subject.val().length > 0) {
                                return true;
                            }
                        }
                    }
                }
                else {
                    // If the CKEditors aren't there then that means we have destroyed them (to fill the underlying textarea for POST) but the
                    // EditableList plugin will validate the form again so we need to return the right value here
                    var isValid = false;
                    $("textarea.bodyText").each(function () {
                        if ($(this).val().length > 0) {
                            // If the body has text, the corresponding subject must also have text
                            var subject = $(this).parents(".tab:first").find("input.subjectText");
                            if (subject.val().length > 0) {
                                // Just returning true directly will only exist the .each loop and not the validator function
                                isValid = true;
                            }
                        }
                    });

                    return isValid;
                }

                return false;

            }, "");

            $.validator.unobtrusive.adapters.addBool("DateFormatValidation");
            $.validator.addMethod("DateFormatValidation", function (value, element, param) {
                var expression = UNGM.Validation.dateFormatValidationRegEx(false);

                // Hack for Spanish March which has MS bug UNGMVRR-4717
                var culture = $('html').attr('lang');
                if (culture == "es" && value.toLowerCase().indexOf("-mar-") >= 0) {
                    value = value.replace("-mar-", "-marzo-");
                }

                if (value.trim().length == 0 || value.match(expression)) {
                    return true;
                }
                else {
                    return false;
                }
            });

            $.validator.unobtrusive.adapters.addBool("DateTimeFormatValidation");
            $.validator.addMethod("DateTimeFormatValidation", function (value, element, param) {
                var expression = UNGM.Validation.dateFormatValidationRegEx(true);

                // Hack for Spanish March which has MS bug UNGMVRR-4717
                var culture = $('html').attr('lang');
                if (culture == "es" && value.toLowerCase().indexOf("-mar-") >= 0) {
                    value = value.replace("-mar-", "-marzo-");
                }

                if (value.length == 0 || value.match(expression)) {
                    return true;
                }
                else {
                    return false;
                }
            });
            // START OF MY NEW DATE STUFF
            $.validator.addMethod('dateafter', function (value, element, param) {
                var dateVal = $("#" + element.id).datepicker("getDate");
                var minDate;
                var pastDateAllow = false;

                if (value.length < 1 && param.nullable)
                    return true;

                if (param.minSelector.length > 0) {
                    var minDateElement = $("#" + param.minSelector);
                    minDate = minDateElement.datepicker("getDate");
                }
                else {
                    var now = new Date();
                    minDate = new Date(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), 0, 0, 0);
                }

                if (param.afterDateAllow.length > 0 && param.afterDateAllow.toLowerCase() == "true") {
                    var statusId = parseInt($("#Status").val());
                    if (statusId == param.afterDateAllowStatus) { // allow edit statusId pass from attribute
                        // get original date
                        var savedDate = new Date($(element).siblings("#SavedDate").val());
                        // if original date is not change, allow to edit.
                        if (Date.parse(dateVal) == Date.parse(savedDate)) {
                            pastDateAllow = true;
                        }
                    }
                }

                return minDate <= dateVal || minDate == null || pastDateAllow;
            });

            $.validator.addMethod('datebefore', function (value, element, param) {
                var dateVal = $("#" + element.id).datepicker("getDate");
                var maxDate;
                if (value.length < 1 && param.nullable)
                    return true;

                if (param.maxSelector.length > 0) {
                    var maxDateElement = $("#" + param.maxSelector);
                    maxDate = maxDateElement.datepicker("getDate");
                }
                else {
                    maxDate = new Date();
                    maxDate.setHours(23, 59, 59, 999);
                }

                return maxDate >= dateVal || maxDate == null;
            });

            // The adapter to support ASP.NET MVC unobtrusive validation
            $.validator.unobtrusive.adapters.add('dateafter', ['afterdatefield', 'nullable', 'allowdateafter', 'allowdateafterstatus'],
                function (options) {
                    var params = {
                        minSelector: options.params.afterdatefield,
                        nullable: options.params.nullable == "true",
                        afterDateAllow: options.params.allowdateafter,
                        afterDateAllowStatus: options.params.allowdateafterstatus
                    };

                    options.rules['dateafter'] = params;
                    if (options.message) {
                        options.messages['dateafter'] = options.message;
                    }
                });
            $.validator.unobtrusive.adapters.add('datebefore', ['beforedatefield', 'nullable'],
                function (options) {
                    var params = {
                        maxSelector: options.params.beforedatefield,
                        nullable: options.params.nullable == "true"
                    };

                    options.rules['datebefore'] = params;
                    if (options.message) {
                        options.messages['datebefore'] = options.message;
                    }
                });

            $.validator.unobtrusive.adapters.addBool("requiredif");
            $.validator.addMethod("requiredif", function (value, element, param) {
                if ($("#" + element.id).is(':radio')) {
                    value = $("[name='" + element.name + "']:checked").val();
                }

                var dependentEl = $("#" + element.id).data("val-requiredif-propertyname");
                var desiredValue = $("#" + element.id).data("val-requiredif-desiredvalue");
                // If desiredValue is a collection, it is sent as a string containing all the values separated by a comma
                var desiredValues = desiredValue != undefined ? desiredValue.split(",") : desiredValue;
                if (desiredValues != undefined && desiredValues.length) {
                    for (var i = 0; i < desiredValues.length; i++) {
                        desiredValues[i] = desiredValues[i].toLowerCase().trim();
                    }
                }

                var dependentElValue;
                if ($("[name='" + dependentEl + "']").is(':radio')) {
                    dependentElValue = $("[name='" + dependentEl + "']:checked").val();
                } else {
                    dependentElValue = $("[name='" + dependentEl + "']").val();
                }

                if (dependentElValue != undefined) {
                    dependentElValue = dependentElValue.toLowerCase();
                }

                if ($.inArray(dependentElValue, desiredValues) > -1 && (value === undefined || value == "")) {
                    return false;
                }
                else {
                    return true;
                }
            });
        }
        // END OF MY NEW DATE STUFF
    },
    initForElement: function (element) {
        element.find(".formRow input, .formRow select, .formRow textarea").each(function () {
            $(this).bind("focusin", UNGM.Validation.elementGotFocus);
            $(this).bind("focusout", UNGM.Validation.elementLostFocus);
        });
        if ($.validator) { $.validator.unobtrusive.parse(element); }
    },
    elementGotFocus: function (evt) {
        var sender = $(evt.currentTarget);
        sender.parents(".formRow").addClass('focus');
        sender.siblings(".field-validation-error").hide();
        sender.siblings(".validationIcon").hide();
        sender.siblings(".validationHint").css("visibility", "visible").css("display", "block");
        $(".validation-summary-errors").remove();
    },
    elementLostFocus: function (evt) {
        var sender = $(evt.currentTarget);
        sender.parents(".formRow").removeClass('focus');
        sender.siblings(".validationHint").css("visibility", "hidden");
        UNGM.Validation.validateElement(sender);

        // Add validation to country autocompletes
        if (sender.hasClass("ui-autocomplete-input")) {
            var countryList = sender.siblings(".countryPicker,.countryTelephonePicker");
            if (countryList.length) {
                UNGM.Validation.validateElement(countryList);
            }
        }
        
        // Add country and fiscal code unique validation on account/vendor regisration
        if (sender.siblings(".duplicateOfCountryAndFiscalCode").length > 0) {
            if (sender.siblings(".duplicateOfCountryAndFiscalCode").is(":visible")) {
                UNGM.Validation.markElementInvalid(countryList);
            }
            else {
                UNGM.Validation.validateElement(countryList);
            }
        }
    },
    validateEmail: function (evt) {
        var sender = $(evt.currentTarget);
    },
    validateElement: function (element) {
        try {
            if (element.valid()) {
                UNGM.Validation.markElementValid(element);
            }
            else {
                UNGM.Validation.markElementInvalid(element);
            }
        }
        catch (ex) { }
    },
    markElementValid: function (element) {
        var exists = element.siblings(".validationIcon.valid");
        if (exists.length > 0) {
            exists.show();
        }
        else {
            var elem = $("<span class='validationIcon valid' />");
            element.after(elem);
        }
        element.siblings(".validationIcon.invalid").hide();
        element.siblings(".field-validation-error").hide();
        //element.siblings(".validationHint").css("visibility", "visible");
    },
    markElementInvalid: function (element) {
        var exists = element.siblings(".validationIcon.invalid");
        if (exists.length > 0) {
            exists.show();
        }
        else {
            var elem = $("<span class='validationIcon invalid' />");
            element.after(elem);
        }
        element.siblings(".validationIcon.valid").hide();
        element.siblings(".field-validation-error").css('visibility', 'visible').css("display", "block");
        element.siblings(".validationHint").css("visibility", "hidden");
    },
    dateFormatValidationRegEx: function (isDateTime) {
        var culture = $('html').attr('lang');
        var languageCode = UNGM.Validation.getLanguageCode(culture);

        var months = $.datepicker.regional[languageCode].monthNamesShort.join("|");
        var time = (isDateTime ? "\\s([01]?[0-9]|2[0-3]):[0-5][0-9]" : "");

        var str = culture === "zh"
            ? "^\\d{4}\-(" + months + ")\-(([0-2][0-9])|([3][0-1]))" + time + "$"
            : culture === "ru"
            ? "^(([0-2][0-9])|([3][0-1]))\.(0?[1-9]|1[012])\.\\d{4}" + time + "$"
            : culture === "ar"
            ? "^(([0-2][0-9])|([3][0-1]))\-([1-9]|1[012])\-\\d{4}" + time + "$"
            : "^(([0-2][0-9])|([3][0-1]))\-(" + months + ")\-\\d{4}" + time + "$";
        return new RegExp(str, "i");
    },
    getLanguageCode: function (culture) {
        var defaultLanguageCode = "en";
        var languageCodes = {
            "en": "en",
            "fr": "fr",
            "es": "es",
            "pt": "pt",
            "zh": "zh-CN",
            "ru": "ru",
            "ar": "ar"
        };
        return languageCodes[culture] || defaultLanguageCode;
    }
}

$(document).ready(function () {
    UNGM.Validation.init();
});


$(".dateField").datepicker();
UNGM.ManageAccount = {
    init: function () {
        $("#change-email-form").off("submit").on("submit", UNGM.ManageAccount.onChangeEmailClicked);
        $("#NewEmail").off("focus").on("focus", UNGM.ManageAccount.onEmailGotFocus);
        $("#NewPassword").off("keyup").on("keyup", UNGM.ManageAccount.onPasswordKeyUp);
    },
    onEmailGotFocus:function(){
        $('#UNGMEmailValidation').html('');
    },
    onChangeEmailClicked: function (evt) {
        //get the form
        evt.preventDefault();
        var form = $(evt.target);
        if (form.valid()) {
            UNGM.throbOver($("#changeEmailPartial"));
            var formData = { newEmail: unescape($("#NewEmail").val()) };
            $.ajax({
                url: UNGM.siteRoot + 'Account/Account/ChangeEmail',
                type: 'POST',
                contentType: 'application/json',
                data: JSON.stringify(formData),
                success: UNGM.ManageAccount.onEmailChangeRequestSubmitted,
                traditional: true
            });
        }
    },
    onEmailChangeRequestSubmitted: function (data) {
        if(data == 'success'){
            // Success, show success message
            $('#UNGMEmailValidation').html('');
            $.confirm(
                UNGM.ManageAccount.ChangeEmailConfirmedTitle, // Title
                UNGM.ManageAccount.ChangeEmailConfirmedMessage, // Message
                UNGM.ManageAccount.ChangeEmailConfirmedOK, //yes button text (blank hides button)
                "", //no button text (blank hides button)
                function () { } //"yes" callback
            );
            // clear the input field
            $("#NewEmail").val("");
        }
        else {
            // failure, show the validation error
            $('#UNGMEmailValidation').html("<span class='validationIcon invalid' />" + data);
        }
        UNGM.hideThrobber();
    },
    getPasswordStrength: function (password) {
        var score = 0;
        var lowerCase = password.match(/[a-z]/g);
        var upperCase = password.match(/[A-Z]/g);
        var digits = password.match(/\d/g);
        var nonAlpha = password.match(/[^\w\s]/g);
        var whitespace = password.match(/\s/);

        if (upperCase && lowerCase) {
            score += 1;
        }

        if (digits) {
            score += 1;
        }

        if (nonAlpha) {
            score += 1;
        }

        if (whitespace) {
            score += 1;
        }

        var length = password.length;
        if (length >= 8) {
            score += 10;
        }

        var strength = 0;
        if (score >= 12) {
            strength = 4;
        } else if (score >= 11) {
            strength = 3;
        } else if (score >= 10) {
            strength = 2;
        }

        return strength;
    },
    onPasswordKeyUp: function (evt) {
        classes= ['pw-very-weak', 'pw-weak', 'pw-mediocre', 'pw-strong', 'pw-very-strong'];
        texts = [UNGM.PasswordVeryWeak, UNGM.PasswordWeak, UNGM.PasswordMediocre, UNGM.PasswordStrong, UNGM.PasswordVeryStrong];
        var sender = $(evt.currentTarget);

        var strength = UNGM.ManageAccount.getPasswordStrength(sender.val());

        var strengthClass = classes[strength];
        var indicator = $('#' + sender.data('indicator'));
        indicator.removeClass(indicator.data('pwclass'));
        indicator.data('pwclass', strengthClass);
        indicator.addClass(strengthClass);
        indicator.find('.label').html(texts[strength]);

        var ariaDescribedby = sender.attr("aria-describedby");
        if (ariaDescribedby.indexOf("pwindicator-info") === -1) {
            sender.attr("aria-describedby", ariaDescribedby + " pwindicator-info");
        }
    }
};;
window.UNGM.ContractAwardSearch = {
    pageIndex: 0,
    prevPageIndex: 0,
    paging: false,
    timeoutFunc: null,
    selectedCountries: [],
    selectedAgencies: [],
    selectedAgenciesReadonly: false,
    selectedUNSPSCs: [],
    selectedUNSPSCsReadonly: false,
    sortField: "AwardDate",
    sortAscending: false,
    inSearch: false,
    pendingSearchRequest: null,
    init: function (CountryPlaceholder) {
        $("#txtContractAwardFilterTitle").bind("keyup", UNGM.ContractAwardSearch.filterKeyUp);
        $("#txtContractAwardFilterDesc").bind("keyup", UNGM.ContractAwardSearch.filterKeyUp);
        $("#txtContractAwardFilterRef").bind("keyup", UNGM.ContractAwardSearch.filterKeyUp);
        $("#txtContractAwardFilterSupplier,#txtContractAwardFilterSupplierUngmNumber").bind("keyup", UNGM.ContractAwardSearch.filterKeyUp);
        $("#txtContractAwardFrom").bind("change", UNGM.ContractAwardSearch.filterDateChange);
        $("#txtContractAwardTo").bind("change", UNGM.ContractAwardSearch.filterDateChange);

        // Sorting except FirstCountry
        $("#tblContractAwards .tableHead .tableRow .tableCell").not(".notsortable").on("click", UNGM.ContractAwardSearch.sort);

        // Search Selectors
        $("#selContractAwardCountry").bind("change", UNGM.ContractAwardSearch.onContractAwardCountrySelect);
        $("#selContractAwardAgency").bind("change", UNGM.ContractAwardSearch.onContractAwardAgencySelect);
        $("#contractAwardFilter #lnkShowUNSPSC").on("click", function () { UNGM.ContractAwardSearch.showUNSPSC(); });
        $("#contractAwardFilter #lnkEditUNSPSC").on("click", function () { UNGM.ContractAwardSearch.editUNSPSC(); });
        $("#contractAwardFilter #lnkExpandUNSPSC").on("click", UNGM.ContractAwardSearch.expandUNSPSC);
        $("#contractAwardFilter #lnkCollapseUNSPSC").on("click", UNGM.ContractAwardSearch.collapseUNSPSC);
        $("#contractAwardFilter #lnkSearch").on("click", UNGM.ContractAwardSearch.searchButtonClicked);

        $("#isCountrySelected").on("change", UNGM.ContractAwardSearch.clearCountry);
        $("#isAgencySelected").on("change", UNGM.ContractAwardSearch.clearAgency);

        // Add place holder
        $("#selContractAwardCountry").attr("placeholder", CountryPlaceholder);

        // Clear All
        $("#contractAwardFilter #lnkClearAll").on("click", UNGM.ContractAwardSearch.clearAll);

        // Set height to show loading for first time
        var contractDiv = $("#contractAwards");
        contractDiv.css("height", 150 + "px");
        // Run search
        UNGM.ContractAwardSearch.search();
        // Set height back to auto
        contractDiv.css("height", "auto");

        UNGM.ieHackTableHeader();
    },
    clearAll: function () {
        $("#txtContractAwardFilterTitle").val('');
        $("#txtContractAwardFilterDesc").val('');
        $("#txtContractAwardFilterRef").val('');
        $("#txtContractAwardFilterSupplier,#txtContractAwardFilterSupplierUngmNumber").val('');
        $("#txtContractAwardFrom").val('');
        $("#txtContractAwardTo").val('');
        UNGM.ContractAwardSearch.selectedCountries = [];
        // Clear selected countries div
        $("#selContractAwardCountry option").eq(0).attr('selected', 'selected');
        $("#selContractAwardCountry").parent(".filterRow").find('.ui-autocomplete-input').val("");
        $("#contractAwardSearchCountry").children("div").remove();
        $("#contractAwardSearchCountry").hide();

        if (!UNGM.ContractAwardSearch.selectedAgenciesReadonly) {
            // Clear selected agencies
            UNGM.ContractAwardSearch.selectedAgencies = [];
            $("#selContractAwardAgency option").eq(0).attr('selected', 'selected');
            $("#selContractAwardAgency").parent(".filterRow").find('.ui-autocomplete-input').val("");
            $("#contractAwardSearchAgency").children("div").remove();
            $("#contractAwardSearchAgency").hide();
        }

        if (!UNGM.ContractAwardSearch.selectedUNSPSCsReadonly) {
            // Clear selected UNSPSCs
            UNGM.ContractAwardSearch.selectedUNSPSCs = [];
            $("#contractAwardFilter #lnkEditUNSPSC").hide();
            $("#contractAwardFilter #lnkShowUNSPSC").show();
        }
        // Clear contractAward type checkbox list
        $(".contractAwardTypeCheckboxList").removeAttr('checked');
        // Set pageing default
        UNGM.ContractAwardSearch.pageIndex = 0;
        UNGM.ContractAwardSearch.paging = false;
        UNGM.ContractAwardSearch.search();
    },
    //#endregion

    //#region Search Functions
    searchButtonClicked: function () {
        if (UNGM.ContractAwardSearch.timeoutFunc) {
            clearTimeout(UNGM.ContractAwardSearch.timeoutFunc);
        }
        UNGM.ContractAwardSearch.pageIndex = 0;
        UNGM.ContractAwardSearch.paging = false;
        $.waypoints('destroy');
        UNGM.ContractAwardSearch.timeoutFunc = setTimeout("UNGM.ContractAwardSearch.search();", 300);
    },
   buildOptions: function () {
        var opts =
        {
            PageIndex: UNGM.ContractAwardSearch.pageIndex,
            PageSize: 15,
            Title: $("#txtContractAwardFilterTitle").val(),
            Description: $("#txtContractAwardFilterDesc").val(),
            Reference: $('#txtContractAwardFilterRef').val(),
            Supplier: $('#txtContractAwardFilterSupplier').val(),
            UngmNumber: $('#txtContractAwardFilterSupplierUngmNumber').val(),
            AwardFrom: $("#txtContractAwardFrom").val(),
            AwardTo: $("#txtContractAwardTo").val(),
            Countries: UNGM.ContractAwardSearch.selectedCountries,
            Agencies: UNGM.ContractAwardSearch.selectedAgencies,
            UNSPSCs: UNGM.ContractAwardSearch.selectedUnspscs,
            SortField: UNGM.ContractAwardSearch.sortField,
            SortAscending: UNGM.ContractAwardSearch.sortAscending
        };
        return opts;
    },
    sort: function (evt) {
        var sender = $(evt.currentTarget);
        var newSortField = sender.attr('id');
        if (UNGM.ContractAwardSearch.sortField == newSortField) {
            // 2 clicks on the same column means swap order
            UNGM.ContractAwardSearch.sortAscending = !UNGM.ContractAwardSearch.sortAscending;
        }
        else {
            // First time column is clicked sorts ASC by default
            UNGM.ContractAwardSearch.sortField = newSortField;
            UNGM.ContractAwardSearch.sortAscending = true;
        }
        $("#tblContractAwards .sortedAsc").removeClass("sortedAsc");
        $("#tblContractAwards .sortedDesc").removeClass("sortedDesc");

        var newClass = UNGM.ContractAwardSearch.sortAscending ? "sortedAsc" : "sortedDesc";
        sender.addClass(newClass);

        UNGM.ContractAwardSearch.PageAndSearch();
    },
    search: function () {
        if (UNGM.ContractAwardSearch.pendingSearchRequest) {
            UNGM.ContractAwardSearch.pendingSearchRequest.abort();
        }
        var opts = UNGM.ContractAwardSearch.buildOptions();
        var url = "";
        if (document.getElementById("txtContractAwardFilterSupplier") === null) {
            url = 'Public/ContractAward/SearchByVendor';
        } else {
            url = 'Public/ContractAward/PublicSearch';
        }
         
        UNGM.throbOver("#contractAwards");
        UNGM.ContractAwardSearch.pendingSearchRequest = $.ajax({
            url: UNGM.siteRoot + url,
            type: 'POST',
            contentType: 'application/json',
            data: JSON.stringify(opts),
            success: UNGM.ContractAwardSearch.onGotData
        });
    },
    PageAndSearch: function () {
        UNGM.ContractAwardSearch.pageIndex = 0;
        UNGM.ContractAwardSearch.paging = false;
        UNGM.ContractAwardSearch.search();
    },
    onGotData: function (data) {
        UNGM.ContractAwardSearch.prevPageIndex = UNGM.ContractAwardSearch.pageIndex;
        data = $.trim(data);
        var dataArray = $(data).toArray();
        var returnRows = $(dataArray).filter(".dataRow").length;
        if (returnRows < 1) {
            if (UNGM.ContractAwardSearch.paging) {
                UNGM.ContractAwardSearch.paging = false;
            }
            else {
                $("#contractAwardsEmpty").show();
                $("#tblContractAwards").hide();
                $("#contractAwardsTotal").hide();
            }
        }
        else {
            $("#tblContractAwards .tableBody").children("script").remove();
            if (UNGM.ContractAwardSearch.paging) {
                $("#tblContractAwards .tableBody").append(data);
                UNGM.ContractAwardSearch.paging = false;
            }
            else {
                $("#tblContractAwards .tableBody").html(data);
                $("#tblContractAwards").show();
                $("#contractAwardsTotal").show();
                $("#contractAwardsEmpty").hide();
            }
            var rows = $("#tblContractAwards").find(".tableRow").length - 1;
            $("#searchRows").html(rows);
            $("#contractAwardsTotal").show();
            $("#tblContractAwards").find(".tableBody .tableRow").off("click").on("click", UNGM.ContractAwardSearch.awardClicked);
            $("#tblContractAwards").find(".tableBody .tableRow").off("keypress").on("keypress", UNGM.ContractAwardSearch.awardClicked);

            var contractAwardContext = null;
            var contractAwardOffset = null;

            var contextHeight = $('#contractAwards').height();
            var tableHeight = $('#tblContractAwards').height();
            var marginForRounding = 3;
            if (contextHeight + marginForRounding < tableHeight) {
                contractAwardOffset = -(tableHeight - contextHeight);
                contractAwardContext = $('#contractAwards');
            } else {
                contractAwardOffset = 'bottom-in-view';
            }

            $('#tblContractAwards').waypoint(function (direction) {
                if (direction === 'down' && !UNGM.ContractAwardSearch.inSearch) {
                    $.waypoints('destroy');
                    UNGM.ContractAwardSearch.pageIndex = UNGM.ContractAwardSearch.prevPageIndex + 1;
                    UNGM.ContractAwardSearch.paging = true;
                    UNGM.ContractAwardSearch.inSearch = true;
                    UNGM.ContractAwardSearch.search();
                }
            }, {
                context: contractAwardContext,
                offset: contractAwardOffset
            });
            UNGM.ContractAwardSearch.inSearch = false;
        }
        // Trigger country hidden to clear value
        $("#isCountrySelected").trigger("change");
        // Trigger agency hidden to clear value
        $("#isAgencySelected").trigger("change");
        UNGM.ieHackTableCells();
        UNGM.hideThrobber();
    },
    awardClicked: function (evt) {
        if (!$(evt.target).is("svg *") && !$(evt.target).is("a *")) {
            UNGM.throbOver("#notices");
            var id = $(evt.currentTarget).data("contractawardid");
            var isPicker = ($("#IsPicker").val() == 'True' ? "?isPicker=true" : "");
            $.ajax({
                url: UNGM.siteRoot + 'Public/ContractAward/Popup/' + id + isPicker,
                type: 'GET',
                success: UNGM.ContractAwardSearch.onGotAwardDetail
            });
        }
    },
    onGotAwardDetail: function (detail) {
        UNGM.hideThrobber();
        var winHeight = $(window).height();
        var detailElem = $(detail);
        var title = detailElem.find("#awardTitle").html();
        $("#contractAwardDetail").dialog({
            modal: true,
            open: function () {
                $("#contractAwardDetail").empty().append(detailElem);
                $("#contractAwardDetail .pickAward").bind("click", UNGM.ContractAwardSearch.pickAwardClicked);
            },
            title: title,
            width: '66%',
            height: winHeight - (winHeight * 0.2),
            hide: { effect: 'fade', duration: 100 },
            show: { effect: 'fade', duration: 100 }
        });

    },
    //#endregion

    //#region UNSPSC Functions
    showUNSPSC: function () {
        var winHeight = $(window).height();
        $("#contractAwardUNSPSCSelector").dialog({
            modal: true,
            open: function () {
            },
            title: UNGM.ContractAwardSearch.UNSPSCTitle,
            open: function () {
                $(".unspsc-action-clear-selected").click();
            },
            width: '66%',
            height: winHeight - (winHeight * 0.2),
            hide: { effect: 'fade', duration: 100 },
            show: { effect: 'fade', duration: 100 }
        });
    },
    editUNSPSC: function () {
        var winHeight = $(window).height();
        $("#contractAwardUNSPSCSelector").dialog({
            modal: true,
            open: function () {
                setTimeout(function () {
                    $(".unspsc-action-filter-selected").click();
                }, 500);
            },
            title: UNGM.ContractAwardSearch.UNSPSCTitle,
            width: '66%',
            height: winHeight - (winHeight * 0.2),
            hide: { effect: 'fade', duration: 100 },
            show: { effect: 'fade', duration: 100 }
        });
    },
    expandUNSPSC: function () {
        $(".contractAwardSelectedUNSPSC").show();
        $("#lnkExpandUNSPSC").hide();
        $("#lnkCollapseUNSPSC").show();
    },
    collapseUNSPSC: function () {
        $(".contractAwardSelectedUNSPSC").hide();
        $("#lnkExpandUNSPSC").show();
        $("#lnkCollapseUNSPSC").hide();
    },
    unspscSaveCallback: function () {
        if (UNGM.ContractAwardSearch.selectedUnspscs.length > 0) {
            $("#contractAwardFilter #lnkShowUNSPSC").hide();
            $("#contractAwardFilter #lnkEditUNSPSC").show();
        }
        else {
            $("#contractAwardFilter #lnkEditUNSPSC").hide();
            $("#contractAwardFilter #lnkShowUNSPSC").show();
        }

        $("#contractAwardUNSPSCSelector").dialog('close');
        UNGM.ContractAwardSearch.pageIndex = 0;
        UNGM.ContractAwardSearch.paging = false;
        UNGM.ContractAwardSearch.search();
    },
    removeUNSPSCClicked: function (evt) {
        var removedId = $(evt.currentTarget).data("Id")
        UNGM.UNSPSC.removeCode(removedId);
        UNGM.ContractAwardSearch.removeItemClicked(UNGM.ContractAwardSearch.selectedUNSPSCs, removedId, ".contractAwardSelectedUNSPSC", "#contractAwardSearchUNSPSC")
    },
    //#endregion

    //#region Agency Functions
    onContractAwardAgencySelect: function (evt) {
        var sender = $(evt.currentTarget);
        var agencyId = parseInt(sender.val());
        if (sender.val() == '') {
            return;
        }
        var agencyName = sender.children(':selected').text();

        UNGM.ContractAwardSearch.onItemSelect(agencyId, agencyName, UNGM.ContractAwardSearch.selectedAgencies, "#contractAwardSearchAgency", 'contractAwardSelectedAgency', 'contractAwardSelectedAgencyName', UNGM.ContractAwardSearch.removeAgencyClicked);
        $("#isAgencySelected").val(1);
    },
    removeAgencyClicked: function (evt) {
        UNGM.ContractAwardSearch.removeItemClicked(UNGM.ContractAwardSearch.selectedAgencies, $(evt.currentTarget).data("Id"), ".contractAwardSelectedAgency", "#contractAwardSearchAgency")
    },
    clearAgency: function (evt) {
        UNGM.ContractAwardSearch.clearSelection(evt, "#selContractAwardAgency");
    },
    setSelectedAgenciesReadonly: function (agencies) {
        agencies = (agencies instanceof Array) ? agencies : [agencies];
        UNGM.ContractAwardSearch.selectedAgencies = agencies;
        UNGM.ContractAwardSearch.selectedAgenciesReadonly = true;
    },

    //#endregion

    //#region Country Functions
    onContractAwardCountrySelect: function (evt) {
        var sender = $(evt.currentTarget);
        var countryId = sender.val();
        if (countryId == '') {
            return;
        }
        var countryName = sender.children(':selected').text();
        var selectedCountry = {
            Id: countryId,
            Name: countryName
        };
        UNGM.ContractAwardSearch.onItemSelect(countryId, countryName, UNGM.ContractAwardSearch.selectedCountries, "#contractAwardSearchCountry", 'contractAwardSelectedCountry', 'contractAwardSelectedCountryName', UNGM.ContractAwardSearch.removeCountryClicked);
        $("#isCountrySelected").val(1);
    },
    removeCountryClicked: function (evt) {
        UNGM.ContractAwardSearch.removeItemClicked(UNGM.ContractAwardSearch.selectedCountries, $(evt.currentTarget).data("Id"), ".contractAwardSelectedCountry", "#contractAwardSearchCountry")
    },
    clearCountry: function (evt) {
        UNGM.ContractAwardSearch.clearSelection(evt, "#selContractAwardCountry");
    },
    setSelectedUNSPSCsReadonly: function (unspscs) {
        unspscs = (unspscs instanceof Array) ? unspscs : [unspscs];
        unspscs.forEach(function (unspsc) {
            UNGM.ContractAwardSearch.selectedUNSPSCs.push(unspsc.Id);
            UNGM.ContractAwardSearch.addItemToPlaceHolder(unspsc.Id, unspsc.Name, unspsc.Code, "#contractAwardSearchUNSPSC", "contractAwardSelectedUNSPSC", "contractAwardSelectedUNSPSC");
        });
        UNGM.ContractAwardSearch.selectedUNSPSCsReadonly = true;
        $(".contractAwardSelectedUNSPSC").hide();
    },
    //#endregion

    //#region Helper Functions
    onItemSelect: function (itemId, itemName, storedItemArray, holderClassName, selectedIdDiv, selectedNameSpan, removeCallback ) {
        // Do nothing if agency already in list
        if ($.grep(storedItemArray, function (value) { return value == itemId; }).length > 0) { return; };
        // Add selected agency to the array
        storedItemArray.push(itemId);
        //Add selected agency to place holder
        UNGM.ContractAwardSearch.addItemToPlaceHolder(itemId, itemName, null, holderClassName, selectedIdDiv, selectedNameSpan, removeCallback);

        if (storedItemArray.length > 0) {
            $(holderClassName).show();
        }
        else {
            $(holderClassName).hide();
        }
        // Set pageing default
        UNGM.ContractAwardSearch.PageAndSearch();
    },
    addItemToPlaceHolder: function (itemId, itemName, itemCode, holderClassName, selectedIdDiv, selectedNameSpan, removeCallback) {
        var holder = $(holderClassName);
        var elem = $("<div class='" + selectedIdDiv + "'></div>");
        elem.data("ID", itemId);
        var span = $("<span class='" + selectedNameSpan + "'></span>");
        span.html((itemCode !== null ? itemCode + " - " : "") + itemName);
        elem.append(span);
        if (removeCallback !== undefined) {
            var removeButton = $("#removeButtonTemplate").clone();
            removeButton.removeAttr("id").show();
            removeButton.data("Id", itemId);
            removeButton.bind("click", removeCallback);
            removeButton.text(removeButton.text() + " " + (itemCode !== null ? itemCode + " - " : "") + itemName);
            elem.append(removeButton);
        }
        holder.append(elem);
    },
    removeItemClicked: function (removedArray, removedId, selectedItemDivClass, SelectedItemsDivId) {
        removedArray.splice($.inArray(removedId, removedArray), 1);
        // Remove selected agency div from place holder
        $(selectedItemDivClass).filter(function () { return $(this).data("ID") == removedId }).remove();
        //hide selected UNSPSC div when all are removed.
        if (removedArray.length == 0) {
            $(SelectedItemsDivId).hide();
        }
        // Set pageing default
        UNGM.ContractAwardSearch.PageAndSearch()
    },
    clearSelection: function (evt, divToClear) {
        var change = $(evt.currentTarget).val();
        if (change == 1) {
            $(divToClear).parent(".filterRow").find('.ui-autocomplete-input').val("");
            $(this).val("0");
        }
    },
    setResultTableMaxHeight: function (height) {
        var contractAwards = $("#contractAwards");
        contractAwards.css("max-height", height);
        contractAwards.css("overflow", "auto");
    }
    //#endregion
}
;
(function ($) {
    var methods = {
        init: function (options) {

            if (!options.listUrl || !options.getEditUrl || !options.getInsertUrl || !options.postEditUrl || !options.postInsertUrl || !options.deleteUrl) {
                throw ("Invalid options for editableList plugin. See UNGM.EditableList.js for the minimum required set of options that must be supplied.");
            }

            settings = options;

            elements.container = this.eq(0);
            // save setting in container data
            elements.container.data("settings", settings);
            var addButton;

            if (elements.container.find(".addanother").length > 0) {
                addButton = elements.container.find(".addanother");
            }
            else {
                addButton = $("<input type='button' value ='"+ UNGM.editableListAddText +" "+ settings.entityName + "' class='addanother' />");
            }
            addButton.unbind("click.editableList").bind("click.editableList", methods.addAnother);
            elements.container.append(addButton);

            if (!settings.isReadonly
                && (settings.maxItems == null || (settings.maxItems != null && settings.maxItems > elements.container.find(".editableListItem").length))) {
                elements.container.find(".addanother").show();
                elements.container.find(".addanother").unbind("click.editableList").bind("click.editableList", methods.addAnother);
            }
            else {
                elements.container.find(".addanother").hide();
                elements.container.find(".addanother").unbind("click.editableList", methods.addAnother);
            }
            elements.listContainer = elements.container.find(".listContainer");
            methods.bindOptions(elements.listContainer);

            if (settings.itemClickedCallback) {
                elements.listContainer.find(".editableListItem").addClass("clickableListItem").unbind("click", methods.itemClicked).bind("click", methods.itemClicked);
            }
        },
        addAnother: function (evt) {
            var maincontainer = $(evt.currentTarget).parent("div");
            if (maincontainer.length > 0) {
                settings = maincontainer.data("settings");
            }
            UNGM.throbOver(elements.container);
            $.ajax({
                type: 'GET',
                url: settings.getInsertUrl,
                success: function (data) {
                    var newForm = $(data);
                    elements.contextForm = newForm;
                    elements.contextForm.find("form").attr("action", settings.postInsertUrl);
                    elements.contextForm.find("input[type='submit']").bind("click", methods.submitForm);
                    elements.contextForm.find("input[type='datetime']").datepicker({
                        onSelect: function (dateText, inst) {
                            UNGM.Validation.validateElement($(this));
                        },
                        changeYear: true,
                        changeMonth: true
                    });
                    UNGM.Validation.initForElement(elements.contextForm);
                    var modal = $("<div>").dialog({
                        modal: true,
                        title: UNGM.editableListAddDialogTitle,
                        width: '80%',
                        height: settings.dialogHeight,
                        hide: { effect: 'fade', duration: 100 },
                        show: { effect: 'fade', duration: 100 },
                        close: function () { elements.contextForm.parent().remove(); }


                    }).append(elements.contextForm);

                    if (!settings.dialogHeight) {
                        modal.dialog('option', 'height', elements.contextForm.outerHeight());
                    }

                    UNGM.hideThrobber();
                    UNGM.initTabsIn(elements.contextForm);
                    elements.contextForm.find(".validationIcon").hide();
                    elements.contextForm.find(".field-validation-error").hide();
                }
            });
        },
        submitForm: function (evt) {
            var form = $(evt.currentTarget).parents('form');
            var actionUrl = form.find("#Id").length ? settings.postEditUrl : settings.postInsertUrl;
            
            if (form.valid()) {
                UNGM.throbOver(elements.contextForm);
                $.ajax({
                    type: form.attr('method'),
                    url: actionUrl,
                    data: form.serialize(),
                    success: function (data) {
                        if ( data && data.error) {
                            // an error message was returned, so don't continue, show the error message instead
                            $.confirm(
                                "", // title
                                data.message, // message
                                "OK", // yes button
                                "", // no button
                                function () { }, //"yes" callback
                                300 // the minimum width of the model dialog
                            );
                            UNGM.hideThrobber();
                        }
                        else {
                            if (settings.formSubmittedCallback) {
                                settings.formSubmittedCallback(form);
                            }

                            elements.contextForm.parent().dialog('close');

                            var container = $(evt.currentTarget).data("container");
                            if (container != null) {
                                elements.container = $("#" + container);
                                elements.listContainer = elements.container.find(".listContainer");
                            }

                            methods.list();
                        }
                    }
                });
            }
            return false;
        },
        bindOptions: function (element) {
            element.find(".btnEdit").unbind("click").bind("click", methods.showEdit);
            element.find(".btnDelete").unbind("click").bind("click", methods.deleteItem);
        },
        list: function () {
            var url = settings.listUrl;
            UNGM.throbOver(elements.container);
            $.ajax({
                type: 'GET',
                url: url,
                success: function (data) {

                    elements.listContainer.html(data);

                    if (settings.itemClickedCallback) {
                        elements.listContainer.find(".editableListItem").addClass("clickableListItem").unbind("click").bind("click", methods.itemClicked);
                    }

                    methods.bindOptions(elements.listContainer);
                    // Look for a callback method here
                    if (UNGM.EditableListCallbacks && UNGM.EditableListCallbacks.listChangedCallback) {
                        UNGM.EditableListCallbacks.listChangedCallback();
                    }

                    // Hide 'add another button' if no more items are allowed
                    if (settings.maxItems == null || (settings.maxItems != null && settings.maxItems > elements.container.find(".editableListItem").length)) {
                        elements.container.find(".addanother").show();
                        elements.container.find(".addanother").unbind("click.editableList").bind("click.editableList", methods.addAnother);
                    }
                    else {
                        elements.container.find(".addanother").hide();
                        elements.container.find(".addanother").unbind("click.editableList", methods.addAnother);
                    }

                    UNGM.hideThrobber();
                }
            });
        },
        get: function (itemId) {
            var url;
            if (settings.getEditUrl.indexOf("{0}") >= 0) {
                url = settings.getEditUrl.replace("{0}", itemId);
            } else {
                url = settings.getEditUrl + itemId;
            }

            UNGM.throbOver(elements.container);
            $.ajax({
                type: 'GET',
                url: url,
                success: function (data) {
                    var newForm = $(data);
                    elements.contextForm = newForm;
                    elements.contextForm.find("input[type='submit']").bind("click", methods.submitForm);
                    elements.contextForm.find("input[type='datetime']").datepicker({
                        onSelect: function (dateText, inst) {
                            UNGM.Validation.validateElement($(this));
                        },
                        changeYear: true,
                        changeMonth: true
                    });
                    UNGM.Validation.initForElement(elements.contextForm);

                    var modal = $("<div>").dialog({
                        modal: true,
                        title: UNGM.editableListEditDialogTitle,
                        width: '66%',
                        height: settings.dialogHeight,
                        hide: { effect: 'fade', duration: 100 },
                        show: { effect: 'fade', duration: 100 },
                        close: function () { elements.contextForm.parent().remove(); }
                    }).append(elements.contextForm);

                    if (!settings.dialogHeight) {
                        modal.dialog('option', 'height', elements.contextForm.outerHeight());
                    }

                    UNGM.hideThrobber();
                    UNGM.initTabsIn(elements.contextForm);
                }
            });
        },
        showEdit: function (evt) {
            var item = $(evt.currentTarget).parents(".editableListItem:first");
            var maincontainer = item.parents("div.listMainContainer");
            if (maincontainer.length > 0) {
                settings = maincontainer.data("settings");
            }
            var itemId = item.data("itemid");
            methods.get(itemId);
            evt.stopPropagation();
        },
        deleteItem: function (evt) {

            $.confirm(
                UNGM.editableListConfirmDialogTitle,
                UNGM.editableListConfirmDialogText,
                UNGM.editableListConfirmDialogYes,
                UNGM.editableListConfirmDialogNo,
                function () {
                    var item = $(evt.currentTarget).parents(".editableListItem:first");
                    var maincontainer = item.parents("div.listMainContainer");
                    if (maincontainer.length > 0) {
                        settings = maincontainer.data("settings");
                    }
                    var itemId = item.data("itemid");
                    var obj = { itemId: itemId };
                    var url = settings.deleteUrl;

                    // If there's a file involved in the item, make it available in the document picker
                    if (item.data("documentid") !== undefined && UNGM.DocumentPicker) {
                        var removedDocId = item.data("documentid");

                        for (var i = 0; i < UNGM.DocumentPicker.filesUsed.length; i++) {
                            if (UNGM.DocumentPicker.filesUsed[i] == removedDocId) {
                                UNGM.DocumentPicker.filesUsed.splice(i, 1);
                                $("#documentSearch .isused[data-documentid='" + removedDocId + "']").val(0);
                                UNGM.DocumentPicker.disableUnavailableDocs();
                            }
                        }
                    }
                    elements.listContainer = $(evt.currentTarget).parents(".listContainer");
                    elements.container = elements.listContainer.parent();

                    UNGM.throbOver(elements.container);
                    $.ajax({
                        type: 'POST',
                        url: url,
                        data: obj,
                        success: function (data) {
                            methods.list();
                            UNGM.hideThrobber();
                        }
                    });
                }
            );


            evt.stopPropagation();
        },
        itemClicked: function (evt) {
            var maincontainer = $(evt.currentTarget).parent("div").parent("div");
            if (maincontainer !== undefined) {
                settings = maincontainer.data("settings");
            }
            if (settings.itemClickedCallback) {
                var sender = $(evt.currentTarget);
                settings.itemClickedCallback(sender);
            }
        },
        option: function (name, value) {
            if (value === undefined) {
                return settings[name];
            }
            settings[name] = value;
        }
    };

    elements = {
        contextForm: null
    };
    settings = {
        listUrl: null,
        getInsertUrl: null,
        postInsertUrl: null,
        getEditUrl: null,
        postEditUrl: null,
        deleteUrl: null,
        itemClickedCallback: null,
        formSubmittedCallback: null,
        entityName: null,
        isReadonly: false,
        maxItems: null,
        dialogHeight: null
    };

    $.fn.editableList = function (method) {

        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        } else {
            $.error('Method ' + method + ' does not exist on jQuery.editableList');
        }

    };

})(jQuery);;
UNGM.ExpandableContacts = {
    btnShowDetailsText: "Show details",     // this value will be replaced with localised UI text
    btnHideDetailsText: "Hide details",     // this value will be replaced with localised UI text

    init: function () {
        $(".editableListItem > span").css("cursor", "pointer").off("click").on("click", UNGM.ExpandableContacts.onContactClicked);
        $(".btnExpandAll").off("click").on("click", UNGM.ExpandableContacts.onExpandAllContactsClicked);
        $(".btnCollapseAll").off("click").on("click", UNGM.ExpandableContacts.onCollapseAllContactsClicked);
    },
    onContactClicked: function (e) {
        $details = $(e.target).parents(".editableListItem").children(".contactDetails");
        $details.slideToggle(function () {
            $(this).siblings(".options").find(":button").prop("value", $(this).is(":visible") ? UNGM.ExpandableContacts.btnHideDetailsText : UNGM.ExpandableContacts.btnShowDetailsText);
        });
    },
    onExpandAllContactsClicked: function () {
        $(".contactDetails").slideDown(function () {            
            $(".btnExpandAll").parent().find(".options :button").prop("value", UNGM.ExpandableContacts.btnHideDetailsText);
        });
    },
    onCollapseAllContactsClicked: function () {
        $(".contactDetails").slideUp(function () {            
            $(".btnCollapseAll").parent().find(".options :button").prop("value", UNGM.ExpandableContacts.btnShowDetailsText);
        });
    }
};
'use strict';

(function (namespace, undefined) {
    namespace.ExpandableItems = Factory;

    function Factory(selector) {
        var root = $(selector);
        root.on("click", ".btnDetails", toggleDetail);

        function toggleDetail(e) {
            var detail = $(e.target).parents(".expandableListItem").children(".body");
                detail.slideToggle(function () {
                    $(this).siblings(".options").find(".btnDetails").prop("value", $(this).is(":visible") ? "Hide details" : "Show details");
                    $(this).siblings(".expandable, .options").toggleClass("expanded");
                });
        }
    }
})(window.UNGM = window.UNGM || {});;
window.UNGM.Inbox = {
    subject: null,
    currentConversationId: null,
    replyToEmailId: null,
    resendConfirmationMessageTitle: "",
    resendConfirmationMessageMessage: "",
    resendConfirmationMessageYes: "",
    resendConfirmationMessageNo: "",
    searchFunction: null,
    pendingSearchRequest: null,
    general: {
        pageIndex: 0,
        sortField: "Id",
        sortAscending: true,
        paging: false,
        inSearch: false,
        folderId: "receivedItems"   // The default view shows the 'receivedItems'
    },/*
    conversationsFolder: {
        pageIndex: 0,
        sortField: "Id",
        sortAscending: true,
        paging: false,
        folderId: "Conversations",
        isContentLoaded: false
    },*/
    receivedItemsFolder: {
        pageIndex: 0,
        sortField: "Date",
        sortAscending: false,
        paging: false,
        folderId: "ReceivedItems",
        isContentLoaded: false
    },
    sentItemsFolder: {
        pageIndex: 0,
        sortField: "Date",
        sortAscending: false,
        paging: false,
        folderId: "SentItems",
        isContentLoaded: false
    },
    init: function () {
        $(".tableBody").on("click", ".tableRow", UNGM.Inbox.onConversationClicked);
        $(".tableBody").on("keypress", ".tableRow", UNGM.Inbox.onConversationClicked);
        $("#btnBack").bind("click", UNGM.Inbox.onBackClicked);
        $(".btnSearch").bind("click", UNGM.Inbox.btnSearchClicked);
        $("#formInboxFilter").bind("submit", UNGM.Inbox.btnSearchClicked);
        $("#conversationContainer").on("click", ".btnReply", UNGM.Inbox.onReplyClicked);
        $("#conversationContainer").on("click", ".btnReplyWithTemplate", UNGM.Inbox.onReplyWithTemplateClicked);
        $("#conversationContainer").on("click", ".btnSend", UNGM.Inbox.onSendClicked);
        $("#conversationContainer").on("click", ".btnResend", UNGM.Inbox.onResendClicked);
        $("#conversationContainer").on("click", ".btnCancel", UNGM.Inbox.onCancelClicked);
        $("#inboxContainer .accessibilityTab").bind("click", UNGM.Inbox.onFolderChanged);
        $(".clearFilter").bind("click", UNGM.Inbox.clearAll);
        // Conversations tab is not sortable
        // $("#ConversationsFolder .tableHead .header").addClass("notsortable");
        $(".folderHolder .tableHead .header").not(".notsortable").on("click", UNGM.Inbox.sort);

        // Load message on load if the url contains the id
        UNGM.Inbox.onPageLoaded();

        UNGM.ieHackTableHeader();
    },
    onFolderChanged: function (e) {
        var currentFolderId = $(e.currentTarget).attr("id");

        $.waypoints('destroy');

        switch (currentFolderId) {
            case "ReceivedItems":
                UNGM.Inbox.general = UNGM.Inbox.receivedItemsFolder;
                UNGM.Inbox.searchFunction = UNGM.Inbox.search;

                if (!UNGM.Inbox.receivedItemsFolder.isContentLoaded) {
                    UNGM.Inbox.general.pageIndex = 0;
                    UNGM.Inbox.general.paging = false;
                    UNGM.Inbox.search();
                    UNGM.Inbox.receivedItemsFolder.isContentLoaded = true;
                }
                else {
                    UNGM.Inbox.setWaypoints();
                }
                break;
            case "SentItems":
                UNGM.Inbox.general = UNGM.Inbox.sentItemsFolder;
                UNGM.Inbox.searchFunction = UNGM.Inbox.search;

                if (!UNGM.Inbox.sentItemsFolder.isContentLoaded) {
                    UNGM.Inbox.general.pageIndex = 0;
                    UNGM.Inbox.general.paging = false;
                    UNGM.Inbox.search();
                    UNGM.Inbox.sentItemsFolder.isContentLoaded = true;
                }
                else {
                    UNGM.Inbox.setWaypoints();
                }
                break;
        }
    },
    setWaypoints: function () {
        // Only set the waypoints if there are more items to load
        var $folder = $("#" + UNGM.Inbox.general.folderId + "Folder");

        if ($folder.find(".showing").html() == $folder.find(".searchTotal").html()) {
            return;
        }
        
        $folder.find(".folderHolder").waypoint(function (direction) {
            if (direction === 'down' && !UNGM.Inbox.general.inSearch) {
                $.waypoints('destroy');
                UNGM.Inbox.general.inSearch = false;
                UNGM.Inbox.general.pageIndex += 1;
                UNGM.Inbox.general.paging = true;
                UNGM.Inbox.searchFunction();
            }
        }, { offset: 'bottom-in-view' });
        UNGM.Inbox.general.inSearch = false;
    },
    clearAll: function (e) {
        $target = $(e.currentTarget);
        $filter = $target.parents(".folderFilter");
        $filter.find("input[type=text]:visible").val('');

        UNGM.Inbox.general.pageIndex = 0;
        UNGM.Inbox.general.paging = false;
        UNGM.Inbox.search();
    },
    filterKeyUp: function () {
        if (UNGM.Inbox.timeoutFunc) {
            clearTimeout(UNGM.Inbox.timeoutFunc);
        }

        UNGM.Inbox.timeoutFunc = setTimeout(function () {
            UNGM.Inbox.general.pageIndex = 0;
            UNGM.Inbox.general.paging = false;
            UNGM.Inbox.search();
        }, 700);
    },
    sort: function (evt) {
        var sender = $(evt.currentTarget);
        var newSortField = sender.attr('id');
        if (UNGM.Inbox.general.sortField == newSortField) {
            UNGM.Inbox.general.sortAscending = !UNGM.Inbox.general.sortAscending;
        } else {
            // First time column is clicked sorts ASC by default
            UNGM.Inbox.general.sortField = newSortField;
            UNGM.Inbox.general.sortAscending = true;
        }

        $(".folderHolder:visible .header.sortedAsc").removeClass("sortedAsc");
        $(".folderHolder:visible .header.sortedDesc").removeClass("sortedDesc");

        var newClass = UNGM.Inbox.general.sortAscending ? "sortedAsc" : "sortedDesc";
        sender.addClass(newClass);

        UNGM.Inbox.general.pageIndex = 0;
        UNGM.Inbox.general.paging = false;
        UNGM.Inbox.search();
    },
    list: function () {
        UNGM.throbOver();

        var opts = UNGM.Inbox.buildOptions();

        $.ajax({
            url: 'Inbox/ListConversations',
            type: 'POST',
            contentType: 'application/json',
            data: JSON.stringify(opts),
            success: UNGM.Inbox.onGetEmailsSuccess
        });
    },
    buildOptions: function () {
        var $filter = $(".folderFilter:visible");

        var opts = {
            PageIndex: UNGM.Inbox.general.pageIndex,
            SortField: UNGM.Inbox.general.sortField,
            SortAscending: UNGM.Inbox.general.sortAscending,
            FolderId: UNGM.Inbox.general.folderId,
            DateFrom: $filter.find(".txtDateSentFrom").val(),
            DateTo: $filter.find(".txtDateSentTo").val(),
            Email: $filter.find(".txtEmail").val(),
            Subject: $filter.find(".txtSubject").val(),
            Body: $filter.find(".txtBody").val()
        };

        return opts;
    },
    search: function () {
        // do not search if we're viewing an email
        if ($("#btnBack").is(':visible')) {
            return;
        }
        UNGM.throbOver();

        var opts = UNGM.Inbox.buildOptions();

        if (UNGM.Inbox.pendingSearchRequest) {
            UNGM.Inbox.pendingSearchRequest.abort();
        }
        UNGM.Inbox.pendingSearchRequest = $.ajax({
            url: 'Inbox/Search',
            type: 'POST',
            contentType: 'application/json',
            data: JSON.stringify(opts),
            success: UNGM.Inbox.onGetEmailsSuccess
        });
    },
    onGetEmailsSuccess: function (response) {
        if (response.length) {
            var $folderContainer = $("#" + UNGM.Inbox.general.folderId + "Folder")
            var $tableBody = $folderContainer.find(".tableBody");

            if (UNGM.Inbox.general.paging) {
                $tableBody.append(response);
                UNGM.Inbox.general.paging = false;
            }
            else {
                $tableBody.html(response);
            }

            UNGM.ieHackTableCells();
        }

        var showing = $tableBody.find(".tableRow").length;
        $folderContainer.find(".showing").html(showing);

        if (showing > 0) {
            $folderContainer.find(".noEmailsInfo").hide();
            $folderContainer.find(".resultsContainer").show();
        }
        else {
            $folderContainer.find(".noEmailsInfo").show();
            $folderContainer.find(".resultsContainer").hide();
        }

        UNGM.Inbox.setWaypoints();
        UNGM.hideThrobber();
    },
    onPageLoaded: function () {
        UNGM.Inbox.general = UNGM.Inbox.receivedItemsFolder;
        UNGM.Inbox.searchFunction = UNGM.Inbox.search;

        if (window.location.href.indexOf('#') != -1) {
            UNGM.Inbox.currentConversationId = window.location.href.substring(window.location.href.indexOf('#') + 1, window.location.href.length);
            UNGM.Inbox.getConversation();
        }        
        else {
            UNGM.Inbox.search();
            //UNGM.Inbox.conversationsFolder.isContentLoaded = true;
        }
        
    },
    onConversationClicked: function (e) {
        var $target = $(e.currentTarget);
        UNGM.Inbox.currentConversationId = $target.data("conversationid");

        // Add id of conversation to url
        if (typeof window.history.replaceState == 'function') {
            window.history.pushState("Open conversation", "Open conversation", "#" + UNGM.Inbox.currentConversationId);
        }

        // Set value to the button to go back
        switch (UNGM.Inbox.general.folderId) {
            //case "Conversations":
            //    $("#btnBack").val(UNGM.Inbox.btnBackToConversationsValue);
            //    break;
            case "ReceivedItems":
                $("#btnBack").val(UNGM.Inbox.btnBackToReceivedItemsValue);
                break;
            case "SentItems":
                $("#btnBack").val(UNGM.Inbox.btnBackToSentItemsValue);
                break;
        }
        
        UNGM.Inbox.getConversation();
    },
    getConversation: function () {
        UNGM.throbOver($("#inbox"));
        $.ajax({
            url: UNGM.siteRoot + "Account/Inbox/GetConversation?conversationid=" + UNGM.Inbox.currentConversationId,
            type: 'GET',
            success: UNGM.Inbox.onGotConversation,
            error: function (event, jqXHR, ajaxSettings, thrownError) {
                if (jqXHR.status == "403") {
                    // The user does not have access to the email
                    return false;
                }
            }
        });
    },
    onGotConversation: function (data) {
        $("#inboxContainer").hide();
        $("#conversationEmails").html(data);
        $("#conversationSubject").html(UNGM.Inbox.subject);
        $("#conversationContainer").fadeIn("fast");
        $("#conversationContainer .editableListItem:last").find(".body").show();
        $("#btnBack").scrollintoview();
        UNGM.hideThrobber();
    },
    onBackClicked: function () {
        if (typeof window.history.replaceState == 'function') {
            window.history.pushState("Inbox", "Inbox", "#");
            history.replaceState({}, '', window.location.href.slice(0, window.location.href.indexOf('#') - window.location.href.length));
        }
        UNGM.Inbox.currentConversationId = null;
        $("#conversationContainer").hide();
        $("#inboxContainer").fadeIn("fast");
        // make sure the waypoints are switched back on for the search tab we're returning to
        var activeTab = $(".activeTab")
        var newObj = { currentTarget: activeTab };
        UNGM.Inbox.onFolderChanged(newObj);
        //if (!UNGM.Inbox.conversationsFolder.isContentLoaded) {
        //    UNGM.Inbox.list();
        //    UNGM.Inbox.conversationsFolder.isContentLoaded = true;
        //}
    },
    btnSearchClicked: function () {
        $.waypoints('destroy');
        UNGM.Inbox.general.pageIndex = 0;
        UNGM.Inbox.general.paging = false;
        UNGM.Inbox.searchFunction();
    },
    onReplyWithTemplateClicked: function(e) {
        var $button = $(e.currentTarget);
        var $email = $button.parents(".editableListItem");
        UNGM.Inbox.currentConversationId = $email.data("conversationid");
        UNGM.Inbox.replyToEmailId = $email.data("id");
        UNGM.FeedbackEmail.ccEmails = [];
        UNGM.FeedbackEmail.bccEmails = [];
        // open the email dialog
        UNGM.throbOver("#conversationContainer");
        $.ajax({
            url: UNGM.siteRoot + 'UNUser/EmailTemplates/EmailFeedback',
            type: 'POST',
            contentType: 'application/json',
            success: UNGM.Inbox.onFeedbackEmail
        });
    },
    onFeedbackEmail: function (data) {
        $("#emailDialog").html(data);
        $("#radShowAll").click();
        $("#divAllOrMatching").hide();
        UNGM.HelpdeskTemplates.isInboxEmail = true;
        // open the dialog
        $("#emailDialog").dialog({
            modal: true,
            title: "Reply to feedback",
            width: 900,
            height: 640,
            hide: { effect: 'fade', duration: 100 },
            show: { effect: 'fade', duration: 100 }
        });
        UNGM.hideThrobber();
    },
    sendTemplateEmail: function () {
        // If the user is not active the document picker doesn't exist.
        try {
            var attachments = $.map(UNGM.DocumentPicker.filesUsed, function (val) { return val.Id; });
        }
        catch (e) { }

        var newEmail = {
            Id: UNGM.Inbox.replyToEmailId,
            Body: UNGM.HelpdeskTemplates.getCurrentBodyText(),
            Attachments: attachments,
            cc: UNGM.FeedbackEmail.ccEmails,
            bcc: UNGM.FeedbackEmail.bccEmails
        };
        // form has already been validated  in the UNGM.HelpdeskTemplates.js script
        UNGM.throbOver($("#conversationContainer"));
        $.ajax({
            url: UNGM.siteRoot + "Account/Inbox/ReplyEmail",
            type: 'POST',
            contentType: 'application/json',
            data: JSON.stringify(newEmail),
            success: function () {
                // If the user is not active the document picker doesn't exist.
                try {
                    UNGM.DocumentPicker.filesUsed = [];
                }
                catch (e) { }
                $("#emailDialog").dialog("close");
                // Show a message telling the user that the emails have been sent
                $.confirm(
                    UNGM.HelpdeskTemplates.EmailSentTitle, // Title
                    UNGM.HelpdeskTemplates.EmailSentMessage, // Message
                    "",
                    UNGM.HelpdeskTemplates.EmailSentOK,
                    ""  //"yes" callback
               );

                UNGM.Inbox.getConversation();
            },
            complete: function () {
                UNGM.hideThrobber();
            }
        });
    },
    onReplyClicked: function (e) {
        var $button = $(e.currentTarget);
        var $email = $button.parents(".editableListItem");

        if (!$email.find(".replyForm").length) {
            $form = $("#replyForm").clone().removeAttr("id").addClass("replyForm");
            $email.find(".body").append($form);
        }
        else {
            $form = $email.find(".replyForm");
        }
        $textarea = $form.find("textarea");
        $textarea.attr("cols", $email.width() / 8.3);
        setTimeout(function () { $textarea.focus(); }, 0);
        $form.fadeIn("fast");
        $email.find(".body").slideDown("fast");
        UNGM.DocumentPicker.init();
        $textarea[0].setSelectionRange(0, 0);
    },
    onCancelClicked: function (e) {
        var $button = $(e.currentTarget);
        $button.parents(".replyForm").fadeOut("fast", function () {
            $(this).remove();
        });
    },
    onSendClicked: function (e) {
        var $button = $(e.currentTarget);
        var $email = $button.parents(".email");
        UNGM.Inbox.currentConversationId = $email.data("conversationid");

        // If the user is not active the document picker doesn't exist.
        try {
            var attachments = $.map(UNGM.DocumentPicker.filesUsed, function (val) { return val.Id; });
        }
        catch (e) { }

        var newEmail = {
            Id: $email.data("id"),
            Body: $email.find("textarea").val().replace(/\n/g, '<br />'),
            Attachments: attachments
        };

        // Validate the form manually because there's no model in the view
        if (!$.trim(newEmail.Body).length) {
            $email.find(".errorMessageEmpty").show();
            $email.find("textarea").bind("focus", function () {
                $email.find(".errorMessageEmpty").hide();
            });
            return false;
        }

        UNGM.throbOver($("#conversationContainer"));
        $.ajax({
            url: UNGM.siteRoot + "Account/Inbox/ReplyEmail",
            type: 'POST',
            contentType: 'application/json',
            data: JSON.stringify(newEmail),
            success: function () {
                // If the user is not active the document picker doesn't exist.
                try {
                    UNGM.DocumentPicker.filesUsed = [];
                }
                catch (e) { }

                $(".docslist").html("");
                $(".noDocsMessage").show();
                $button.parents(".replyForm").fadeOut("fast", function () {
                    $(this).remove();
                });
                UNGM.Inbox.getConversation();
                $('html, body').animate({
                }, 500);
            },
            complete: function () {
                UNGM.hideThrobber();
            }
        });
    },
    onResendClicked: function (e) {

        var resendEmailConfirmed = function () {
            var $button = $(e.currentTarget);
            var $email = $button.parents(".email");
            var id = $email.data("id");
            UNGM.Inbox.currentConversationId = $email.data("conversationid");

            UNGM.throbOver($("#conversationContainer"));
            $.ajax({
                url: UNGM.siteRoot + "Account/Inbox/ResendEmail/",
                type: 'POST',
                data: "id=" + id,
                success: function () {
                    UNGM.Inbox.getConversation();
                },
                complete: function () {
                    UNGM.hideThrobber();
                }
            });
        };

        $.confirm(
            UNGM.Inbox.resendConfirmationMessageTitle, // Title
            UNGM.Inbox.resendConfirmationMessageMessage, // Message
            UNGM.Inbox.resendConfirmationMessageYes,
            UNGM.Inbox.resendConfirmationMessageNo,
            resendEmailConfirmed  //"yes" callback
        );
    }
};
window.UNGM.ManageUserSettings = {
    RevokeClientAccessConfirmationTitle: '',
    RevokeClientAccessConfirmationMessage: '',
    RevokeClientAccessConfirmationBtnYes: '',
    RevokeClientAccessConfirmationBtnNo: '',
    init: function () {
        $('#PreferredLanguage').val(UNGM.currentuserCookieLanguage);      // needed for safari
        $('#PreferredLanguage').bind('change', UNGM.ManageUserSettings.preferredLanguageChanged);
        $('.btnRevokeClientAccess').bind('click', UNGM.ManageUserSettings.onRevokeClientAccessClicked);
        $('#ReceivesNotificationsOfCompanyNameChange').on('change', UNGM.ManageUserSettings.onReceivesNotificationsOfCompanyNameChangeChanged);
        $('[name="ReceiveMarketingEmails"]').on('change', UNGM.ManageUserSettings.onReceiveMarketingEmailsChanged);
    },
    preferredLanguageChanged: function () {
        UNGM.Throbber.Push();
        var preferredLanguage = $('#PreferredLanguage').val();
        UNGM.setUserLanguage(preferredLanguage);
    },
    onRevokeClientAccessClicked: function (e) {
        var apiClientId = $(e.currentTarget).data('api-client-id');

        var revokeAccessOk = function () {
            UNGM.throbOver();

            $.ajax({
                url: UNGM.siteRoot + 'Account/Account/RevokeClientAccess',
                type: 'POST',
                data: { 'apiClientId': apiClientId },
                success: function (response) {
                    $('#clientGrantHolder').html(response);
                    // Bind button events
                    $('.btnRevokeClientAccess').bind('click', UNGM.ManageUserSettings.onRevokeClientAccessClicked);
                },
                complete: UNGM.hideThrobber
            });
        }

        $.confirm(
            UNGM.ManageUserSettings.RevokeClientAccessConfirmationTitle,
            UNGM.ManageUserSettings.RevokeClientAccessConfirmationMessage,
            UNGM.ManageUserSettings.RevokeClientAccessConfirmationBtnYes,
            UNGM.ManageUserSettings.RevokeClientAccessConfirmationBtnNo,
            revokeAccessOk
        );
    },
    onReceivesNotificationsOfCompanyNameChangeChanged: function (event) {
        UNGM.Throbber.Push();
        var receivesNotificationsOfCompanyNameChange = $(event.currentTarget).prop('checked');
        var url = receivesNotificationsOfCompanyNameChange
            ? UNGM.siteRoot + 'Account/UserSettings/OptInForNotificationsOfCompanyNameChange'
            : UNGM.siteRoot + 'Account/UserSettings/OptOutOfNotificationsOfCompanyNameChange';
        $.post(url).always(UNGM.Throbber.Pop);
    },
    onReceiveMarketingEmailsChanged: function (event) {
        UNGM.Throbber.Push();
        var receiveMarketingEmails = $(event.currentTarget).val() === "True";
        var url = receiveMarketingEmails
            ? UNGM.siteRoot + 'Account/UserSettings/OptInForMarketingEmails'
            : UNGM.siteRoot + 'Account/UserSettings/OptOutOfMarketingEmails';

        $.post(url).always(function () {
            UNGM.Throbber.Pop();
        });
    }
}
;
(function (namespace, undefined) {

    //
    // NoticeSearch
    //
    
    namespace.NoticeSearch = function (parameter) {
        this.divNoticeMain = $(parameter.divNoticeMainSelector);

        this.btnApplySearch = parameter.btnApplySearch;
        this.btnDeleteSavedSearch = parameter.btnDeleteSavedSearch;
        this.NoSavedSearchFound = parameter.NoSavedSearchFound;
        this.FailedToLoadSavedSearches = parameter.FailedToLoadSavedSearches;
        this.SearchFilterSaved = parameter.SearchFilterSaved;
        this.SearchFilterNotSaved = parameter.SearchFilterNotSaved;
        this.DefaulSearchSet = parameter.DefaulSearchSet;
        this.DefaulSearchNotSet = parameter.DefaulSearchNotSet;
        this.SearchFilterDeleted = parameter.SearchFilterDeleted;
        this.SearchFilterNotDeleted = parameter.SearchFilterNotDeleted;
        this.SearchFilterShare = parameter.SearchFilterShare;
        this.SearchFilterErrorOnShare = parameter.SearchFilterErrorOnShare;
        this.SearchFilterShare = parameter.SearchFilterShare;
       
        this.selNoticeAgency = $(parameter.selNoticeAgencySelector);
        this.hidIsAgencySelected = $(parameter.hidIsAgencySelectedSelector);
        this.divNoticeSearchAgency = $(parameter.divNoticeSearchAgencySelector);
        this.hidIsCountrySelected = $(parameter.hidIsCountrySelectedSelector);
        this.selNoticeCountry = $(parameter.selNoticeCountrySelector);
        this.divNoticeSearchCountry = $(parameter.divNoticeSearchCountrySelector);
        this.btnEOI = $(parameter.btnEOISelector);
        this.btnSaveNotice = $(parameter.btnSaveNotice);
        this.lblNoticeSearchTotal = $(parameter.lblNoticeSearchTotalSelector);
        this.txtNoticePublishedFrom = $(parameter.txtNoticePublishedFromSelector);
        this.txtNoticePublishedTo = $(parameter.txtNoticePublishedToSelector);
        this.txtNoticeDeadlineFrom = $(parameter.txtNoticeDeadlineFromSelector);
        this.txtNoticeDeadlineTo = $(parameter.txtNoticeDeadlineToSelector);
        this.btnSaveNoticeSearch = $(parameter.btnSaveNoticeSearchSelector);
        this.parameter = parameter;

        this.chbSustainableNoticeClass = this.divNoticeMain.find("#chkSustainable");
        this.chbIsActiveNoticeClass = this.divNoticeMain.find("#chkIsActive");
        this.chbNoticeTypeClass = this.divNoticeMain.find(".noticeTypeCheckboxList");
        this.chbTypeOfCompetitions = this.divNoticeMain.find(".typeOfCompetitionCheckboxList");
        this.pickNotice = this.divNoticeMain.find(".pickNotice");
        this.divNoticeData = this.divNoticeMain.find('#notices');
        this.divNoticeTotal = this.divNoticeMain.find('#noticesTotal');
        this.txtNoticeFilterTitle = this.divNoticeMain.find("#txtNoticeFilterTitle");
        this.txtNoticeFilterDesc = this.divNoticeMain.find("#txtNoticeFilterDesc");
        this.txtNoticeFilterRef = this.divNoticeMain.find("#txtNoticeFilterRef");
        this.divNoticeSearchUNSPSC = this.divNoticeMain.find("#noticeSearchUNSPSC");
        this.divNoticeUNSPSCSelector = this.divNoticeMain.find("#noticeUNSPSCSelector");
        this.btnClearAll = this.divNoticeMain.find("#lnkClearAll");
        this.btnSearch = this.divNoticeMain.find("#lnkSearch");
        this.lnkShowUNSPSC = this.divNoticeMain.find("#lnkShowUNSPSC");
        this.lnkEditUNSPSC = this.divNoticeMain.find("#lnkEditUNSPSC");
        this.divEditNotice = this.divNoticeMain.find("#editNotice");
        this.tblNotices = this.divNoticeMain.find("#tblNotices");
        this.hidIsEOISearch = this.divNoticeMain.find("#isEOISearch");
        this.hidIsPicker = this.divNoticeMain.find("#IsPicker");
        this.hidIsForSavedNotice = this.divNoticeMain.find("#IsForSavedNotice");
        this.hidIsVendorSubscribedToTenderAlertService = this.divNoticeMain.find("#IsVendorSubscribedToTenderAlertService");
        this.hidWidgetUNSPSCs = this.divNoticeMain.find("#WidgetUNSPSCs");
        this.hidWidgetAgency = this.divNoticeMain.find("#WidgetAgency");
        this.hidNoticeDisplayType = this.divNoticeMain.find("#NoticeDisplayType");

        this.unspscTitleText = parameter.UNSPSCTitleText;
        this.EOIFailureTitle = parameter.EOIFailureTitle;
        this.EOIFailureMessage = parameter.EOIFailureMessage;
        this.EOIFailureOK = parameter.EOIFailureOK;

        this.CanNotExpressInterestTitle = parameter.CanNotExpressInterestTitle;
        this.CanNotExpressInterestMessage = parameter.CanNotExpressInterestMessage;
        this.CanNotExpressInterestConfirmButton = parameter.CanNotExpressInterestConfirmButton;

        this.ShowSubscriptionMessage = parameter.ShowSubscriptionMessage;
        this.SubscribeTitle = parameter.SubscribeTitle;
        this.SubscribeMessage = parameter.SubscribeMessage;
        this.SubscribeConfirmButtonText = parameter.SubscribeConfirmButtonText;
        this.SubscribeCancelButtonText = parameter.SubscribeCancelButtonText;

        this.CountryPlaceholder = parameter.CountryPlaceholder;
        this.selectedCountries = [];
        this.selectedAgencies = [];
        this.selectedUNSPSCs = [];
        this.selectedTypeOfCompetitions = [];
        this.sustainableNotice = false;
        this.isActiveNotice = true;
        this.selectedNoticeTypes = [];
        this.selectedNoticeDisplayType = null;
        this.prevPageIndex = 0;
        this.pageIndex = 0;
        this.paging = false;
        this.inSearch = false;
        this.timeoutFunc = null;
        this.sortField = "Deadline"; // default sort by
        this.sortAscending = true;
        this.pendingSearchRequest = null;

        this.selNoticeAgency.bind("change", this.onNoticeAgencySelect(this));
        this.prePopulateFilters(this);
        this.selNoticeCountry.bind("change", this.onNoticeCountrySelect(this));
        this.selNoticeCountry.attr("placeholder", this.CountryPlaceholder);
        this.lnkShowUNSPSC.on("click", this.showUNSPSC(this));
        this.lnkEditUNSPSC.on("click", this.editUNSPSC(this));

        this.chbNoticeTypeClass.off("click").on("click", this.selectNoticeType(this));
        this.chbTypeOfCompetitions.off("click").on("click", this.selectTypeOfCompetition(this));

        this.chbSustainableNoticeClass.off("click").on("click", this.selectSustainableNotice(this));
        this.chbIsActiveNoticeClass.off("click").on("click", this.selectActiveNotice(this));

        this.btnSearch.on("click", this.Search(this, true));
        this.btnClearAll.on("click", this.clearAll(this));

        this.tblNotices.find('.tableHead .tableRow .tableCell').not(".notsortable").on("click", this.Sort(this));

        this.btnSaveNoticeSearch.on("click", this.saveNoticeSearch(this));
        var todayDate = new Date();

        this.txtNoticeDeadlineFrom.datepicker("setDate", todayDate);
        this.txtNoticePublishedTo.datepicker("option", "maxDate", todayDate);
        this.txtNoticePublishedTo.datepicker("setDate", todayDate);

        this.hidIsAgencySelected.on("change", this.clearAgency(this));
        this.hidIsCountrySelected.on("change", this.clearCountry(this));

        // Load UNSPSCs,Agency,NoticeDisplayType from Widget setting
        if (this.hidWidgetUNSPSCs.val()) {
            this.renderReadOnlyUNSPSCs(this);
        }
        if (this.hidWidgetAgency.val()) {
            this.renderReadOnlyAgency(this);
        }
        if (this.hidNoticeDisplayType.val()) {
            this.renderReadOnlyDisplayType(this);
        }

        //only run the search if we're not in picker mode (search will not be needed if the picker isn't used) 
        if (this.hidIsPicker !== undefined && this.hidIsPicker.length !== 0) {
            var ip = this.hidIsPicker.val().toLowerCase();
            if (!(ip == 'true')) {
                // Set height to show loading for first time
                this.divNoticeData.css("height", 150 + "px");
                this.Search(this).call();
                // Set height back to auto
                this.divNoticeData.css("height", "auto");
            }
        }
        //Check if called from widget's page
        if (this.divNoticeMain.attr("id") != "noticeMain") {
            this.divNoticeData.css("max-height", 400 + "px");
            this.divNoticeData.css("overflow", "auto");
        }
        // Datepickers select change
        this.txtNoticePublishedFrom.datepicker({
            onSelect: function (dateText, inst) {
            }
        });

        UNGM.ieHackTableHeader();
    }

    namespace.NoticeSearch.prototype.setupEventHandlers = function () {
        var $this = this;

        $('#savedSearchesList').on('click', '.apply-search', function (event) {
            $this.applySavedSearch(event);
        });

        $('#savedSearchesList').on('click', '.delete-search', function (event) {
            $this.deleteSavedSearch(event);
        });
        $('#savedSearchesList').on('change', '.share-search', function (event) {
            $this.toggleShareSavedSearch(event, $(this).data("id"), $(this).is(":checked"));
        });
        $('#savedSearchesList').on('change', '.default-search', function (event) {
            $('.default-search').not(this).prop('checked', false);
            var searchId = $(this).data("id");
            if (this.checked) {
                $this.setDefaultSearch(searchId);
            } else {
                $this.setDefaultSearch(searchId);
            }
        });
    };

    namespace.NoticeSearch.prototype.ReAssignEOIAndIntendButtons = function (parameter) {
        this.btnEOI = $(parameter.btnEOISelector);
        this.btnEOI.off("click").on("click", this.expressInterestClick(this));
        this.btnEOI.off("keypress").on("keypress", this.expressInterestClick(this));
    }

    namespace.NoticeSearch.prototype.ReAssignSaveNoticeButtons = function (parameter) {
        this.btnSaveNotice = $(parameter.btnSaveNotice);
        this.btnSaveNotice.off("click").on("click", this.saveNoticeClick(this));
        this.btnSaveNotice.off("keypress").on("keypress", this.saveNoticeClick(this));
    }

    namespace.NoticeSearch.prototype.ReAssignSearchTotal = function (parameter, searchTotal) {
        this.lblNoticeSearchTotal = $(parameter.lblNoticeSearchTotalSelector);
        this.lblNoticeSearchTotal.html("");
        this.lblNoticeSearchTotal.html(searchTotal);
    }

    namespace.NoticeSearch.prototype.Search = function ($this, resetPageIndex) {
        return function () {
            if ($this.pendingSearchRequest) {
                $this.pendingSearchRequest.abort();
            }
            if (resetPageIndex) {
                $this.pageIndex = 0;
            }
            var opts = $this.BuildOptions($this);
            UNGM.throbOver($this.divNoticeData);
            var url = "";
            if ($this.hidIsEOISearch.val() === "true") {
                url = UNGM.siteRoot + 'Public/Notice/SearchEOI';
            }
            else {
                url = UNGM.siteRoot + 'Public/Notice/Search';
                if ($this.hidIsForSavedNotice.val() === "True") {
                    url += '?isForSavedNotice=true';
                }
            }
            $this.pendingSearchRequest =
                $.ajax({
                    url: url,
                    type: 'POST',
                    contentType: 'application/json',
                    data: JSON.stringify(opts),
                    success: function (data) { $this.onGotData(data, $this); UNGM.Throbber.Pop(); }
                });
        }
    }

    namespace.NoticeSearch.prototype.BuildOptions = function ($this) {

        var opts =
        {
            PageIndex: $this.pageIndex,
            PageSize: 15,
            Title: $this.txtNoticeFilterTitle.val(),
            Description: $this.txtNoticeFilterDesc.val(),
            Reference: $this.txtNoticeFilterRef.val(),
            PublishedFrom: $this.txtNoticePublishedFrom.val(),
            PublishedTo: $this.txtNoticePublishedTo.val(),
            DeadlineFrom: $this.txtNoticeDeadlineFrom.val(),
            DeadlineTo: $this.txtNoticeDeadlineTo.val(),
            Countries: $this.selectedCountries,
            Agencies: $this.selectedAgencies,
            UNSPSCs: $this.selectedUNSPSCs,
            NoticeTypes: $this.selectedNoticeTypes,
            SortField: $this.sortField,
            SortAscending: $this.sortAscending,
            isPicker: ($this.hidIsPicker.val() || 'false').toLowerCase() === 'true',
            IsSustainable: $this.sustainableNotice,
            IsActive: $this.isActiveNotice,
            NoticeDisplayType: $this.selectedNoticeDisplayType,
            NoticeSearchTotalLabelId: $this.lblNoticeSearchTotal.attr('id'),
            TypeOfCompetitions: $this.selectedTypeOfCompetitions
        };
        return opts;
    }

    namespace.NoticeSearch.prototype.Sort = function ($this) {
        return function (evt) {
            var sender = $(evt.currentTarget);
            var newSortField = sender.attr('id');
            switch (newSortField) {
                case "id_Deadline":
                    newSortField = "Deadline";
                    break;
                case "id_DatePublished":
                    newSortField = "DatePublished";
                    break;
            }
            if (newSortField == undefined || newSortField == "") {
                newSortField = "Deadline";
            }

            if ($this.sortField == newSortField) {
                // 2 clicks on the same column means swap order
                $this.sortAscending = !$this.sortAscending;
            }
            else {
                // First time column is clicked sorts ASC by default
                $this.sortField = newSortField;
                $this.sortAscending = true;
            }

            $this.divNoticeMain.find("#tblNotices .sortedAsc").removeClass("sortedAsc");
            $this.divNoticeMain.find("#tblNotices .sortedDesc").removeClass("sortedDesc");

            var newClass = $this.sortAscending ? "sortedAsc" : "sortedDesc";
            sender.addClass(newClass);

            $this.pageIndex = 0;
            $this.paging = false;
            $this.Search($this).call();

        }
    }

    namespace.NoticeSearch.prototype.onGotData = function (data, $this) {
        $this.prevPageIndex = $this.pageIndex;
        data = $.trim(data);
        var dataArray = $(data).toArray();
        var returnRows = $(dataArray).filter(".dataRow").length;
        if (returnRows < 1) {
            if ($this.paging) {
                $this.paging = false;
            }
            else {
                $this.divNoticeData.find("#noticesEmpty").show();
                $this.divNoticeData.find("#tblNotices").hide();
                $this.divNoticeTotal.hide();
                $this.divNoticeData.find("#intendEOI").hide();
            }
        }
        else {
            $this.divNoticeData.children("script").remove();
            if ($this.paging) {
                $this.divNoticeData.find(".tableBody").append(data);
                $this.paging = false;
            }
            else {
                $this.divNoticeData.find(".tableBody").html(data);
                $this.divNoticeData.find("#tblNotices").show();
                $this.divNoticeTotal.show();
                $this.divNoticeData.find("#noticesEmpty").hide();
            }

            if ($("#IsPicker").val().toLowerCase() == 'true') {
                $this.pickNotice.bind("click", $this.pickNoticeClicked);
            }

            $this.showingCount = ($this.tblNotices.find(".tableRow").length - 1);
            $this.totalCount = parseInt($this.lblNoticeSearchTotal.html(), 10);


            $this.ReAssignEOIAndIntendButtons($this.parameter);
            $this.ReAssignSaveNoticeButtons($this.parameter);
            $this.divNoticeData.find(".btnEdit").off("click").on("click", $this.editNotice($this));
            $this.divNoticeMain.find(".tableBody .tableRow").off("click").on("click", $this.noticeClickedOrEnterKeypressed($this));
            $this.divNoticeMain.find(".tableBody .tableRow").off("keypress").on("keypress", $this.noticeClickedOrEnterKeypressed($this));
            $this.divNoticeMain.find('.tableHead .tableRow .tableCell').not(".notsortable").off("click").on("click", this.Sort(this));
            $this.divNoticeMain.find("#SearchCountOf").show();
            $this.divNoticeMain.find("#searchCount").show()
            $this.divNoticeMain.find("#searchCountNo").text($this.showingCount);
            // showhide EOI
            $this.ShowHideEOI($this);

            // Calculate context and offset depending on the display page
            var noticeContext = null;
            var noticeOffset = null;

            var contextHeight = $this.divNoticeData.height();
            var tableHeight = $this.divNoticeData.find("#tblNotices").height();
            var marginForRounding = 3;
            if (contextHeight + marginForRounding < tableHeight) {
                noticeOffset = -(tableHeight - contextHeight);
                noticeContext = $this.divNoticeData;
            } else {
                // if picker, context is dialogbox id
                if ($("#IsPicker").val().toLowerCase() == 'true') {
                    noticeContext = $("#dlgNoticeSearch");
                    noticeOffset = -(tableHeight - $("#dlgNoticeSearch").height());
                } else {
                    noticeOffset = 'bottom-in-view';
                }
            }

            $this.divNoticeData.find("#tblNotices").waypoint(function (direction) {
                if (direction === 'down' && !$this.inSearch && $this.showingCount < $this.totalCount) {
                    $this.divNoticeData.find("#tblNotices").waypoint('destroy');
                    $this.pageIndex = $this.prevPageIndex + 1;
                    $this.inSearch = true;
                    $this.paging = true;
                    $this.Search($this).call();
                }
            }, {
                context: noticeContext,
                offset: noticeOffset
            });
            $this.inSearch = false;

        }
        // Trigger agency hidden to clear value
        $this.hidIsAgencySelected.trigger("change");
        // Trigger country hidden to clear value
        $this.hidIsCountrySelected.trigger("change");
        UNGM.ieHackTableCells();
        UNGM.hideThrobber();
    }

    namespace.NoticeSearch.prototype.ShowHideEOI = function ($this) {
        if ($this.divNoticeData.find("#tblNotices").find('.buttonIntend').length > 0) {
            $this.divNoticeData.find('#intendEOI').show();
        }
        else {
            $this.divNoticeData.find('#intendEOI').hide();
        }
    }

    namespace.NoticeSearch.prototype.onNoticeAgencySelect = function ($this) {
        return function (evt) {

            var sender = $(evt.currentTarget);
            var agencyId = parseInt(sender.val());
            if (sender.val() == '') {
                return;
            }
            var agencyAbbreviation = sender.children(':selected').text();

            $this.addAgencyFilter($this, agencyId, agencyAbbreviation);

            $this.pageIndex = 0;
            $this.paging = false;
            $this.Search($this).call();
            // Set hidden value to 1 to trigger change.
            $this.hidIsAgencySelected.val(1);
        }
    }

    namespace.NoticeSearch.prototype.prePopulateFilters = function ($this) {
        if ($this.parameter.PrePopulateFilters && $this.parameter.PrePopulateFilters.AgencyId) {
            var agencyId = $this.parameter.PrePopulateFilters.AgencyId;
            var agencyAbbreviation = $this.parameter.PrePopulateFilters.AgencyAbbreviation;

            $this.addAgencyFilter($this, agencyId, agencyAbbreviation);
        }
    }

    namespace.NoticeSearch.prototype.onNoticeCountrySelect = function ($this) {
        return function (evt) {
            var sender = $(evt.currentTarget);
            var countryId = sender.val();
            if (countryId == '') {
                return;
            }
            var countryName = sender.children(':selected').text();
            var selectedCountry = {
                Id: countryId,
                Name: countryName
            };

            // Search 
            for (var i = 0; i < $this.selectedCountries.length; i++) {
                if ($this.selectedCountries[i] == countryId) {
                    return; // country is already in the list, so do nothing
                }
            }
            // Add selected country to the array
            $this.selectedCountries.push(countryId);

            //Add selected country to place holder
            var holder = $this.divNoticeSearchCountry;
            var elem = $("<div class='noticeSelectedCountry'></div>");
            elem.data("ID", countryId);

            var span = $("<span class='noticeSelectedCountryName'></span>");
            span.html(countryName);

            var removeButton = $("#removeButtonTemplate").clone();
            removeButton.removeAttr("id").show();
            removeButton.data("Id", countryId);
            removeButton.text(removeButton.text() + " " + countryName);
            removeButton.bind("click", $this.removeCountryClicked($this));

            elem.append(span).append(removeButton);
            holder.append(elem);

            if ($this.selectedCountries.length > 0) {
                $this.divNoticeSearchCountry.show();
            }
            else {
                $this.divNoticeSearchCountry.hide();
            }
            $this.pageIndex = 0;
            $this.paging = false;
            $this.Search($this).call();

            // Set hidden valaue to 1 to trigger change.
            $this.hidIsCountrySelected.val(1);
        }
    }

    namespace.NoticeSearch.prototype.removeAgencyClicked = function ($this) {
        return function (evt) {
            var sender = $(evt.currentTarget);
            var removedArray = "";
            removedArray = $this.selectedAgencies;
            var removedId = sender.data("Id");

            for (var i = 0; i < removedArray.length; i++) {
                if (removedArray[i] == removedId) {
                    removedArray.splice(i, 1);
                }
            }
            // Remove selected agency div from place holder
            var parentMain = sender.parents($this.divNoticeSearchAgency);
            parentMain.find(".noticeSelectedAgency").each(function () {
                if ($(this).data("ID") == removedId) {
                    $(this).closest("div").remove();
                }
            });
            //hide selected agency div when all are removed.
            if (removedArray.length == 0) {
                $this.divNoticeSearchAgency.hide();
            }
        }
    }

    namespace.NoticeSearch.prototype.removeCountryClicked = function ($this) {
        return function (evt) {
            var sender = $(evt.currentTarget);
            var removedArray = $this.selectedCountries;

            var removedId = sender.data("Id");

            for (var i = 0; i < removedArray.length; i++) {
                if (removedArray[i] == removedId) {
                    removedArray.splice(i, 1);
                }
            }
            // Remove selected country div from place holder
            var parentMain = sender.parents($this.divNoticeSearchCountry);
            parentMain.find(".noticeSelectedCountry").each(function () {
                if ($(this).data("ID") == removedId) {
                    $(this).closest("div").remove();
                }
            });
            //hide selected country div when all are removed.
            if (removedArray.length == 0) {
                $this.divNoticeSearchCountry.hide();
            }
        }
    }

    namespace.NoticeSearch.prototype.removeUNSPSCClicked = function ($this) {
        return function (evt) {
            var sender = $(evt.currentTarget);
            var removedArray = $this.selectedUNSPSCs;

            var removedId = sender.data("Id");

            for (var i = 0; i < removedArray.length; i++) {
                if (removedArray[i] == removedId) {
                    removedArray.splice(i, 1);
                }
            }
            UNGM.UNSPSC.removeCode(removedId);

            // Remove selected UNSPSC div from place holder
            var parentMain = sender.parents($this.divNoticeSearchUNSPSC);
            parentMain.find(".noticeSelectedUNSPSC").each(function () {
                if ($(this).data("ID") == removedId) {
                    $(this).closest("div").remove();
                }
            });
            //hide selected UNSPSC div when all are removed.
            if (removedArray.length == 0) {
                $this.divNoticeSearchUNSPSC.hide();
            }
        }
    }

    namespace.NoticeSearch.prototype.clearCountry = function ($this) {
        return function () {
            var change = $(this).val();
            if (change == 1) {
                $this.selNoticeCountry.parent(".filterRow").find('.ui-autocomplete-input').val("");
                $(this).val("0");
            }
        }
    }

    namespace.NoticeSearch.prototype.clearAgency = function ($this) {
        return function () {
            var change = $(this).val();
            if (change == 1) {
                $this.selNoticeAgency.parent(".filterRow").find('.ui-autocomplete-input').val("");
                $(this).val("0");
            }
        }
    }

    namespace.NoticeSearch.prototype.showUNSPSC = function ($this) {
        return function () {
            UNGM.UNSPSC.saveCallback = $this.unspscSaveCallback($this);
            
            //refresh the picker selection
            var picker = $this.divNoticeUNSPSCSelector.find(".unspsc");
            UNGM.UNSPSC.bindSelectedCodes(picker);

            var winHeight = $(window).height();
            $this.divNoticeUNSPSCSelector.dialog({
                modal: true,
                title: $this.unspscTitleText,
                open: function () {
                    $(".unspsc-action-clear-selected").click();
                },
                width: $(window).width() < 480 ? '100%' : '66%',
                height: $(window).width() < 480 ? $(window).height() : winHeight - (winHeight * 0.2),
                hide: { effect: 'fade', duration: 100 },
                show: { effect: 'fade', duration: 100 }
            });
        }
    }

    namespace.NoticeSearch.prototype.editUNSPSC = function ($this) {
        return function () {
            UNGM.UNSPSC.saveCallback = $this.unspscSaveCallback($this);
            
            //refresh the picker selection
            var picker = $this.divNoticeUNSPSCSelector.find(".unspsc");
            UNGM.UNSPSC.bindSelectedCodes(picker);

            var winHeight = $(window).height();
            $this.divNoticeUNSPSCSelector.dialog({
                modal: true,
                title: $this.unspscTitleText,
                open: function () {
                    setTimeout(function () {
                        $(".unspsc-action-filter-selected").click();
                    }, 500);
                },
                width: $(window).width() < 480 ? '100%' : '66%',
                height: $(window).width() < 480 ? $(window).height() : winHeight - (winHeight * 0.2),
                hide: { effect: 'fade', duration: 100 },
                show: { effect: 'fade', duration: 100 }
            });
            
        }
    }

    namespace.NoticeSearch.prototype.unspscSaveCallback = function ($this) {
        return function () {
            //Add selected UNSPSC to place holder
          
            var unspscId = null;
            $this.selectedUNSPSCs = [];
            for (var i = 0; i < UNGM.UNSPSC.selectedItems.length; i++) {
                unspscId = parseInt(UNGM.UNSPSC.selectedItems[i].id, 10);
                $this.selectedUNSPSCs.push(unspscId);
            }

            if ($this.selectedUNSPSCs.length > 0) {
                $this.lnkShowUNSPSC.hide();
                $this.lnkEditUNSPSC.show();
            }
            else {
                $this.lnkEditUNSPSC.hide();
                $this.lnkShowUNSPSC.show();
            }

            var selector = $this.divNoticeUNSPSCSelector;
            if (selector.is(':data(dialog)') || selector.hasClass('ui-dialog-content')) {
                selector.dialog("close");
            }
        }
    }

    namespace.NoticeSearch.prototype.selectNoticeType = function ($this) {
        return function (evt) {
            var sender = $(evt.currentTarget);
            var checked = sender.prop("checked");
            var typeId = sender.attr("id");

            if (checked) {
                $this.selectedNoticeTypes.push(typeId);
            }
            else {
                for (var i = 0; i < $this.selectedNoticeTypes.length; i++) {
                    if ($this.selectedNoticeTypes[i] == typeId) {
                        $this.selectedNoticeTypes.splice(i, 1);
                    }
                }
            }
        }
    }

    namespace.NoticeSearch.prototype.selectSustainableNotice = function ($this) {
        return function (evt) {
            var sender = $(evt.currentTarget);
            var checked = sender.prop("checked");

            $this.sustainableNotice = checked;
        }
    }

    namespace.NoticeSearch.prototype.selectActiveNotice = function ($this) {
        return function (evt) {
            var sender = $(evt.currentTarget);
            var checked = sender.prop("checked");

            $this.isActiveNotice = checked;
        }
    }

    namespace.NoticeSearch.prototype.selectTypeOfCompetition = function ($this) {
        return function (evt) {
            var sender = $(evt.currentTarget);
            var checked = sender.prop("checked");

            if (checked) {
                $this.selectedTypeOfCompetitions.push(sender.val());
            }
            else {
                if ($this.selectedTypeOfCompetitions.length == 1) {
                    $this.selectedTypeOfCompetitions = [];
                }
                else {
                    for (var i = 0; i < $this.selectedTypeOfCompetitions.length; i++) {
                        if ($this.selectedTypeOfCompetitions[i] == sender.val()) {
                            $this.selectedTypeOfCompetitions.splice(i, 1);
                        }
                    }
                }
            }
        }
    }

    namespace.NoticeSearch.prototype.clearAll = function ($this) {
        return function () {

            $this.txtNoticeFilterTitle.val('');
            $this.txtNoticeFilterDesc.val('');
            $this.txtNoticeFilterRef.val('');

            $this.selectedCountries = [];
            $this.selectedNoticeTypes = [];
            $this.selectedTypeOfCompetitions = [];
            $this.sustainableNotice = false;
            $this.isActiveNotice = false;

            $this.selNoticeCountry.find('option').eq(0).attr('selected', 'selected');
            $this.selNoticeCountry.parent(".filterRow").find('.ui-autocomplete-input').val("");
            $this.divNoticeSearchCountry.children("div").remove();
            $this.divNoticeSearchCountry.hide();

            $this.chbNoticeTypeClass.removeAttr('checked');
            $this.chbSustainableNoticeClass.removeAttr('checked');
            $this.chbIsActiveNoticeClass.removeAttr('checked');
            $this.chbTypeOfCompetitions.removeAttr('checked');

            if (!$this.hidWidgetAgency.val()) {
                $this.selectedAgencies = [];
                $this.selNoticeAgency.find('option').eq(0).attr('selected', 'selected');
                $this.selNoticeAgency.parent(".filterRow").find('.ui-autocomplete-input').val("");
                $this.divNoticeSearchAgency.children("div").remove();
                $this.divNoticeSearchAgency.hide();
            }

            if (!$this.hidWidgetUNSPSCs.val()) {
                $this.selectedUNSPSCs = [];
                $("#noticeFilter #lnkEditUNSPSC").hide();
                $("#noticeFilter #lnkShowUNSPSC").show();
            }

            if (!$this.hidNoticeDisplayType.val() || $this.hidNoticeDisplayType.val().indexOf('All') > 0) {
                $this.txtNoticePublishedFrom.val('');
                $this.txtNoticePublishedTo.val('');
                $this.txtNoticeDeadlineFrom.val('');
                $this.txtNoticeDeadlineTo.val('');
            }

            $this.pageIndex = 0;
            $this.paging = false;
            $this.Search($this).call();
        }
    }

    namespace.NoticeSearch.prototype.editNotice = function ($this) {
        return function (evt) {
            evt.stopPropagation();
            var id = $(evt.currentTarget).data("noticeid");
            UNGM.throbOver($this.divNoticeData);
            var url = UNGM.siteRoot + 'UNUser/Notice/PopupEdit?id=' + id;
            $.ajax({
                url: url,
                type: 'POST',
                contentType: 'application/json',
                success: function (data) { $this.onNoticeEdit(data, $this); }
            });
        }
    },

    namespace.NoticeSearch.prototype.onNoticeEdit = function (data, $this) {

            var winHeight = $(window).height();
            $this.divEditNotice.hide().html(data).dialog({
                modal: true,
                width: '90%',
                height: winHeight - (winHeight * 0.1),
                hide: { effect: 'fade', duration: 100 },
                show: { effect: 'fade', duration: 100 },
                open: function () {
                    UNGM.initTabsIn($this.divEditNotice);
                    UNGM.Validation.init();
                    var mainDialog = $this.divEditNotice;
                    mainDialog.find("form").each(function () {
                        $(this).find(".validationIcon,.field-validation-error").hide();
                        $(this).removeData("validator");
                        $(this).removeData("unobtrusiveValidation");
                        $.validator.unobtrusive.parse(this);
                    });
                },
                close: function () {
                    // destroy the CKEDitor otherwise we'll get errors
                    for (var instanceName in CKEDITOR.instances) {
                        CKEDITOR.instances[instanceName].updateElement();
                        CKEDITOR.instances[instanceName].destroy(); // The instances must be destroyed or the next time we open a modal we get errors
                    }
                }
            });

            UNGM.hideThrobber();
        }

    namespace.NoticeSearch.prototype.noticeClickedOrEnterKeypressed = function ($this) {
        return function (evt) {
            if (!$(evt.target).is("svg *") && !$(evt.target).is("a *") && !$($(evt).attr('target')).hasClass('buttonViewDocuments')) {
                UNGM.gaEvent('Access to notice detail', 'Click', 'Whole table row -> Dialog');
                UNGM.throbOver($this.divNoticeData);
                var id = $(evt.currentTarget).data("noticeid");
                var isPicker = ($this.hidIsPicker.val().toLowerCase() == 'true' ? "?isPicker=true" : "");
                $.ajax({
                    url: UNGM.siteRoot + 'Public/Notice/Popup/' + id + isPicker,
                    type: 'GET',
                    success: function (data) { $this.onGotNoticeDetail(data, $this); },
                    cache: true
                })
            } else {
                UNGM.gaEvent('Access to notice detail', 'Click', 'Button with icon -> New tab');
            }
        }

    }

    namespace.NoticeSearch.prototype.onGotNoticeDetail = function (detail, $this) {
        UNGM.hideThrobber();
        var winHeight = $(window).height();
        var detailElem = $(detail);
        var title = detailElem.find("#noticeTitle").html();

        $("<div>").attr("id", "noticeDetail")
            .html(detail)
            .dialog({
                modal: true,
                width: $(window).width() < 480 ? '100%' : '66%',
                title: title,
                height: $(window).width() < 480 ? $(window).height() : winHeight - (winHeight * 0.2),
                hide: { effect: 'fade', duration: 100 },
                show: { effect: 'fade', duration: 100 },
                open: function () {
                    UNGM.ExpandableContacts.init();
                    UNGM.NoticeView.init();
                    UNGM.UNSPSC.init();
                    UNGM.initTabs();
                    UNGM.Notice.ViewDocument.initFor("#notice-detail-view-document-container");
                    $("#noticeDetail .pickNotice").bind("click", $this.pickNoticeClicked($this));
                    $this.ReAssignEOIAndIntendButtons($this.parameter);
                    $('#wholePage').css('overflow', 'hidden');
                },
                close: function () { $("#noticeDetail").dialog("destroy"); }
            });
    }

    namespace.NoticeSearch.prototype.pickNoticeClicked = function ($this) {
        return function (evt) {
            // Call this back at the root
            UNGM.NoticePickerCallbacks.pickNoticeClicked(evt);
        }
    }

    namespace.NoticeSearch.prototype.expressInterestClick = function ($this) {
        return function (evt) {
            evt.stopPropagation();

            UNGM.Throbber.Push();

            $.ajax({
                url: UNGM.siteRoot + 'Public/Notice/IsUserAuthenticated',
                type: 'GET',
                contentType: 'application/json',
                success: function (isAuthenticated) {
                    if (isAuthenticated === "False") {
                        window.location = UNGM.siteRoot + 'Account/Account/Login?returnUrl=' + window.location.pathname;
                    } else {
                        var $target = $(evt.currentTarget);

                        // if notice is published through UNGM and does not require EOI then show a detail message and return
                        if ($target.data('noticecanbeexpressedinterest') === "False") {
                            $.confirm(
                                $this.CanNotExpressInterestTitle,
                                $this.CanNotExpressInterestMessage,
                                $this.CanNotExpressInterestConfirmButton,
                                "",
                                function () { }
                            );

                            UNGM.hideThrobber();
                            return;
                        }

                        var id = $target.data("noticeid");
                        var agencyid = $target.data("agencyid");
                        var data = {
                            noticeId: id,
                            agencyId: agencyid
                        };

                        var url = UNGM.siteRoot + 'Public/Notice/ExpressInterest';
                        $.ajax({
                            url: url,
                            data: JSON.stringify(data),
                            type: 'POST',
                            contentType: 'application/json',
                            success: function (response) {
                                if (response.success) {
                                    $target.hide();
                                    $target.parents(".table-cell-eoi").next().show();
                                    $(".view-document-container").show();
                                    if (response.isVendorSubsribedToTenderAlertService === false && $this.ShowSubscriptionMessage !== "False") {
                                        $this.ShowSubscriptionMessage = "False";

                                        $.confirmWithNoCallback(
                                            $this.SubscribeTitle,
                                            $this.SubscribeMessage,
                                            $this.SubscribeConfirmButtonText,
                                            $this.SubscribeCancelButtonText,
                                            function () {
                                                window.location.href = UNGM.siteRoot + '/Vendor/MyUNGMPro';
                                            },
                                            function () {
                                                $.ajax({
                                                    url: UNGM.siteRoot + 'Public/Notice/MarkVendorAsNotInterestedInSubscribingToTenderAlertService',
                                                    type: 'POST'
                                                });
                                            }
                                        );
                                    }
                                }
                                else {
                                    $.confirm(
                                        $this.EOIFailureTitle, // Title
                                        $this.EOIFailureMessage, // Message
                                        $this.EOIFailureOK, //yes button text (blank hides button)
                                        "", //no button text (blank hides button)
                                        function ($this) {
                                        } //"yes" callback
                                    );
                                }
                                UNGM.Throbber.Pop();
                            }
                        });
                    }
                }
            });

        }
    }

    namespace.NoticeSearch.prototype.saveNoticeClick = function ($this) {
        return function (evt) {
            evt.stopPropagation();
            if ($this.hidIsVendorSubscribedToTenderAlertService.val() === "False") {
                return;
            }

            UNGM.Throbber.Push();
            var $target = $(evt.currentTarget);
            var action = $target.data("action-url");
            $.post(action)
                .done(function () {
                    $target.hide();
                    $target.siblings(".save-notice-button").show();
                    if (action.includes("UnsaveNotice") && $this.hidIsForSavedNotice.val() === "True") {
                        $this.Search($this).call();
                    }
                    UNGM.Throbber.Pop();
                });
        }
    }

    namespace.NoticeSearch.prototype.expandUNSPSCSelectedClick = function ($this) {
        return function (evt) {
            var lnkExpandUNSPSC = $(evt.currentTarget);

            if (lnkExpandUNSPSC.text().match("Expand")) {
                $this.divNoticeSearchUNSPSC.find('.noticeSelectedUNSPSC').show();
                lnkExpandUNSPSC.text("Collapse all");
            }
            else {
                $this.divNoticeSearchUNSPSC.find('.noticeSelectedUNSPSC').hide();
                lnkExpandUNSPSC.text("Expand all");
            }
        }
    }

    namespace.NoticeSearch.prototype.renderReadOnlyUNSPSCs = function ($this) {
        //Add selected UNSPSC to place holder
        var holder = $this.divNoticeSearchUNSPSC;
        holder.find("div").remove();
        var unspscId = null;
        var Code = null;
        var UNSPSCName = null;
        $this.selectedUNSPSCs = [];
        UNGM.UNSPSC.selectedCodes = JSON.parse($this.hidWidgetUNSPSCs.val());

        // Add to place holder
        var elemExpand = $("<a href='javascript:;'>Expand all</a>");
        elemExpand.on("click", $this.expandUNSPSCSelectedClick($this));
        holder.append(elemExpand);

        for (var i = 0; i < UNGM.UNSPSC.selectedCodes.length; i++) {
            unspscId = parseInt(UNGM.UNSPSC.selectedCodes[i].Id, 10);
            Code = UNGM.UNSPSC.selectedCodes[i].Code;
            UNSPSCName = UNGM.UNSPSC.selectedCodes[i].Name;
            $this.selectedUNSPSCs.push(unspscId);

            // Add to place holder
            var elem = $("<div class='noticeSelectedUNSPSC' style='display: none;'></div>");
            elem.data("ID", unspscId);

            var span = $("<span class='noticeSelectedUNSPSC'></span>");
            span.html(Code + " - " + UNSPSCName);

            elem.append(span);
            holder.append(elem);
        }

        if ($this.selectedUNSPSCs.length > 0) {
            holder.show();
        }
        else {
            holder.hide();
        }

        var selector = $this.divNoticeUNSPSCSelector;
        if (selector.is(':data(dialog)') || selector.hasClass('ui-dialog-content')) {
            selector.dialog("close");
        }

        $this.lnkShowUNSPSC.hide();
    }

    namespace.NoticeSearch.prototype.renderReadOnlyAgency = function ($this) {
        var widgetAgency = JSON.parse($this.hidWidgetAgency.val());
        // Add selected agency to the array
        $this.selectedAgencies.push(widgetAgency.Id);

        //Add selected agency to place holder
        var holder = $this.divNoticeSearchAgency;
        var elem = $("<div class='NoticeSelectedAgency'></div>");
        elem.data("ID", widgetAgency.Id);

        var span = $("<span class='NoticeSelectedAgencyName'></span>");
        span.html(widgetAgency.Name);

        elem.append(span);
        holder.append(elem);

        $this.divNoticeSearchAgency.show();
    }

    namespace.NoticeSearch.prototype.renderReadOnlyDisplayType = function ($this) {
        var noticeDisplayType = JSON.parse($this.hidNoticeDisplayType.val());
        var date = new Date();
        var yDate = new Date(date.setDate(date.getDate() - 1))
        var today = $.datepicker.formatDate('dd-M-yy', new Date());
        var yesterday = $.datepicker.formatDate('dd-M-yy', yDate);

        switch (noticeDisplayType.Id) {
            case 1: // All                
                $this.txtNoticePublishedFrom.val('');
                $this.txtNoticePublishedTo.val('');
                $this.txtNoticeDeadlineFrom.val('');
                $this.txtNoticeDeadlineTo.val('');
                break;
            case 2: // Current active
                $this.txtNoticePublishedFrom.val('');
                $this.txtNoticePublishedTo.val(today);
                $this.txtNoticeDeadlineFrom.val(today);
                $this.txtNoticeDeadlineTo.val('');
                $this.divNoticeMain.find(".filterDatePairLabel").hide();
                $this.divNoticeMain.find(".filterDatePair").hide();
                break;
            case 3: // Previous
                $this.txtNoticePublishedFrom.val('');
                $this.txtNoticePublishedTo.val(yesterday);
                $this.txtNoticeDeadlineFrom.val('');
                $this.txtNoticeDeadlineTo.val(yesterday);
                $this.divNoticeMain.find(".filterDatePairLabel").hide();
                $this.divNoticeMain.find(".filterDatePair").hide();
                break;
        }
    }
    //------------------------------------Save Notice Search---------------------------
    namespace.NoticeSearch.prototype.showMessage = function (message, isSuccess) {
        var messageLabel = $("#messageLabel");
        var messageContainer = $("#messageContainer");

        messageLabel.text(message);
        messageContainer.css("color", isSuccess ? "green" : "red");
        messageContainer.show().delay(3000).fadeOut();
    }

    namespace.NoticeSearch.prototype.loadSavedSearches = function () {
        var $this = this;
        
        $.ajax({
            url: '/Vendor/NoticeSearchFilters/GetAll',
            type: 'GET',
            contentType: 'application/json',
            cache: false,
            success: function (data) {
                var savedSearchesList = $("#savedSearchesList");
                savedSearchesList.empty();
                if (data && data.length > 0) {
                    data.forEach(function (search) {
                        var isDefault = search.Filter.Id === search.DefaultFilterId;
                        var currentUserId = $('#CurrentUserId').val();
                        
                        // Clone the template elements
                        var applyButton = $('#templates .apply-search-template').clone()
                            .removeClass('apply-search-template')
                            .addClass('apply-search')
                            .attr('data-json', JSON.stringify(search.Filter.SearchJSON));

                        var deleteButton = $('#templates .delete-search-template').clone()
                            .removeClass('delete-search-template')
                            .addClass('delete-search')
                            .attr('data-id', search.Filter.Id);

                        var shareCheckboxLabel = $('#templates .share-search-template').clone()
                            .removeClass('share-search-template')
                            .addClass('share-search-label'); 
                        shareCheckboxLabel.find('input').attr('data-id', search.Filter.Id)
                            .prop('checked', search.Filter.IsShared);

                        var defaultCheckboxLabel = $('#templates .default-search-template').clone()
                            .removeClass('default-search-template')
                            .addClass('default-search-label'); 
                        defaultCheckboxLabel.find('input').attr('data-id', search.Filter.Id)
                            .prop('checked', isDefault);

                        // Construct list item
                        var listItem = $('<li>').append($('<span>').addClass('name').text(search.Filter.Name))

                        if (currentUserId == search.Filter.UserId) {
                            listItem.append($('<span>').addClass('share-container').append(shareCheckboxLabel));
                        } else {
                            shareCheckboxLabel.find('input').prop('disabled', true);
                            deleteButton.prop('disabled', true);
                            listItem.append($('<span>').addClass('share-container').append(shareCheckboxLabel));
                        }
                            
                        listItem.append($('<span>').addClass('default-container').append(defaultCheckboxLabel))
                            .append(applyButton)
                            .append(deleteButton);

                        // Append to the list
                        $('#savedSearchesList').append(listItem);

                        if (isDefault) {
                            applyButton.trigger('click');
                        }
                    });

                } else {
                    savedSearchesList.append("<li>" + $this.NoSavedSearchFound + "</li>");
                }
            },
            error: function (xhr, status, error) {
                console.error("Error loading saved searches:", error);
            }
        });
    };

    namespace.NoticeSearch.prototype.applySavedSearch = function (event) {
        var $this = this;
        
        var searchJSONString = $(event.target).data('json');
        
        if (!searchJSONString) {
            $this.showMessage($this.FailedToApplySavedSearches, false);
            return;
        }
        try {
            UNGM.Throbber.Push();
            var searchJSON = JSON.parse(JSON.parse(searchJSONString));
            
            // Populate the fields with the saved search data
            $this.txtNoticeFilterTitle.val(searchJSON.Title || '');
            $this.txtNoticeFilterDesc.val(searchJSON.Description || '');
            $this.txtNoticeFilterRef.val(searchJSON.Reference || '');

            // Reset and populate countries
            $this.selectedCountries = searchJSON.Countries || [];
            $this.divNoticeSearchCountry.children().remove();
            $this.selectedCountries.forEach(function (countryId) {
                var countryName = $this.selNoticeCountry.find(`option[value='${countryId}']`).text();
                $this.addCountryFilter($this, countryId, countryName);
            }.bind(this));

            // Reset and populate agencies
            $this.selectedAgencies = searchJSON.Agencies || [];
            $this.divNoticeSearchAgency.children().remove();
            $this.selectedAgencies.forEach(function (agencyId) {
                var agencyAbbreviation = $this.selNoticeAgency.find(`option[value='${agencyId}']`).text();
                $this.addAgencyFilter($this, agencyId, agencyAbbreviation);
            }.bind(this));

            // Reset and populate UNSPSCs
            $this.selectedUNSPSCs = [];
            $this.selectedUNSPSCs = searchJSON.UNSPSCs;
            window.uvm.setSelectedIds(searchJSON.UNSPSCs); 
            
            if ($this.selectedUNSPSCs.length > 0) {
                $this.lnkShowUNSPSC.hide();
                $this.lnkEditUNSPSC.show();
            } else {
                $this.lnkEditUNSPSC.hide();
                $this.lnkShowUNSPSC.show();
            }
            
            // Reset and populate notice types
            $this.selectedNoticeTypes = searchJSON.NoticeTypes || [];
            $this.chbNoticeTypeClass.prop('checked', false);
            $this.selectedNoticeTypes.forEach(function (typeId) {
                $this.chbNoticeTypeClass.filter(`#${typeId}`).prop('checked', true);
            }.bind(this));

            // Reset and populate type of competitions
            $this.selectedTypeOfCompetitions = searchJSON.TypeOfCompetitions || [];
            $this.chbTypeOfCompetitions.prop('checked', false);
            $this.selectedTypeOfCompetitions.forEach(function (competitionId) {
                $this.chbTypeOfCompetitions.filter(`[value='${competitionId}']`).prop('checked', true);
            }.bind(this));

            // Populate sustainable notice
            $this.sustainableNotice = searchJSON.IsSustainable || false;
            $this.chbSustainableNoticeClass.prop('checked', searchJSON.IsSustainable);

            // Populate active notice
            $this.isActiveNotice = searchJSON.IsActive || false;
            $this.chbIsActiveNoticeClass.prop('checked', searchJSON.IsActive);

            // Ensure hidden fields are set
            $this.hidIsPicker.val(searchJSON.isPicker ? searchJSON.isPicker.toString() : 'false');
            $this.hidIsForSavedNotice.val(searchJSON.IsForSavedNotice ? searchJSON.IsForSavedNotice.toString() : 'false');

            $this.Search($this).call();
            
        } catch (e) {
            this.showMessage($this.FailedToApplySavedSearches, false);
        } 
    }

    namespace.NoticeSearch.prototype.addCountryFilter = function ($this, countryId, countryName) {
        var holder = $this.divNoticeSearchCountry;
        var elem = $("<div class='noticeSelectedCountry'></div>");
        elem.data("ID", countryId);

        var span = $("<span class='noticeSelectedCountryName'></span>");
        span.html(countryName);

        var removeButton = $("#removeButtonTemplate").clone();
        removeButton.removeAttr("id").show();
        removeButton.data("Id", countryId);
        removeButton.text(removeButton.text() + " " + countryName);
        removeButton.bind("click", $this.removeCountryClicked($this));

        elem.append(span).append(removeButton);
        holder.append(elem);

        if ($this.selectedCountries.length > 0) {
            $this.divNoticeSearchCountry.show();
        } else {
            $this.divNoticeSearchCountry.hide();
        }
    }

    namespace.NoticeSearch.prototype.addAgencyFilter = function ($this, agencyId, agencyAbbreviation) {
        // Add selected agency to the array
        $this.selectedAgencies.push(agencyId);
        
        //Add selected agency to place holder
        var holder = $this.divNoticeSearchAgency;
        
        var elem = $("<div class='noticeSelectedAgency'></div>");
        elem.data("ID", agencyId);
        
        var span = $("<span class='noticeSelectedAgencyName'></span>");
        span.html(agencyAbbreviation);
        
        var removeButton = $("#removeButtonTemplate").clone();
        removeButton.removeAttr("id").show();
        removeButton.data("Id", agencyId);
        removeButton.text(removeButton.text() + " " + agencyAbbreviation);
        removeButton.bind("click", $this.removeAgencyClicked($this));
        
        elem.append(span).append(removeButton);
        holder.append(elem);
        
        if ($this.selectedAgencies.length > 0) {
            $this.divNoticeSearchAgency.show();
        }
        else {
            $this.divNoticeSearchAgency.hide();
        }
    }

    namespace.NoticeSearch.prototype.saveNoticeSearch = function ($this) {
        return function () {
            if ($.trim($("#txtSaveNoticeSearch").val()) === '') {
                $("#saveSearchMessageMissingTitle").show();
            } else {
                $("#saveSearchMessageMissingTitle").hide();
                var opts = $this.searchOptions();
                $.ajax({
                    url: '/Vendor/NoticeSearchFilters/Save',
                    type: 'POST',
                    contentType: 'application/json',
                    data: JSON.stringify(opts),
                    success: function () {
                        $this.showMessage($this.SearchFilterSaved, true);
                        $("#txtSaveNoticeSearch").val('');
                        $this.loadSavedSearches($this);
                    }.bind(this),
                    error: function () {
                        $this.showMessage($this.SearchFilterNotSaved, false);
                    }.bind(this)
                });
            }
        }
    }

    namespace.NoticeSearch.prototype.setDefaultSearch = function (searchId) {
        var isDefault = $(event.target).is(":checked");
        var actionUrl = isDefault ? '/Vendor/NoticeSearchFilters/SetDefault' : '/Vendor/NoticeSearchFilters/SetAsNotDefault';
        $.ajax({
            url: actionUrl,
            type: 'POST',
            contentType: 'application/json',
            data: JSON.stringify({ id: searchId, isDefault: isDefault }),
            success: function () {
                this.loadSavedSearches();
                this.showMessage(this.DefaulSearchSet, true);
            }.bind(this),
            error: function () {
                this.showMessage(this.DefaulSearchNotSet, false);
            }.bind(this)
        });
    };


    namespace.NoticeSearch.prototype.deleteSavedSearch = function (event, $this) {
            var searchId = $(event.target).data("id");
            $.ajax({
                url: '/Vendor/NoticeSearchFilters/Delete',
                type: 'POST',
                contentType: 'application/json',
                data: JSON.stringify({ id: searchId }),
                success: function () {
                    $(event.target).closest('li').remove();
                    this.showMessage(this.SearchFilterDeleted, true);
                }.bind(this),
                error: function () {
                    this.showMessage(this.SearchFilterNotDeleted, false);
                }.bind(this)
            });
    }

    namespace.NoticeSearch.prototype.toggleShareSavedSearch = function (event, $this) {
        var searchId = $(event.target).data("id");
        var isShared = $(event.target).is(":checked");
        var actionUrl = isShared ? '/Vendor/NoticeSearchFilters/Share' : '/Vendor/NoticeSearchFilters/Unshare';
        $.ajax({
            url: actionUrl,
            type: 'POST',
            contentType: 'application/json',
            data: JSON.stringify({ id: searchId }),
            success: function () {
                this.loadSavedSearches($this);
                this.showMessage(this.SearchFilterShare, true);
            }.bind(this),
            error: function () {
                this.showMessage(this.SearchFilterErrorOnShare, false);
            }.bind(this)
        });
    }

    namespace.NoticeSearch.prototype.searchOptions = function () {
        var opts = {
            name: $("#txtSaveNoticeSearch").val(),
            searchJSON: JSON.stringify(this.BuildOptions(this)),
            isShared: true
        };
        return opts;
    }

}(window.UNGM.Notice = window.UNGM.Notice || {}));
;
window.UNGM.Notice.ViewDocument = {
    initFor: function (containerSelector) {
        if ($(containerSelector).get(0)) {
            $(containerSelector).get(0).addEventListener("click", UNGM.Notice.ViewDocument.onViewDocumentClicked, true);
        }
    },
    onViewDocumentClicked: function (event) {
        var target = $(event.target);
        if (target.is(".buttonViewDocuments")) {
            event.stopPropagation();
            $.get(`/Public/Notice/ViewDocument/${target.data("notice-id")}`)
                .done(
                    function (data) {
                        if (data.Url) {
                            window.open(data.Url);
                        } else if (data.AlternativeText) {
                            $.confirm(data.AlternativeText.HeaderText, data.AlternativeText.MainText, data.AlternativeText.ButtonText, "", function () { });
                        }
                    });
        }
    }
};
UNGM.NoticeView = {
    init: function () {
        $(".btnDetailsRevision, #revisionsHolder .editableListItem > span:not(.options)").css("cursor", "pointer").unbind("click").bind("click", UNGM.NoticeView.onRevisionDetailsClicked);
    },
    onRevisionDetailsClicked: function (evt) {
        evt.stopPropagation();
        $details = $(evt.currentTarget).parents(".editableListItem").find(".revisionDetails");

        // Set the textarea heights
        $(".displayTextarea").each(function (i, el) {
            $(el).height(el.scrollHeight);
        });

        var button = $details.prev(".options").find(":button.btnDetailsRevision")
        // Get the corresponding detail div
        $details.slideToggle(function () {
            button.prop("value", $details.is(":visible") ? button.data("hide") : button.data("show"));
        });

        // Set the textarea heights. Not sure why this has to be called twice, but it dowsn't work reliably with only one call. Maybe setting a timeout?
        $(".displayTextarea").each(function (i, el) {
            $(el).height(el.scrollHeight);
        });
    }
};
window.UNGM.Registration = {
    userExists: false,
    init: function () {
        $("#companyBox").bind("focusout", UNGM.Registration.companyLostFocus);
        $("#companyBox").bind("focusin", UNGM.Registration.companyGotFocus);
        $("#btnContinueInactivated").bind("click", UNGM.Registration.activationPendingClicked);
        $("#autoPopulateUserDetails").bind("change", UNGM.Registration.autoPopulateUserDetailsChanged);
        $("#frmVendorRegister").bind("submit", UNGM.Registration.onFormSubmit);

        if ($("#btnContinueInactivated").attr("url") == undefined) {
            $("#btnContinueInactivated").hide();
        }
    },  
    activationPendingClicked: function (evt) {
        window.location.href = $(evt.currentTarget).attr("url");
    },
    companyLostFocus: function (evt) {
        var sender = $(evt.currentTarget);
        var company = sender.val();
        var vendorId = $('#Id').val();
        var obj = { companyName: (unescape(company)).replace(/<\/?[^>]+(>|$)/g, ""), vendorID: vendorId };
        $.ajax({
            url: UNGM.siteRoot + 'Vendor/Registration/IsCompanyAvailable',
            type: 'POST',
            data: JSON.stringify(obj),
            contentType: 'application/json',
            success: UNGM.Registration.onCheckedCompany,
            error: function (xhr, status, error) {
                alert("Error!" + xhr.status);
            }
        });
    },
    onCheckedCompany: function (isAvailable) {
        var box = $("#companyBox");
        if (isAvailable) {
            UNGM.Validation.markElementValid(box);
            $("#companyExists").hide();
            UNGM.Validation.validateElement(box);
        } else {
            UNGM.Validation.markElementInvalid(box);
            $("#companyExists").show();
        }
    },
    companyGotFocus: function (evt) {
        $("#CompanyNameExists").hide();
    },
    autoPopulateUserDetailsChanged: function (e) {
        $checkbox = $(e.currentTarget);

        if ($checkbox.is(":checked")) {
            $("#frmVendorRegister #FirstName").val($("#frmVendorRegister #CompanyDirectorFirstName").val());
            $("#frmVendorRegister #LastName").val($("#frmVendorRegister #CompanyDirectorLastName").val());
        }
        else {
            $("#frmVendorRegister #FirstName,#LastName").val("");
        }
    },
    onFormSubmit: function (e) {
        $("#ConfirmPassword").blur();

        var $form = $(e.currentTarget);
        
        // $form.valid() doesn't work when the error is 'a username exists'
        if (!$form.valid() || !UNGM.EmailValidation.verified) {
            e.preventDefault();
            return false;
        }

        // If it gets here means that we can submit
        UNGM.throbOver($form);
    }
};
;
window.UNGM.UNSPSC = {
    timeoutFunc: null,
    select: "SELECT",
    remove: "REMOVE",
    showSelectRemoveAll: false,
    isReadOnly: false,
    showSelectAsParent: false,
    selectedCodes: [],
    selectParentCode: null,
    saveCallback: null,
    selectCallBack: null,
    alreadySavedCodes: [],
    selectCodesAfterSearch: null,
    asrYear: null,
    pendingSearchRequest: null,
    keyCode: Object.freeze({
        LEFT: 37,
        UP: 38,
        RIGHT: 39,
        DOWN: 40,
        ENTER: 13,
        TAB:9
    }),
    init: function () {
        $(".nodeName.expandable, .nodeName.expanded").off("click").on("click", UNGM.UNSPSC.nodeClicked);
        $(".txtSearchUnspsc").off("keyup").on("keyup", UNGM.UNSPSC.filterKeyUp);
        $(".chkUnspsc").off("change").on("change", UNGM.UNSPSC.checkboxChanged);
        $(".btnSaveUnspsc").off("click").on("click", UNGM.UNSPSC.saveClicked);
        $(".lnkRemoveUnspsc").off("click").on("click", UNGM.UNSPSC.removeButtonClicked);
        $(".lnkUspscRemoveAll").off("click").on("click", UNGM.UNSPSC.removeAllClicked);
        $(".unspscTree").off("click").on("click", ".lnkUspscRemoveChildren", { select: UNGM.UNSPSC.remove }, UNGM.UNSPSC.selectOrRemoveChildrenClicked);
        $(".unspscTree").off("click").on("click", ".lnkUspscSelectChildren", { select: UNGM.UNSPSC.select }, UNGM.UNSPSC.selectOrRemoveChildrenClicked);
        $(".lnkUspscSelectParent").off("click").on("click", UNGM.UNSPSC.selectCodeAsParent);
        $(".lnkExpandAll").off("click").on("click", UNGM.UNSPSC.expandAllClicked);
        $(".lnkCollapseAll").off("click").on("click", UNGM.UNSPSC.collapseAllClicked);
        UNGM.UNSPSC.updateUnspscSelectedCodeHeight();

        $(".nodeName:first").attr("tabindex", 0);
        $(".unspsc").on("keydown", ".nodeName", UNGM.UNSPSC.nodeKeyDown);
    },
    getSelectedCodes: function (picker) {
        UNGM.UNSPSC.selectedCodes = picker.find(".unspscSelectedCodes").data("codes");
    },
    setSelectedCodes: function (picker) {
        picker.find(".unspscSelectedCodes").data("codes", UNGM.UNSPSC.selectedCodes);
    },
    removeCode: function (removedId) {
        // remove it from the picker array UNGM.UNSPSC.selectedCodes
        for (var i = 0; i < UNGM.UNSPSC.selectedCodes.length; i++) {
            if (UNGM.UNSPSC.selectedCodes[i].Id == removedId) {
                UNGM.UNSPSC.selectedCodes.splice(i, 1);
            }
        }
    },
    nodeClicked: function (evt) {
        var sender = $(evt.currentTarget);
        var appendTo;
        if (sender.siblings(".selectRemoveAll").length > 0) {
            appendTo = sender.siblings(".selectRemoveAll");
        }
        else if (sender.siblings(".selectAsParent").length > 0) {
            appendTo = sender.siblings(".selectAsParent");
        }
        else {
            appendTo = sender;
        }
        var existingChildren = sender.siblings(".unspscChildren");
        if (existingChildren.length > 0) {
            if (existingChildren.is(":visible")) {
                existingChildren.hide();
                sender.removeClass("expanded").addClass("expandable");
                sender.attr("aria-expanded", false);
            }
            else {
                existingChildren.show();
                sender.removeClass("expandable").addClass("expanded");
                sender.attr("aria-expanded", true);
            }
            UNGM.UNSPSC.updateUnspscSelectedCodeHeight();
        }
        else {
            var nodeId = sender.data("nodeid");
            var picker = sender.parents(".unspsc");
            UNGM.throbOver(picker);
            $.ajax({
                url: UNGM.siteRoot + 'UNSPSC/Children/' + nodeId
                    + "?showSelectRemoveAll=" + UNGM.UNSPSC.showSelectRemoveAll
                    + "&isReadOnly=" + UNGM.UNSPSC.isReadOnly
                    + "&showSelectAsParent=" + UNGM.UNSPSC.showSelectAsParent
                    + "&isASRUNSPSC=" + (UNGM.UNSPSC.asrYear != null && UNGM.UNSPSC.asrYear != 0),
                type: 'GET',
                success: function (data) {
                    var elem = $("<div class='unspscChildren'></div");
                    elem.append(data);
                    appendTo.after(elem);
                    elem.find(".chkUnspsc").bind("change", UNGM.UNSPSC.checkboxChanged);
                    sender.removeClass("expandable").addClass("expanded");
                    sender.attr("aria-expanded", true);
                    $(".nodeName.expandable, .nodeName.expanded").off("click").on("click", UNGM.UNSPSC.nodeClicked);
                    $(".lnkUspscSelectParent").off("click").on("click", UNGM.UNSPSC.selectCodeAsParent);
                    // Check the codes in the tree
                    UNGM.UNSPSC.checkUncheckCodesInTree(picker);
                    UNGM.UNSPSC.updateUnspscSelectedCodeHeight();
                    UNGM.hideThrobber();
                }
            });
        }
    },
    filterKeyUp: function (evt) {
        if (UNGM.UNSPSC.timeoutFunc) {
            clearTimeout(UNGM.UNSPSC.timeoutFunc);
        }
        UNGM.UNSPSC.timeoutFunc = setTimeout(function () {
            UNGM.UNSPSC.search(evt);
        }, 600);
    },
    search: function (evt) {
        if (UNGM.UNSPSC.pendingSearchRequest) {
            UNGM.UNSPSC.pendingSearchRequest.abort();
        }

        var sender = $(evt.currentTarget);
        var appendTo;
        if (sender.parents(".unspsc").find(".selectAsParent").length > 0) {
            appendTo = sender.parents(".unspsc").find(".selectAsParent")[0];
        }
        var picker = sender.parents(".unspsc");
        var searchText = sender.val();

        // /i means: canse insensitive
        if (searchText.match(/^unselect:/i)) {
            UNGM.UNSPSC.selectCodesAfterSearch = false;
            searchText = searchText.replace(/unselect:/i, '');
        }
        else if (searchText.match(/^select:/i)) {
            UNGM.UNSPSC.selectCodesAfterSearch = true;
            searchText = searchText.replace(/select:/i, '');
        }

        if (searchText == null || searchText == '' || (UNGM.UNSPSC.asrYear != null && UNGM.UNSPSC.asrYear != 0 && searchText.length < 4)) {
            picker.find(".unspscTree").show();
            picker.find(".unspscSearchResults").hide();
            picker.find(".unspscNoResults").hide();
        }
        else {
            picker.find(".unspscTree").hide();
            UNGM.throbOver(picker);
            UNGM.UNSPSC.pendingSearchRequest = $.ajax({
                url: UNGM.siteRoot + 'UNSPSC/Search',
                type: 'POST',
                data: {
                    filter: searchText,
                    isReadOnly: UNGM.UNSPSC.isReadOnly,
                    showSelectAsParent: UNGM.UNSPSC.showSelectAsParent,
                    alreadySavedCodes: UNGM.UNSPSC.alreadySavedCodes,
                    asrYear: UNGM.UNSPSC.asrYear
                },
                success: function (data) {
                    UNGM.UNSPSC.onGotSearch(data, picker, searchText);
                    $(".nodeName:first").attr("tabindex", 0);
                }
            });
        }
        // append selectAsParent to every node except level rank 5
        var tree = picker.find(".unspscTree");
        $(tree).find('*[data-isparent="True"]').each(function () {
            var cur = $(this);
            if ($(this).siblings(".selectAsParent").length < 1) {
                appendTo.after($(this));
            }
        });
    },
    onGotSearch: function (data, picker, searchText) {
        if (data && data.trim().length > 0) {
            picker.find(".unspscSearchResults").html(data).show().find(".chkUnspsc").bind("change", UNGM.UNSPSC.checkboxChanged);
            picker.find(".unspscSearchResults").find(".nodeName.expanded").bind("click", UNGM.UNSPSC.nodeClicked);
            picker.find(".unspscSearchResults").find(".lnkUspscSelectParent").off("click").on("click", UNGM.UNSPSC.selectCodeAsParent);
            picker.find(".unspscNoResults").hide();

            // Check the codes of the result
            UNGM.UNSPSC.checkUncheckCodesInTree(picker);
        }
        else {
            picker.find(".unspscNoResults").show();
            picker.find(".unspscSearchResults").hide();
        }

        // Functionality to bulk select/unselect codes
        if (UNGM.UNSPSC.selectCodesAfterSearch !== null) {
            var allCodesInFilter = $.map(searchText.split(','), $.trim);
            UNGM.UNSPSC.getSelectedCodes(picker);

            for (var index = 0; index < allCodesInFilter.length; index++) {
                var $codeCbx = $("input[data-unspscode='" + allCodesInFilter[index] + "']");

                if ($codeCbx.length > 0) {
                    var codeInFilter = {
                        Id: $codeCbx.data("unspscid"),
                        Code: $codeCbx.data("unspscode"),
                        Name: $codeCbx.parent().siblings(".nodeName").html().replace($codeCbx.data("unspscode") + ' - ', '')
                    };

                    if (UNGM.UNSPSC.selectCodesAfterSearch == true) {
                        if ($codeCbx.is(":checked") == false) {
                            $codeCbx.prop("checked", true);
                            UNGM.UNSPSC.selectedCodes.push(codeInFilter);
                        }
                    }
                    else {
                        if ($codeCbx.is(":checked") == true) {
                            $codeCbx.prop("checked", false);
                            for (var i = 0; i < UNGM.UNSPSC.selectedCodes.length; i++) {
                                if (UNGM.UNSPSC.selectedCodes[i].Id == codeInFilter.Id) {
                                    UNGM.UNSPSC.selectedCodes.splice(i, 1);
                                }
                            }
                        }
                    }
                }
            }

            UNGM.UNSPSC.bindSelectedCodes(picker);
            UNGM.UNSPSC.selectCodesAfterSearch = null;
        }
        UNGM.hideThrobber();
    },
    checkboxChanged: function (evt) {
        var sender = $(evt.currentTarget);
        var picker = sender.parents(".unspsc");
        var unspscid = sender.data("unspscid");
        var unspscode = sender.data("unspscode");
        var name = sender.parent().siblings(".nodeName").find("span:last").html();
        name = name.replace(unspscode + ' - ', '');
        var selectedCode = {
            Id: unspscid,
            Code: unspscode,
            Name: name
        };
        UNGM.UNSPSC.getSelectedCodes(picker);

        if (sender.is(":checked")) {
            for (var i = 0; i < UNGM.UNSPSC.selectedCodes.length; i++) {
                if (UNGM.UNSPSC.selectedCodes[i].Id == unspscid) {
                    return; // code is already there so do nothing
                }
            }
            UNGM.UNSPSC.selectedCodes.push(selectedCode);
        }
        else {
            for (var i = 0; i < UNGM.UNSPSC.selectedCodes.length; i++) {
                if (UNGM.UNSPSC.selectedCodes[i].Id == unspscid) {
                    UNGM.UNSPSC.selectedCodes.splice(i, 1);
                }
            }
        }
        UNGM.UNSPSC.bindSelectedCodes(picker);
    },
    bindSelectedCodes: function (picker) {
        var holder = picker.find(".unspscSelectedCodeTree");
        holder.empty();

        UNGM.UNSPSC.getSelectedCodes(picker);
        if (UNGM.UNSPSC.selectedCodes) {
            UNGM.UNSPSC.selectedCodes = UNGM.UNSPSC.selectedCodes.sort(UNGM.UNSPSC.sortComparer);
        }

        if (UNGM.UNSPSC.selectedCodes) {
            for (var i = 0; i < UNGM.UNSPSC.selectedCodes.length; i++) {
                var elem = $("<div class='unspscSelectedCode'></div>");
                var span = $("<span class='unspscSelectedCodeName'></span>");
                var removeButton = $("#removeButtonTemplate").clone();
                var deleted = "";
                removeButton.removeAttr("id").show();
                removeButton.data("unspscid", UNGM.UNSPSC.selectedCodes[i].Id);
                span.html(UNGM.UNSPSC.selectedCodes[i].Code + " - " + UNGM.UNSPSC.selectedCodes[i].Name);
                if (UNGM.UNSPSC.selectedCodes[i].IsDeleted) {
                    span.addClass("unspscDeleted");
                    deleted = $("<span class='unspscDeletedInfo'></span>");
                }
                removeButton.bind("click", UNGM.UNSPSC.removeButtonClicked);
                removeButton.text(removeButton.text() + " " + UNGM.UNSPSC.selectedCodes[i].Code + " - " + UNGM.UNSPSC.selectedCodes[i].Name);
                elem.append(span).append(deleted).append(removeButton);
                holder.append(elem);
            }
        }

        if (UNGM.UNSPSC.selectedCodes && UNGM.UNSPSC.selectedCodes.length > 0) {
            picker.find(".unspscNoCodes").hide();
        }
        else {
            picker.find(".unspscNoCodes").show();
        }
        $("#codeCount").html(UNGM.UNSPSC.selectedCodes ? UNGM.UNSPSC.selectedCodes.length : "");
        UNGM.UNSPSC.checkUncheckCodesInTree(picker);
        UNGM.UNSPSC.setSelectedCodes(picker);
    },
    removeButtonClicked: function (evt) {
        var sender = $(evt.currentTarget);
        var picker = sender.parents(".unspsc");
        var unspscid = sender.data("unspscid");
        UNGM.UNSPSC.getSelectedCodes(picker);
        if (UNGM.UNSPSC.selectedCodes) {
            for (var i = 0; i < UNGM.UNSPSC.selectedCodes.length; i++) {
                if (UNGM.UNSPSC.selectedCodes[i].Id == unspscid) {
                    UNGM.UNSPSC.selectedCodes.splice(i, 1);
                }
            }
        }
        UNGM.UNSPSC.setSelectedCodes(picker);
        UNGM.UNSPSC.bindSelectedCodes(picker);
    },
    saveClicked: function (evt) {
        var picker = $(evt.currentTarget).parents(".unspsc");
        if (!UNGM.UNSPSC.saveCallback) {
            throw ("the UNGM.UNSPSC.saveCallback property must be set in order to use the 'save selected codes' button in this control");
        }
        UNGM.UNSPSC.getSelectedCodes(picker);
        UNGM.UNSPSC.saveCallback(evt);
    },
    removeAllClicked: function (evt) {
        var picker = $(evt.currentTarget).parents(".unspsc");
        UNGM.UNSPSC.selectedCodes = [];
        UNGM.UNSPSC.setSelectedCodes(picker);
        UNGM.UNSPSC.bindSelectedCodes(picker);
    },
    selectOrRemoveChildrenClicked: function (evt) {
        UNGM.throbOver($(".unspsc"));
        var picker = $(evt.currentTarget).parents(".unspsc");
        // get the children from the server
        var codeId = $(evt.currentTarget).data("unspscid")
        $.ajax({
            url: UNGM.siteRoot + 'UNSPSC/GetChildren?id=' + codeId,
            type: 'GET',
            contentType: 'application/json',
            success: function (data) {
                UNGM.UNSPSC.onGotChildrenForSelectOrRemove(data, picker, evt.data.select);
            }
        });
    },
    onGotChildrenForSelectOrRemove: function (children, picker, select) {
        // get the current ids
        UNGM.UNSPSC.getSelectedCodes(picker);
        var currentIds = [];
        // for some reason $.map isn't working here. So do it the old fashioned way.
        $.each(UNGM.UNSPSC.selectedCodes, function (index, value) {
            currentIds.push(value.Id);
        });
        for (var i = 0; i < children.length; i++) {
            if (select == UNGM.UNSPSC.select) {
                // push
                if ($.inArray(children[i].Id, currentIds) == -1) {
                    UNGM.UNSPSC.selectedCodes.push(children[i]);
                };
            } else {
                // pop
                UNGM.UNSPSC.selectedCodes = $.map(UNGM.UNSPSC.selectedCodes, function (u) { if (u.Id != children[i].Id) { return u; } });
            }
        }
        // set the codes for the picker
        UNGM.UNSPSC.setSelectedCodes(picker);
        //bind the new code set to the UI
        UNGM.UNSPSC.bindSelectedCodes(picker);
        UNGM.hideThrobber();
    },
    sortComparer: function (a, b) {
        if (a.Code < b.Code) return -1;
        if (a.Code > b.Code) return 1;
        return 0;
    },
    expandAllClicked: function (evt) {
        var picker = $(evt.currentTarget).parents(".unspscSelector");
        picker.find(".expandable").click();
    },
    collapseAllClicked: function (evt) {
        var picker = $(evt.currentTarget).parents(".unspscSelector");
        picker.find(".expanded").each(function () {
            var existingChildren = $(this).siblings(".unspscChildren");
            if (existingChildren.length > 0) {
                existingChildren.hide();
                $(this).removeClass("expanded").addClass("expandable");
                $(this).focus();
            }
        });
    },
    checkUncheckCodesInTree: function (picker) {
        UNGM.UNSPSC.getSelectedCodes(picker);
        picker.find(".chkUnspsc").prop("checked", false);
        if (UNGM.UNSPSC.selectedCodes) {
            for (var i = 0; i < UNGM.UNSPSC.selectedCodes.length; i++) {
                picker.find(".chkUnspsc[data-unspscid=" + UNGM.UNSPSC.selectedCodes[i].Id + "]").prop("checked", true);
            }
        }
    },
    selectCodeAsParent: function (evt) {
        var sender = $(evt.currentTarget);
        if (!UNGM.UNSPSC.selectCallBack) {
            throw ("the UNGM.UNSPSC.selectCallBack property must be set in order to use the 'select as parent' function");
        }
        var unspscid = sender.data("unspscid");
        var unspscode = sender.data("unspscode");
        var rank = sender.data("rank");
        var name = sender.parent().siblings(".nodeName").html();
        name = name.replace(unspscode + ' - ', '');
        var selectedCode = {
            Id: unspscid,
            Code: unspscode,
            Rank: rank,
            Name: name
        };
        UNGM.UNSPSC.selectParentCode = selectedCode;
        var test = "";
        UNGM.UNSPSC.selectCallBack(evt);
    },
    updateUnspscSelectedCodeHeight: function () {
        $(".unspscSelectedCodeTree").height($(".unspscSearchBar").height() + $(".unspscTree").height());
    },
    nodeKeyDown: function(e) {
        var currentNode = $(e.currentTarget);
        var currentNodeIndex = $(".nodeName:visible").index(currentNode);
        var nodesCount = $(".nodeName:visible").length;

        switch (e.keyCode) {
            case UNGM.UNSPSC.keyCode.UP:
                $('.chkUnspsc').attr('tabindex', 0);
                e.preventDefault();
                UNGM.UNSPSC.focusPreviousNode(currentNode, currentNodeIndex);

                break;

            case UNGM.UNSPSC.keyCode.DOWN:
                $('.chkUnspsc').attr('tabindex', 0);
                e.preventDefault();
                UNGM.UNSPSC.focusNextNode(currentNode, currentNodeIndex, nodesCount);

                break;
                
            case UNGM.UNSPSC.keyCode.LEFT:
                $('.chkUnspsc').attr('tabindex', 0);
                if (currentNode.hasClass("expanded")) {
                    UNGM.UNSPSC.nodeClicked(e);
                } else {
                    UNGM.UNSPSC.focusParentNode(currentNode, currentNodeIndex);
                }

                break;

            case UNGM.UNSPSC.keyCode.RIGHT:
                $('.chkUnspsc').attr('tabindex', 0);
                if (currentNode.hasClass("expandable")) {
                    UNGM.UNSPSC.nodeClicked(e);
                } else if (currentNode.hasClass("expanded")) {
                    UNGM.UNSPSC.focusNextNode(currentNode, currentNodeIndex, nodesCount);
                }

                break;

            case UNGM.UNSPSC.keyCode.TAB:
                $('.chkUnspsc').attr('tabindex', -1);

                break;

            case UNGM.UNSPSC.keyCode.ENTER:
                e.preventDefault();
                if (!document.hasFocus() || !document.activeElement) {
                    return;
                }
                var input = document.getElementsByClassName('chkUnspsc');
                var focusList = $('a[href], area[href], input, select, textarea, button, iframe, object, embed, *[tabindex], *[contenteditable]')
                    .not('[tabindex=-1], [disabled], :hidden');
                var i = focusList.index(document.activeElement);
                if (i < 0) {
                    focusList[0].focus(); // nothing is focussed so go to list item 0
                } else if (i - 1 > -1) {
                    console.log(i);
                    focusList[i - 1].click(); // click the current checkbox
                }

                break;
        }
    }, 
    focusNextNode: function (currentNode, currentNodeIndex, nodesCount) {
        if (currentNodeIndex + 1 === nodesCount) {
            return;
        }

        var nextNode = $(".nodeName:visible").eq(currentNodeIndex + 1);
        currentNode.attr("tabindex", -1);
        nextNode.attr("tabindex", 0);
        nextNode.focus();
    },
    focusPreviousNode: function (currentNode, currentNodeIndex) {
        if (currentNodeIndex === 0) {
            return;
        }

        var prevNode = $(".nodeName:visible").eq(currentNodeIndex - 1);
        currentNode.attr("tabindex", -1);
        prevNode.attr("tabindex", 0);
        prevNode.focus();
    },
    focusParentNode: function (currentNode, currentNodeIndex) {
        if (currentNodeIndex === 0) {
            return;
        }

        var parentNode = currentNode.parent().parent().prev();
        currentNode.attr("tabindex", -1);
        parentNode.attr("tabindex", 0);
        parentNode.focus();
    }
}
;
window.UNGM.OrganizationUserAccountRegistration = {
    emailInvalid: true,
    init: function() {
        $("#Password").bind("keyup", UNGM.ManageAccount.onPasswordKeyUp);
        $("form").bind("focusin", UNGM.removeError);
        $("form").bind("submit", UNGM.OrganizationUserAccountRegistration.validateForm);
        $("#btnAcceptStandardsOfConduct").bind("click", UNGM.OrganizationUserAccountRegistration.acceptStandardsOfConduct);
    },
    validateForm: function (e) {
        e.preventDefault();
        var form = $("#frmOrganizationUser");

        if (form.valid() && UNGM.EmailValidation.verified) {
            grecaptcha.execute();
            console.log("validating");
            return true;
        }

        return false;
    },
    submitForm: function () {
        var form = $("#frmOrganizationUser");
        
        UNGM.throbOver();
        $.ajax({
            url: form.attr("action"),
            type: 'POST',
            data: form.serialize(),
            global: false, // Disable global events, as UNGM.ajaxErrorHandler 
            success: function () {
                window.location = UNGM.siteRoot + "Account/Registration/ActivatePending";
            },
            error: function (response) {
                UNGM.appendErrorTo(form, response.responseJSON);
                UNGM.hideThrobber();
            }
        });
    },
    acceptStandardsOfConduct: function() {
        $(".organization-registration-step1").hide();
        $(".organization-registration-step2").show();
    }
};
window.UNGM.VendorRegistration = {
    currentVendorId: 0,
    selectedExportCountries: [],
    hasGeneralCountryChanged: false,
    hasIndividualConsultantTypeChanged: false,
    isAssistedRegistration: false,
    companyNameIsAvailable: true,
    completionPercent: 1,
    isUnspscTabInitialized: false,
    submittingAgencyIds: null,
    tenderAlertServiceTabCallback: null,
    init: function (completionModel) {
        $(".tabHeader").bind("click", UNGM.VendorRegistration.onTabClicked);
        $("#Unspsc").on("click", UNGM.VendorRegistration.initUnspscTab);

        $(".tab:not(#vr-unspsc-panel)").on("submit", "form", UNGM.VendorRegistration.onFormSubmitted);
        $(".tabs").on("focusin", "form :input", UNGM.removeError);
        $(".tabs").on("click", "[name='DeclarationOfEligibility']", UNGM.VendorRegistration.declarationOfEligibilityClicked);
        $(".tabs").on("click", "[name='RegistrationType']", UNGM.VendorRegistration.registrationTypeClicked);
        $(".tabs").on("change", "#DummyCountryId", UNGM.VendorRegistration.onExportCountrySelected);
        $(".tabs").on("click", "#selectAllCountries", UNGM.VendorRegistration.onSelectAllCountriesClicked);
        $(".tabs").on("click", "#removeAllCountries", UNGM.VendorRegistration.onRemoveAllCountriesClicked);

        if (UNGM.VendorRegistration.isAssistedRegistration) {
            UNGM.tabContentReceivedCallback = UNGM.AssistedRegistration.onTabContentReceived;
        } else {
            UNGM.tabContentReceivedCallback = UNGM.VendorRegistration.tabContentReceivedCallback;
        }

        $(".back-to-previous-step").off("click").on("click", UNGM.VendorRegistration.goToPreviousTab);

        $("#vendor-registration-steps .progress-steps__step-actions").off("click").on("click", UNGM.VendorRegistration.goToCorrespondingTab);

        UNGM.VendorRegistration.setBirthdateDatepicker();

        // Change company name & contacts tab funcionalitiy
        $(".tabs").on("click", "#btnInviteUser", UNGM.VendorRegistration.inviteUser);
        $(".tabs").on("click", ".btnCancelInvitation", UNGM.VendorRegistration.cancelInvite);
        $(".tabs").on("click", ".btnResendInvitation", UNGM.VendorRegistration.resendInvitation);
        $(".tabs").on("click", "#tblContacts tbody tr", UNGM.VendorRegistration.showDetails);
        $(".tabs").on("click", ".btnEditContact", UNGM.VendorRegistration.editContact);
        $(".tabs").on("click", ".btnSetAsPrimaryContact", UNGM.VendorRegistration.setAsPrimaryContact);
        $(".tabs").on("click", ".btnDeleteContact", UNGM.VendorRegistration.deleteContact);
        $(".btnChangeName").off("click").on("click", UNGM.VendorRegistration.changeName);
        $("#CompanyName").on("focusout", UNGM.VendorRegistration.companyNameFocusOut);
        $("#ChangeCompanyBox").on("focusout", UNGM.VendorRegistration.changeCompanyNameLostFocus);
        $("#ChangeCompanyBox").on("focusin", UNGM.VendorRegistration.companyGotFocus);
        $("#Comments").on("focusout", UNGM.VendorRegistration.commentsLostFocus);
        $("#btnSaveChangeName").off("click").on("click", UNGM.VendorRegistration.saveChangeName);
        $("#Reason").on("change", UNGM.VendorRegistration.reasonChange);
        $("#btnAcceptRegistration").off("click").on("click", UNGM.VendorRegistration.acceptRegistrationInvitation);
        $("#GeneralCountryId").on("change", UNGM.VendorRegistration.checkCountryAndFiscalCodeUnique);
        $("#FiscalCode").on("focusout", UNGM.VendorAccountRegistration.checkCountryAndFiscalCodeUnique);
        // Submission        
        $("#btnResubmitRegistration").off("click").on("click", UNGM.VendorRegistration.resubmitRegistration);
        $("#ParentCompany").autocompleteNoConflict({
            serviceUrl: UNGM.siteRoot + 'Vendor/Registration/GetParentSuggestions',
            minChars: 5,
            deferRequestBy: 500
        });
        $("input[name=IndividualConsultantTypeId]:radio").on("click", UNGM.VendorRegistration.onIndividualConsultantTypeClicked);

        $('[name=OwnershipType]').change(UNGM.VendorRegistration.onCompanyOwnershipTypeChanged);
        $('[name=WomenOwnership]').change(UNGM.VendorRegistration.onCompanyWomenOwnershipChanged);
        UNGM.VendorRegistration.onCompanyOwnershipTypeChanged();

        $('#TenderAlertServiceTab').click(UNGM.VendorRegistration.onTenderAlertServiceTabClicked);
        $('#btnViewSanction').off("click").on("click", UNGM.VendorRegistration.showSanctions);

        UNGM.VendorRegistration.updateCompletion(completionModel);

        UNGM.VendorRegistration.showSpecificTabIfAny();
    },
    showSpecificTabIfAny: function() {
        var parameter = "#tab=";
        if (window.location.href.indexOf(parameter) !== -1) {
            var index1 = window.location.href.indexOf(parameter) + parameter.length;
            var index2 = window.location.href.indexOf("&", index1);
            if (index2 === -1) {
                index2 = window.location.href.length;
            }
            var tabId = window.location.href.substring(index1, index2);

            if (tabId.length) {
                UNGM.VendorRegistration.goToTab($(".tab[data-tab='" + tabId + "']"));
            }
        }
    },
    initUnspscTab: function () {
        if (!UNGM.VendorRegistration.isUnspscTabInitialized) {
            UNGM.VendorRegistration.isUnspscTabInitialized = true;
            uvm.bootstrap('#vr-unspsc-panel', ['UNGM.Vendor.Registration']);
        }
    },
    setBirthdateDatepicker: function () {
        $("[name='Birthdate']").datepicker({
            maxDate: 0,
            changeMonth: true,
            changeYear: true,
            yearRange: "-100:+0",
            onSelect: function () {
                if ($("[name='Birthdate']").val().length > 0) {
                    UNGM.Validation.validateElement($("[name='Birthdate']"));
                }
                UNGM.Validation.validateElement($(this));
            }
        });
    },
    tabContentReceivedCallback: function (tabElement) {
        if (tabElement.find("#VendorRegistrationTypeInfo").length) {
            UNGM.VendorRegistration.bindExportCountries();
        }

        UNGM.Validation.initForElement(tabElement.find("form"));
        UNGM.markRequiredFields();
        $(".back-to-previous-step").off("click").on("click", UNGM.VendorRegistration.goToPreviousTab);
    },
    registrationTypeClicked: function (e) {
        if ($(this).val() === "National") {
            $("#exportToCountrySelector").hide(300);
            $("[name='CountryIds']").remove();
            UNGM.VendorRegistration.selectedExportCountries = [];
        } else {
            $("#exportToCountrySelector").show(300);
        }
        // rebind the countries
        UNGM.VendorRegistration.bindExportCountries();
    },
    onExportCountrySelected: function (e) {
        var sender = $(e.currentTarget);
        var countryId = sender.val();
        if (countryId == '') {
            return;
        }
        var countryName = sender.children(':selected').text();

        var country = {
            Id: countryId,
            Name: countryName
        };
        // Check if the country is already in the list
        if ($.grep(UNGM.VendorRegistration.selectedExportCountries, function (e) { return e.Id == country.Id; }).length == 0 && country.Id.length) {
            UNGM.VendorRegistration.selectedExportCountries.push(country);
            UNGM.VendorRegistration.bindExportCountries();
        }
        // HACK: doing this immediately doesn't work for some reason (due to plugin) so wait a little before clearing text
        setTimeout(' $("#DummyCountryId").val(""); $("#exportToCountryPickerHolder input").val("").focus();', 200);
    },
    bindExportCountries: function () {
        // Render the countries on the page
        var holder = $("#exportToCountryHolder");
        holder.empty();
        $("[name='CountryIds']").remove();

        if (UNGM.VendorRegistration.selectedExportCountries.length === 0) {
            $("#exportToCountryNoCountries").show();
            $("#exportToCountryHolder").css('height', '0'); // Hack for IE
        } else {
            $("#exportToCountryNoCountries").hide();
            for (var i = 0; i < UNGM.VendorRegistration.selectedExportCountries.length; i++) {
                holder.append(UNGM.VendorRegistration.renderExportCountry(UNGM.VendorRegistration.selectedExportCountries[i]));
            }
            $("#exportToCountryHolder").css('height', ''); // Hack for IE
        }
    },
    renderExportCountry: function (country) {
        var elem = $("<div class='exportToCountry editableListItem'></div>");
        var name = $("<span class='exportToCountryName'></span>");
        var options = $("<span class='options'></span>");
        if (!UNGM.VendorRegistration.countriesReadonly) {
            var remove = $("<a href='javascript:;' class='btn btn-small'>" + UNGM.VendorRegistration.removeCountryButtonText + "</a>");
            remove.data("countryId", country.Id);
            remove.bind("click", UNGM.VendorRegistration.removeExportCountry);
            options.append(remove);
        }

        name.html(country.Name);
        var newCountryHidden = $("<input type='hidden' value='" + country.Id + "' name='CountryIds'/>");
        var clearElement = $("<div class='clear'></div>");
        elem.append(name).append(options).append(newCountryHidden).append(clearElement);
        return elem;
    },
    removeExportCountry: function (evt) {
        var sender = $(evt.currentTarget);
        var countryId = sender.data("countryId");

        for (var i = 0; i < UNGM.VendorRegistration.selectedExportCountries.length; i++) {
            if (UNGM.VendorRegistration.selectedExportCountries[i].Id == countryId) {
                UNGM.VendorRegistration.selectedExportCountries.splice(i, 1);
            }
        }
        UNGM.VendorRegistration.bindExportCountries();
    },
    onRemoveAllCountriesClicked: function () {
        UNGM.VendorRegistration.selectedExportCountries = [];
        UNGM.VendorRegistration.bindExportCountries();
    },
    onSelectAllCountriesClicked: function () {
        UNGM.VendorRegistration.selectedExportCountries = [];
        $("#DummyCountryId option:not(:first)").each(function (i, o) {
            var country = {
                Id: $(o).val(),
                Name: $(o).text()
            };
            UNGM.VendorRegistration.selectedExportCountries.push(country);
        });
        UNGM.VendorRegistration.bindExportCountries();
    },
    declarationOfEligibilityClicked: function () {
        if ($(this).val() === "Yes") {
            $("#eligibilityCommentsDiv").hide();
        } else {
            $("#eligibilityCommentsDiv").show();
        }
    },
    onFormSubmitted: function (e) {
        e.preventDefault();
        var form = $(e.currentTarget);

        if (!form.valid()) {
            return false;
        }
        if (form.attr('id') === "frmGeneral") {
            if (UNGM.VendorAccountRegistration.countryAndFiscalCodeInvalid
                || !UNGM.VendorRegistration.companyNameIsAvailable) {
                return false;
            }
            if ((UNGM.VendorRegistration.hasGeneralCountryChanged === true
                || UNGM.VendorRegistration.hasIndividualConsultantTypeChanged === true)
                && UNGM.VendorRegistration.AtLeastOneActiveSubmission) {
                UNGM.VendorRegistration.saveAndConfirmCountryOrIndividualConsultantTypeChange();
                return;
            }
        }

        UNGM.VendorRegistration.submitForm(form);
    },
    submitForm: function (form) {
        UNGM.Throbber.Push();
        $.ajax({
            url: form.attr("action"),
            type: "POST",
            data: form.serialize(),
            global: false,
            success: function (response) {
                if (form.find("#Surname").length) {
                    // Reload declaration of eligibility
                    $("#vr-declaration-panel").data("reload", true);
                }

                var hasJustBeenCreated = response.id !== null && response.id > 0;
                if (UNGM.VendorRegistration.isAssistedRegistration && hasJustBeenCreated) {
                    UNGM.AssistedRegistration.reloadPage(response.id);
                    return;
                }

                UNGM.VendorRegistration.updateCompletion(response);
            },
            error: function (response) {
                UNGM.appendErrorTo(form, response.responseJSON);
            },
            complete: UNGM.Throbber.Pop
        });
    },
    goToTab: function (tab) {
        var currentActive = $(".tab.step-tab-active");
        currentActive.removeClass("step-tab-active");
        tab.addClass("step-tab-active");
        UNGM.VendorRegistration.setCurrentStep(tab);
        window.scrollTo(0, 0);

        if (tab.data("tab") === "general-tab") {
            return;
        }

        if (tab.data("tab") === "unspsc-tab") {
            UNGM.VendorRegistration.initUnspscTab();
            return;
        }

        if (tab.data("tab") === "what-next-tab") {
            UNGM.VendorRegistration.tenderAlertServiceTabCallback();
            return;
        }

        UNGM.reloadTab(tab);
    },
    goToCorrespondingTab: function(e) {
        var sender = $(e.currentTarget);
        var parent = sender.closest("#vendor-registration-steps .progress-steps__step");

        UNGM.VendorRegistration.goToTab($(".tab[data-tab='" + parent.data("tab") + "']"));
    },
    goToPreviousTab: function (e) {
        var currentActive = $(".tab.step-tab-active");
        var previousTab = currentActive.prev();
        UNGM.VendorRegistration.goToTab(previousTab);
    },
    updateCompletion: function (response) {
        if (response.completion === 100) {
            var isSubmissionBlockForDuplication = UNGM.VendorRegistration.isAssistedRegistration ? false : response.isSubmissionBlockForDuplication;
            if (isSubmissionBlockForDuplication) {
                $("#duplicateWarning").show();
            }
            $("#btnResubmitRegistration").removeProp('disabled');
            $(".incomplete-registration").removeClass('incomplete-registration').addClass('complete-registration');
        } else {
            $("#duplicateWarning").hide();
            $("#btnResubmitRegistration").prop('disabled', true);
            $(".complete-registration").removeClass('complete-registration').addClass('incomplete-registration');
        }

        var lastActiveStep = UNGM.VendorRegistration.findLastActiveStep(response);
        UNGM.VendorRegistration.goToTab($(".tab[data-tab='" + lastActiveStep.data("tab") + "']"));
    },
    findLastActiveStep: function (response) {
        var lastActiveStep = $(".general-info-step");
        if (response.generalTabComplete) {
            lastActiveStep = $(".address-step");
            lastActiveStep.addClass("progress-steps__step--active");

        } else {
            return lastActiveStep;
        }

        if (response.addressTabComplete) {
            lastActiveStep = $(".registration-type-step");
            lastActiveStep.addClass("progress-steps__step--active");
        } else {
            return lastActiveStep;
        }

        if (response.nationalTabComplete) {
            lastActiveStep = $(".contact-step");
            lastActiveStep.addClass("progress-steps__step--active");
        } else {
            return lastActiveStep;
        }

        if (response.contactTabComplete) {
            lastActiveStep = $(".unspsc-step");
            lastActiveStep.addClass("progress-steps__step--active");
        } else {
            return lastActiveStep;
        }

        if (response.codingTabComplete) {
            if (UNGM.VendorRegistration.isAssistedRegistration) {
                lastActiveStep = $(".documents-step");
                lastActiveStep.addClass("progress-steps__step--active");
                return lastActiveStep;
            } else {
                lastActiveStep = $(".declaration-step");
                lastActiveStep.addClass("progress-steps__step--active");
            }
        } else {
            return lastActiveStep;
        }

        if (response.declarationTabComplete) {
            lastActiveStep = $(".whatnext-step");
            lastActiveStep.addClass("progress-steps__step--active");
        } else {
            return lastActiveStep;
        }

        return lastActiveStep;
    },
    setCurrentStep: function (currentTab) {
        var currentStep = $("#vendor-registration-steps .progress-steps__step[data-tab='" + currentTab.data("tab") + "']");
        $("#vendor-registration-steps .progress-steps__step").removeClass("progress-steps__step--current-step");
        currentStep.addClass("progress-steps__step--current-step");
        var currentStepButtonId = currentTab.attr("aria-labelledby");
        $(`.progress-steps__step-actions:not(#${currentStepButtonId})`).attr("aria-expanded", false);
        $(`#${currentStepButtonId}`).attr("aria-expanded", true);
    },
    setCountryPicker: function (picker, optionValue) {
        picker.val(optionValue); //change the select box
        picker.parent('.formRow').find('.ui-autocomplete-input').val(picker.find("option[value='" + optionValue + "']").text());
    },
    saveAndConfirmCountryOrIndividualConsultantTypeChange: function (e) {
        UNGM.Throbber.Push();
        var postObj = {
            generalCountryId: $("#GeneralCountryId").val(),
            individualConsultantTypeId: $("input[name=IndividualConsultantTypeId]:checked").val() !== undefined ? $("input[name=IndividualConsultantTypeId]:checked").val() : ""
        };

        $.ajax({
            url: UNGM.siteRoot + 'Vendor/Registration/UpdateSensitiveData',
            type: 'POST',
            data: postObj,
            success: function (data) {
                UNGM.VendorRegistration.reloadAgencySubmissionTab();
                UNGM.VendorRegistration.submitForm($("#frmGeneral"));
                UNGM.Throbber.Pop();
            },
            traditional: true
        });
    },
    postForm: function (evt, form) {
        var sender = null;

        if (form === undefined) {
            form = $(evt.currentTarget).parents('form');
            sender = $(evt.currentTarget);
        }
        else {
            sender = form.find("input[type=submit]");
        }

        var nexttab = sender.data("nexttab");
        if (form.valid() && !form.find("#companyExists:visible").length) {      // valid() returns true when a company exists
            UNGM.throbOver(form);

            if (form.attr('action').indexOf("/General") > 0
                && (UNGM.VendorRegistration.hasGeneralCountryChanged === true || UNGM.VendorRegistration.hasIndividualConsultantTypeChanged === true)
                && UNGM.VendorRegistration.AtLeastOneActiveSubmission) {
                UNGM.VendorRegistration.saveAndConfirmCountryOrIndividualConsultantTypeChange();
                return;
            }

            $.ajax({
                type: "POST",
                url: form.attr('action'),
                data: form.serialize(),
                success: function (response) {
                    // If the country has changed or individual consultant change, the Vendor-Agency match may have changed too
                    if (form.attr('action').indexOf("/General") > 0
                        && UNGM.VendorRegistration.hasGeneralCountryChanged == true || UNGM.VendorRegistration.hasIndividualConsultantTypeChanged == true) {
                        UNGM.VendorRegistration.reloadAgencySubmissionTab();
                    }
                    // In assisted registrations the action returns the new id of the vendor
                    if (UNGM.VendorRegistration.currentVendorId == 0 && UNGM.VendorRegistration.currentVendorId) {
                        $(".zeroPercent").removeClass("zeroPercent");
                        UNGM.VendorRegistration.currentVendorId = response.Id;
                        $(".Id").val(UNGM.VendorRegistration.currentVendorId);
                        // Allow the UN user to continue the registration
                        $("#msgGeneralInfoMandatory").fadeOut("fast");
                        $(".tabDisabled").removeClass("tabDisabled");
                        UNGM.initTabs();
                        // Add id to url
                        if (window.location.href.indexOf("/" + UNGM.VendorRegistration.currentVendorId) < 0) {
                            if (typeof window.history.replaceState == 'function') {
                                window.history.pushState("Assisted registration", "Assisted registration", window.location + "/" + UNGM.VendorRegistration.currentVendorId);
                            }
                            else {
                                window.location.href = UNGM.siteRoot + "UNUser/AssistedRegistration/" + UNGM.VendorRegistration.currentVendorId;
                            }
                        }
                    }
                    UNGM.VendorRegistration.updateCompletion();
                    UNGM.hideThrobber();
                    if (nexttab) {
                        $(".tabHeader").eq(nexttab).click();
                        $(".tabHeader").scrollintoview();
                    }
                }
            });
        }
        else {
            UNGM.hideThrobber();
        }
    },

    handleNotSubmittedAgencyWarning: function () {
        if ($(".chkNotSubmittedAgency:checked").length > 0) {
            $("#divAgencyNotSelected").hide();
        }
        else if (UNGM.VendorRegistration.completionPercent == 100) {
            $("#divAgencyNotSelected").show();
        }
    },

    // Company Available 
    resendInvitation: function (evt) {
        // Get the Id of the cancelled invite
        var button = $(evt.currentTarget);
        var Id = button.data('invitee-id');

        UNGM.throbOver($('#vendorRegistration'));
        $.ajax({
            type: "POST",
            url: UNGM.siteRoot + 'Vendor/Registration/ResendUserInvitation?inviteId=' + Id,
            success: UNGM.VendorRegistration.displayPendingInvites
        });
    },
    inviteUser: function (evt) {
        var winHeight = $(window).height();
        $('#emailBox').val('');
        $('#Language').val(UNGM.currentuserCookieLanguage);
        $('#InviteText').val('');
        $("#userInviteForm").dialog({
            modal: true,
            title: $("#inviteUserDialogTitle").val(),
            width: 700,
            hide: { effect: 'fade', duration: 100 },
            show: { effect: 'fade', duration: 100 },
            open: function () {
                $("#btnSendInvite").off("click").on("click", UNGM.VendorRegistration.sendInviteValidation);
            }
        });
    },
    cancelInvite: function (evt) {
        // Get the Id of the cancelled invite
        var button = $(evt.currentTarget);
        var Id = button.data('invitee-id');

        var deleteOk = function () {
            UNGM.throbOver($('#vendorRegistration'));
            $.ajax({
                type: "POST",
                url: UNGM.siteRoot + 'Vendor/Registration/CancelUserInvitation?inviteId=' + Id,
                success: UNGM.VendorRegistration.displayPendingInvites
            });
        };

        // confirmation
        $.confirm(
            UNGM.VendorRegistration.DeleteInviteConfirmationTitle,
            UNGM.VendorRegistration.DeleteInviteConfirmationMessage,
            UNGM.VendorRegistration.DeleteInviteConfirmationYesButton,
            UNGM.VendorRegistration.DeleteInviteConfirmationNoButton,
            deleteOk
        );
    },
    displayPendingInvites: function (data) {
        try {
            $('#pendingInvites').html(data);
            //now rebind the click handlers
            $(".tabs").off("click", ".btnCancelInvitation");
            $(".btnCancelInvitation").off("click").on("click", UNGM.VendorRegistration.cancelInvite);
            $(".btnResendInvitation").off("click").on("click", UNGM.VendorRegistration.resendInvitation);
        }
        finally {
            UNGM.hideThrobber();
        }
    },
    sendInviteValidation: function (evt) {
        evt.preventDefault();
        var form = $(evt.currentTarget).parents('form');

        if (!form.valid() || !UNGM.EmailValidation.verified) {
            return false;
        }

        grecaptcha.execute();
        UNGM.GoogleRecaptcha.successCallback = UNGM.VendorRegistration.sendInvite;
        
        return true;
    },
    sendInvite: function () {
        UNGM.throbOver(form);
        var form = $("#inviteContactForm");
        $.ajax({
            type: "POST",
            url: form.attr('action'),
            data: form.serialize(),
            success: UNGM.VendorRegistration.inviteSent
        });
    },
    inviteSent: function (data) {
        try {
            // Close the dialog
            $('#userInviteForm').dialog('close');
            UNGM.VendorRegistration.displayPendingInvites(data);
        }
        finally {
            UNGM.hideThrobber();
        }
    },
    showDetails: function (evt) {
        // Get the agency Object
        var sender = $(evt.currentTarget);
        var parentRow = sender;//.parents("tr:first");
        var contactObject = sender.data("object");
        //open the dialog box, showing all the Details
        var winHeight = $(window).height();
        $("#contactDetails").dialog({
            modal: true,
            open: function () {
                $("#viewUserTitle").html(contactObject.UserTitleLocalName);
                $("#viewFirstName").html(contactObject.FirstName);
                $("#viewMiddleName").html(contactObject.MiddleName);
                $("#viewSurname").html(contactObject.Surname);
                $("#viewCompanyPosition").html(contactObject.CompanyPosition);
                $("#viewCountryName").html(contactObject.CountryName);
                $("#viewEmail").html(contactObject.Email);
                $("#viewTelephoneCountryName").html(contactObject.ContactTelephoneCountryName);
                $("#viewTelephoneNumber").html(contactObject.TelephoneNumber);
                $("#viewTelephoneExtension").html(contactObject.TelephoneExtension);
                $("#viewMobileCountryName").html(contactObject.MobileCountryName);
                $("#viewMobileNumber").html(contactObject.MobileNumber);
            },
            title: contactObject.UserTitleName + " " + contactObject.FirstName + " " + contactObject.Surname,
            width: '550px',
            height: winHeight - (winHeight * 0.45),
            hide: { effect: 'fade', duration: 100 },
            show: { effect: 'fade', duration: 100 }
        });
    },
    deleteContact: function (evt) {
        // Stop the even propagation
        evt.stopPropagation();
        var deleteOk = function () {
            // Carry out the delete
            // Get the Id of the cancelled invite
            var button = $(evt.currentTarget);
            var id = button.data('contact-id');

            var postObject = {};
            postObject.Id = id;
            UNGM.throbOver($('#vendorRegistration'));
            $.ajax({
                type: "POST",
                url: UNGM.siteRoot + 'Vendor/Registration/DeactivateUser',
                contentType: 'application/json',
                data: JSON.stringify(postObject),
                success: UNGM.VendorRegistration.onDeleteContact
            });

        };
        //are you sure?
        $.confirm(
            $("#delConfirmationTitle").val(), // Title
            $("#delConfirmationMessage").val(), // Message
            $("#delConfirmationDeleteText").val(), //yes button text (blank hides button)
            $("#delConfirmationCancelText").val(), //no button text (blank hides button)
            deleteOk //"yes" callback
        );
    },
    onDeleteContact: function (data) {
        // If user has deleted themsevles, go to the main page
        if (data.length === undefined) {
            // User has deleted themsevles, go to the main page
            location.href = $("#RedirectToHome").val();
        }
        else {
            // User deleted a different contact, refresh the contacts data
            try {
                $('#allContacts').html(data);
            }
            finally {
                UNGM.hideThrobber();
            }
        }
    },
    editContact: function (evt) {
        // Get the agency Object
        var sender = $(evt.currentTarget);
        var parentRow = sender.parents("tr:first");
        var contactObject = parentRow.data("object");
        //open the dialog box, showing all the Details
        var winHeight = $(window).height();
        //Have to remove all script elements, as the autocompletes have already been run
        //jQuery re-calls document.Ready once it's created the dialog, so autocompletes were being set twice.
        $("#contactEditor").find("script").remove();
        $("#contactEditor").dialog({
            modal: true,
            open: function () {
                $("#btnCancelEdit").on("click", UNGM.VendorRegistration.cancelEdit);
                $("#btnSaveContact").on("click", UNGM.VendorRegistration.saveContact);
                $("#contactEditForm #Id").val(contactObject.Id);
                $("#contactEditForm #UserTitle").val(contactObject.UserTitleName);
                $("#contactEditForm #FirstName").val(contactObject.FirstName);
                $("#contactEditForm #MiddleName").val(contactObject.MiddleName);
                $("#contactEditForm #Surname").val(contactObject.Surname);
                $("#contactEditForm #CompanyPosition").val(contactObject.CompanyPosition);
                UNGM.VendorRegistration.setCountryPicker($("#contactEditForm #CountryId"), contactObject.CountryId);
                //$("#contactEditForm #CountryId").val(contactObject.CountryId);
                $("#contactEditForm #Email").val(contactObject.Email);
                UNGM.VendorRegistration.setCountryPicker($("#contactEditForm #ContactTelephoneCountryId"), contactObject.ContactTelephoneCountryId);
                //$("#contactEditForm #ContactTelephoneCountryId").val(contactObject.ContactTelephoneCountryId);
                $("#contactEditForm #TelephoneNumber").val(contactObject.TelephoneNumber);
                $("#contactEditForm #TelephoneExtension").val(contactObject.TelephoneExtension);
                UNGM.VendorRegistration.setCountryPicker($("#contactEditForm #MobileCountryId"), contactObject.MobileCountryId);
                //$("#contactEditForbtnSaveContactm #MobileCountryId").val(contactObject.MobileCountryId);
                $("#contactEditForm #MobileNumber").val(contactObject.MobileNumber);
                $("#contactEditForm .validationIcon, #contactEditForm .field-validation-error").hide();
            },
            title: UNGM.VendorRegistration.editContactDialogTitle + " - " + contactObject.UserTitleName + " " + contactObject.FirstName + " " + contactObject.Surname,
            width: '750px',
            height: winHeight - (winHeight * 0.15),
            hide: { effect: 'fade', duration: 100 },
            show: { effect: 'fade', duration: 100 }
        });
        evt.stopPropagation();
    },
    setAsPrimaryContact: function (evt) {
        evt.stopPropagation();

        var button = $(evt.currentTarget);
        var contactId = button.data('contact-id');

        UNGM.throbOver();
        $.ajax({
            type: "POST",
            url: "Registration/SelectCompanyPrimaryContact?contactUserId=" + contactId,
            contentType: 'application/json',
            complete: function () {
                UNGM.hideThrobber();
                UNGM.VendorRegistration.reloadContacts();
            }
        });
    },
    cancelEdit: function (evt) {
        //just close the dialog.
        $("#contactEditor").dialog('close');
    },
    saveContact: function (evt) {
        evt.preventDefault();

        var form = $(evt.currentTarget).parents('form');

        if (!form.valid()) {
            return false;
        }

        UNGM.throbOver(form);
        $.ajax({
            url: form.attr('action'),
            type: 'POST',
            data: form.serialize(),
            success: UNGM.VendorRegistration.onSavedContact
        });
    },
    onSavedContact: function (response) {
        $("#contactEditor").dialog('close');
        UNGM.VendorRegistration.updateCompletion(response);
        UNGM.VendorRegistration.reloadContacts();
    },
    reloadContacts: function () {
        $.ajax({
            url: UNGM.siteRoot + "Vendor/Registration/ListContacts",
            type: 'GET',
            contentType: 'application/json',
            success: function (data) {
                $('#allContacts').html(data);
                $(".btnSaveContact").off("click").on("click", UNGM.VendorRegistration.saveContact);
                $(".btnSetAsPrimaryContact").off("click").on("click", UNGM.VendorRegistration.setAsPrimaryContact);
                UNGM.hideThrobber();
            }
        });
    },
    // This function is called from the callback: UNGM.UNSPSC.saveCallback in file: UNGM.Web/Areas/Vendor/Views/UNSPSC/Index.cshtml
    // Also when the the country in the General tab changes
    reloadAgencySubmissionTab: function () {
        if (!UNGM.VendorRegistration.isAssistedRegistration) {
            UNGM.Throbber.Push();
            $.ajax({
                type: "GET",
                url: UNGM.siteRoot + "Vendor/VendorAgency/Index",
                success: function (response) {
                    $("#divAgencySelection").html(response);
                    UNGM.VendorRegistration.handleNotSubmittedAgencyWarning();
                },
                complete: function () {
                    UNGM.VendorRegistration.hasGeneralCountryChanged = false;
                    UNGM.VendorRegistration.hasIndividualConsultantTypeChanged = false;
                    UNGM.Throbber.Pop();
                }
            });
        }
    },
    submitRegistration: function () {
        var submitOk = function () {
            UNGM.throbOver($('#centre'));
            $.ajax({
                type: "POST",
                url: UNGM.siteRoot + 'Vendor/Registration/SubmitRegistration?vendorId=' + UNGM.VendorRegistration.currentVendorId + '&isassistedregistration=' + UNGM.VendorRegistration.isAssistedRegistration,
                success: function () {
                    if (UNGM.VendorRegistration.isAssistedRegistration) {
                        window.location.href = UNGM.siteRoot + "UNUser/AssistedRegistration/" + UNGM.VendorRegistration.currentVendorId;
                    }
                    else {
                        window.location.href = UNGM.siteRoot + "Vendor/Registration/Registration";
                    }
                }
            });
        };

        //are you sure?
        $.confirm(
            UNGM.VendorRegistration.submitConfirmationTitle, // Title
            UNGM.VendorRegistration.submitConfirmationMessage, // Message
            UNGM.VendorRegistration.submitConfirmationYesText, //yes button text (blank hides button)
            UNGM.VendorRegistration.submitConfirmationCancelText, //no button text (blank hides button)
            submitOk //"yes" callback
        );
    },
    resubmitRegistration: function () {
        var clickedOnOk = function () {
            UNGM.throbOver($('#vendorRegistration').prev());
            $.ajax({
                type: "POST",
                url: UNGM.siteRoot + 'Vendor/Registration/ResubmitRegistration',
                success: function () {
                    window.location.href = UNGM.siteRoot + "Vendor/Registration/Registration";
                }
            });
        };

        //are you sure?
        $.confirm(
            UNGM.VendorRegistration.resubmitConfirmationTitle, // Title
            UNGM.VendorRegistration.resubmitConfirmationMessage, // Message
            UNGM.VendorRegistration.resubmitConfirmationYesText, //yes button text (blank hides button)
            UNGM.VendorRegistration.resubmitConfirmationCancelText, //no button text (blank hides button)
            clickedOnOk //"yes" callback
        );
    },
    companyNameFocusOut: function (event) {
        var companyName = $(event.currentTarget);
        var checkingAvailability = companyName.siblings(".checkingAvailability");
        var companyExists = companyName.siblings("#companyExists");
        checkingAvailability.show();
        UNGM.VendorRegistration.checkCompanyNameAvailable(companyName.val()).then(function (isAvailable) {
            companyExists.toggle(!isAvailable);
            UNGM.VendorRegistration.companyNameIsAvailable = isAvailable;
            checkingAvailability.hide();
        });
    },
    checkCompanyNameAvailable: function (companyName) {
        var deferred = $.Deferred();
        $.ajax({
            url: UNGM.siteRoot + 'Account/Registration/IsCompanyNameAvailable?companyName=' + encodeURIComponent(companyName) + "&vendorId=" + UNGM.VendorRegistration.currentVendorId,
            type: 'GET',
            contentType: 'application/json',
            success: function (response) { deferred.resolve(response.isAvailable); }
        });
        return deferred.promise();
    },
    changeCompanyNameLostFocus: function (e) {
        var sender = $(e.currentTarget);
        var newCompanyName = UNGM.VendorRegistration.normalizeCompanyName(sender.val());
        sender.val(newCompanyName);

        if (sender.valid()) {
            if (!newCompanyName.length) {
                return false;
            }
            if (UNGM.VendorRegistration.isNewCompanyNameEqualToOldCompanyName()) {
                sender.siblings(".noChangeInCompanyName").show();
                return false;
            }
            sender.siblings(".noChangeInCompanyName").hide();

            sender.siblings(".checkingAvailability").show();
            $.ajax({
                url: UNGM.siteRoot + 'Account/Registration/IsCompanyNameAvailable?companyName=' + encodeURIComponent(newCompanyName) + "&vendorId=" + UNGM.VendorRegistration.currentVendorId,
                type: 'GET',
                contentType: 'application/json',
                success: UNGM.VendorRegistration.onCheckedCompany
            });
        }
    },
    showSanctions: function () {
        UNGM.Throbber.Push();
        $.get('/Vendor/Registration/Sanctions', function (data) {
            $("#sanctionsDialog").html(data).dialog({
                title: `${UNGM.VendorRegistration.sanctionDialogTitle} ${UNGM.VendorRegistration.currentUngmNumber}`,
                modal: true,
                width: $(window).width() < 480 ? '100%' : '66%',
                hide: { effect: 'fade', duration: 100 },
                show: { effect: 'fade', duration: 100 },
                open: UNGM.Throbber.Pop
            });
        });
    },
    onCheckedCompany: function (response) {
        var box = $("#CompanyName");
        $(".checkingAvailability").hide();

        if (response.isAvailable) {
            UNGM.Validation.markElementValid(box);
            $("#frmCompanyNameChange .companyExists").hide();
            UNGM.VendorRegistration.companyNameIsAvailable = true;
            UNGM.Validation.validateElement(box);
        } else {
            UNGM.Validation.markElementInvalid(box);
            UNGM.VendorRegistration.companyNameIsAvailable = false;
            $("#frmCompanyNameChange .companyExists").show();
        }
    },
    changeName: function () {

        UNGM.throbOver($("#frmGeneral"));
        var postObj = { 'currentCompanyName': $("#CompanyName").val() };
        $.ajax({
            type: 'POST',
            url: UNGM.siteRoot + 'Vendor/Registration/CompanyNameChange',
            data: postObj,
            success: function (data) {
                var newForm = $(data);
                elements.contextForm = newForm;
                UNGM.hideThrobber();
                UNGM.Validation.initForElement(elements.contextForm);
                $("#divNameChange").html(elements.contextForm);
                $("#divNameChange").find("#btnSaveChangeName").off("click").on("click", UNGM.VendorRegistration.saveChangeName);
                $("#divNameChange").find("#ChangeCompanyBox").off("focusout").on("focusout", UNGM.VendorRegistration.changeCompanyNameLostFocus);
                $("#divNameChange").find("#ChangeCompanyBox").off("focusin").on("focusin", UNGM.VendorRegistration.companyGotFocus);
                $("#divNameChange").dialog({
                    modal: true,
                    width: '80%',
                    hide: { effect: 'fade', duration: 100 },
                    show: { effect: 'fade', duration: 100 }
                });
                $("#divNameChange").css('maxHeight', $(window).height() * 0.8);
            }
        });
    },
    commentsLostFocus: function (evt) {
        var sender = $("#Comments");
        if ($("#Reason option:selected").val() != "Other") {
            UNGM.Validation.markElementValid(sender);
        }
    },
    reasonChange: function (evt) {
        var sender = $("#Comments");
        UNGM.Validation.markElementValid(sender);
    },
    saveChangeName: function (evt) {
        var docElement = $("#CertificateOfIncorporationDocumentId");
        if (docElement.length > 0 && docElement.val() === "") {
            $(".requiredDocument").show();
            err = true;
            return;
        }
        else {
            $(".requiredDocument").hide();
        }
        if (!UNGM.VendorRegistration.companyNameIsAvailable) {
            err = true;
            return;
        }

        if ($("#frmCompanyNameChange").valid() && !UNGM.VendorRegistration.isNewCompanyNameEqualToOldCompanyName()) {
            var obj = {};
            obj.CompanyName = $("#OldCompanyName").val();
            obj.Reason = $("#Reason option:selected").val();
            obj.Comments = $("#Comments").val();
            obj.CertificateOfIncorporationDocumentId = $("#CertificateOfIncorporationDocumentId").val();
            obj.VendorId = UNGM.VendorRegistration.currentVendorId;
            obj.NewCompanyName = $("#ChangeCompanyBox").val(); // Save current company name as change company name

            UNGM.throbOver($("#divNameChange"));

            $.ajax({
                url: UNGM.siteRoot + 'Vendor/Registration/SaveCompanyNameChange',
                type: 'POST',
                contentType: 'application/json',
                data: JSON.stringify(obj),
                success: function () {
                    window.location.href = window.location.href;
                }
            });
        }
    },
    normalizeCompanyName: function (companyName) {
        return $.trim(companyName.replace(/\s+/g, ' '));
    },
    isNewCompanyNameEqualToOldCompanyName: function () {
        var oldCompanyName = $("#OldCompanyName").val();
        var newCompanyName = $("#ChangeCompanyBox").val();
        return oldCompanyName === newCompanyName.trim();
    },
    acceptRegistrationInvitation: function (evt) {
        var form = $(evt.currentTarget).parents('form');
        if ($("#CodeOfConduct:checked").length == 0) {
            evt.preventDefault();
            $("#divCocRejected").show();
            $("#divCoc").hide();
            return;
        }
        if (form.valid()) {
            var postObject = {};
            postObject.UserName = form.find("#UserName").val();
            postObject.CompanyName = form.find("#CompanyName").val();
            postObject.FirstName = form.find("#FirstName").val();
            postObject.LastName = form.find("#LastName").val();
            postObject.CountryId = form.find("#CountryId").val();
            postObject.Password = form.find("#Password").val();
            postObject.CompanyDirectorFirstName = form.find("#CompanyDirectorFirstName").val();
            postObject.CompanyDirectorLastName = form.find("#CompanyDirectorLastName").val();
            postObject.CodeOfConduct = true;
            UNGM.throbOver(form);
            $.ajax({
                type: "POST",
                url: form.attr('action'),
                contentType: 'application/json',
                data: JSON.stringify(postObject),
                success: UNGM.VendorRegistration.acceptRegistrationComplete,
                complete: function () { UNGM.hideThrobber(); }
            });
        }
    },
    acceptRegistrationComplete: function (data) {
        UNGM.hideThrobber();
        if (data.success) {
            // Show welcome popup
            var OkHandler = function () {
                // Redirect to Home
                location.href = $("#RedirectToHome").val();
            };
            $.confirm(data.title, data.message, data.okButton, "", OkHandler);
        }
        else {
            $.confirm(data.title, data.message, data.okButton, "", function () { });
        }
    },
    checkCountryAndFiscalCodeUnique: function (e) {
        UNGM.VendorRegistration.hasGeneralCountryChanged = true;
        UNGM.VendorRegistration.isGeneralCountryChangedBackToInitialValue(e);
        UNGM.VendorAccountRegistration.checkCountryAndFiscalCodeUnique(e);
    },
    onIndividualConsultantTypeClicked: function (e) {
        UNGM.VendorRegistration.hasIndividualConsultantTypeChanged = true;
        if ($('#individualConsultantTypeDescription').is(":visible") == false) {
            $('#individualConsultantTypeDescription').show();
        }
        $('#individualConsultantTypeDescription').text($(this).attr('data-description'));
        UNGM.VendorRegistration.isIndividualConsultantTypeChangedBackToInitialValue(e);
    },
    isGeneralCountryChangedBackToInitialValue: function (e) {
        var sender = $(e.currentTarget);
        if (sender.val() == $('#OldGeneralCountryId').val()) {
            UNGM.VendorRegistration.hasGeneralCountryChanged = false;
        }
    },
    isIndividualConsultantTypeChangedBackToInitialValue: function (e) {
        var sender = $(e.currentTarget);
        if (sender.val() == $('#OldIndividualConsultantTypeId').val()) {
            UNGM.VendorRegistration.hasIndividualConsultantTypeChanged = false;
        }
    },
    onCompanyOwnershipTypeChanged: function () {
        var elements = $('[data-enable-if-ownership-type]');
        elements.each(function (_index, item) {
            var element = $(item);
            var enable = UNGM.VendorRegistration.isOwnershipTypeEnabled(element);
            if (enable) {
                element.slideDown(300);
            } else {
                element.slideUp(300);
            }
        });
        setTimeout(UNGM.VendorRegistration.onCompanyWomenOwnershipChanged, 400);
    },
    onCompanyWomenOwnershipChanged: function () {
        var elements = $('[data-enable-if-women-ownership]');
        elements.each(function (_index, item) {
            var element = $(item);
            var enable = UNGM.VendorRegistration.isWomenOwnershipEnabled(element);
            if (enable) {
                element.slideDown(300);
            } else {
                element.slideUp(300);
            }
        });
    },
    isOwnershipTypeEnabled: function (element) {
        var ownerships = JSON.parse(element.attr('data-enable-if-ownership-type'));
        var ownershipType = $('[name=OwnershipType]').filter(function (_index, item) { return $(item).prop('checked'); }).val();
        return $.inArray(ownershipType, ownerships) !== -1;
    },
    isWomenOwnershipEnabled: function (element) {
        var womenOwnerships = JSON.parse(element.attr('data-enable-if-women-ownership'));
        var womenOwnership = $('[name=WomenOwnership]').filter(function (_index, item) { return $(item).prop('checked'); }).val();
        return $('[name=WomenOwnership]').is(':visible') && $.inArray(womenOwnership, womenOwnerships) !== -1;
    },
    onTenderAlertServiceTabClicked: function () {
        UNGM.VendorRegistration.tenderAlertServiceTabCallback();
    },
    setTenderAlertServiceTabCallback: function (callback) {
        UNGM.VendorRegistration.tenderAlertServiceTabCallback = callback;
    }
};;
window.UNGM.ImplementingPartner = {
    currentImplementingPartnerId: 0,
    selectedExportCountries: [],
    hasGeneralCountryChanged: false,
    hasIndividualConsultantTypeChanged: false,
    companyNameIsAvailable: true,
    completionPercent: 1,
    isUnspscTabInitialized: false,
    submittingAgencyIds: null,
    tenderAlertServiceTabCallback: null,
    init: function (completionModel) {
        $(".tabHeader").bind("click", UNGM.ImplementingPartner.onTabClicked);
        $("#Unspsc").on("click", UNGM.ImplementingPartner.initUnspscTab);

        $(".tab:not(#vr-unspsc-panel)").on("submit", "form", UNGM.ImplementingPartner.onFormSubmitted);
        $(".tabs").on("focusin", "form :input", UNGM.removeError);
        $(".tabs").on("click", "[name='DeclarationOfEligibility']", UNGM.ImplementingPartner.declarationOfEligibilityClicked);
        $(".tabs").on("click", "[name='RegistrationType']", UNGM.ImplementingPartner.registrationTypeClicked);
        $(".tabs").on("change", "#DummyCountryId", UNGM.ImplementingPartner.onExportCountrySelected);
        $(".tabs").on("click", "#selectAllCountries", UNGM.ImplementingPartner.onSelectAllCountriesClicked);
        $(".tabs").on("click", "#removeAllCountries", UNGM.ImplementingPartner.onRemoveAllCountriesClicked);

        UNGM.tabContentReceivedCallback = UNGM.ImplementingPartner.tabContentReceivedCallback;

        $(".back-to-previous-step").off("click").on("click", UNGM.ImplementingPartner.goToPreviousTab);

        $("#vendor-registration-steps .progress-steps__step-actions").off("click").on("click", UNGM.ImplementingPartner.goToCorrespondingTab);

        UNGM.ImplementingPartner.setBirthdateDatepicker();

        // Change company name & contacts tab funcionalitiy
        $(".tabs").on("click", "#btnInviteUser", UNGM.ImplementingPartner.inviteUser);
        $(".tabs").on("click", ".btnCancelInvitation", UNGM.ImplementingPartner.cancelInvite);
        $(".tabs").on("click", ".btnResendInvitation", UNGM.ImplementingPartner.resendInvitation);
        $(".tabs").on("click", "#tblContacts tbody tr", UNGM.ImplementingPartner.showDetails);
        $(".tabs").on("click", ".btnEditContact", UNGM.ImplementingPartner.editContact);
        $(".tabs").on("click", ".btnSetAsPrimaryContact", UNGM.ImplementingPartner.setAsPrimaryContact);
        $(".tabs").on("click", ".btnDeleteContact", UNGM.ImplementingPartner.deleteContact);
        $(".btnChangeName").off("click").on("click", UNGM.ImplementingPartner.changeName);
        $("#CompanyName").on("focusout", UNGM.ImplementingPartner.companyNameFocusOut);
        $("#ChangeCompanyBox").on("focusout", UNGM.ImplementingPartner.changeCompanyNameLostFocus);
        $("#ChangeCompanyBox").on("focusin", UNGM.ImplementingPartner.companyGotFocus);
        $("#Comments").on("focusout", UNGM.ImplementingPartner.commentsLostFocus);
        $("#btnSaveChangeName").off("click").on("click", UNGM.ImplementingPartner.saveChangeName);
        $("#Reason").on("change", UNGM.ImplementingPartner.reasonChange);
        $("#btnAcceptRegistration").off("click").on("click", UNGM.ImplementingPartner.acceptRegistrationInvitation);
        $("#GeneralCountryId").on("change", UNGM.ImplementingPartner.checkCountryAndFiscalCodeUnique);
        $("#FiscalCode").on("focusout", UNGM.VendorAccountRegistration.checkCountryAndFiscalCodeUnique);
        // Submission        
        $("#btnResubmitRegistration").off("click").on("click", UNGM.ImplementingPartner.resubmitRegistration);
        $("#ParentCompany").autocompleteNoConflict({
            serviceUrl: UNGM.siteRoot + 'Vendor/Registration/GetParentSuggestions',
            minChars: 5,
            deferRequestBy: 500
        });
        $("input[name=IndividualConsultantTypeId]:radio").on("click", UNGM.ImplementingPartner.onIndividualConsultantTypeClicked);

        $('[name=OwnershipType]').change(UNGM.ImplementingPartner.onCompanyOwnershipTypeChanged);
        $('[name=WomenOwnership]').change(UNGM.ImplementingPartner.onCompanyWomenOwnershipChanged);
        UNGM.ImplementingPartner.onCompanyOwnershipTypeChanged();

        $('#TenderAlertServiceTab').click(UNGM.ImplementingPartner.onTenderAlertServiceTabClicked);
        $('#ImplementingPartnerType').change(UNGM.ImplementingPartner.onImplementingPartnerTypeChanged);

        UNGM.ImplementingPartner.updateCompletion(completionModel);

        UNGM.ImplementingPartner.showSpecificTabIfAny();
    },
    showSpecificTabIfAny: function() {
        var parameter = "#tab=";
        if (window.location.href.indexOf(parameter) !== -1) {
            var index1 = window.location.href.indexOf(parameter) + parameter.length;
            var index2 = window.location.href.indexOf("&", index1);
            if (index2 === -1) {
                index2 = window.location.href.length;
            }
            var tabId = window.location.href.substring(index1, index2);

            if (tabId.length) {
                UNGM.ImplementingPartner.goToTab($(".tab[data-tab='" + tabId + "']"));
            }
        }
    },
    initUnspscTab: function () {
        if (!UNGM.ImplementingPartner.isUnspscTabInitialized) {
            UNGM.ImplementingPartner.isUnspscTabInitialized = true;
            uvm.bootstrap('#vr-unspsc-panel', ['UNGM.ImplementingPartner.Registration']);
        }
    },
    setBirthdateDatepicker: function () {
        $("[name='Birthdate']").datepicker({
            maxDate: 0,
            changeMonth: true,
            changeYear: true,
            yearRange: "-100:+0",
            onSelect: function () {
                if ($("[name='Birthdate']").val().length > 0) {
                    UNGM.Validation.validateElement($("[name='Birthdate']"));
                }
                UNGM.Validation.validateElement($(this));
            }
        });
    },
    tabContentReceivedCallback: function (tabElement) {
        if (tabElement.find("#ImplementingPartnerTypeInfo").length) {
            UNGM.ImplementingPartner.bindExportCountries();
        }

        UNGM.Validation.initForElement(tabElement.find("form"));
        UNGM.markRequiredFields();
        $(".back-to-previous-step").off("click").on("click", UNGM.ImplementingPartner.goToPreviousTab);
    },
    registrationTypeClicked: function (e) {
        if ($(this).val() === "National") {
            $("#exportToCountrySelector").hide(300);
            $("[name='CountryIds']").remove();
            UNGM.ImplementingPartner.selectedExportCountries = [];
        } else {
            $("#exportToCountrySelector").show(300);
        }
        // rebind the countries
        UNGM.ImplementingPartner.bindExportCountries();
    },
    onExportCountrySelected: function (e) {
        var sender = $(e.currentTarget);
        var countryId = sender.val();
        if (countryId == '') {
            return;
        }
        var countryName = sender.children(':selected').text();

        var country = {
            Id: countryId,
            Name: countryName
        };
        // Check if the country is already in the list
        if ($.grep(UNGM.ImplementingPartner.selectedExportCountries, function (e) { return e.Id == country.Id; }).length == 0 && country.Id.length) {
            UNGM.ImplementingPartner.selectedExportCountries.push(country);
            UNGM.ImplementingPartner.bindExportCountries();
        }
        // HACK: doing this immediately doesn't work for some reason (due to plugin) so wait a little before clearing text
        setTimeout(' $("#DummyCountryId").val(""); $("#exportToCountryPickerHolder input").val("").focus();', 200);
    },
    bindExportCountries: function () {
        // Render the countries on the page
        var holder = $("#exportToCountryHolder");
        holder.empty();
        $("[name='CountryIds']").remove();

        if (UNGM.ImplementingPartner.selectedExportCountries.length === 0) {
            $("#exportToCountryNoCountries").show();
            $("#exportToCountryHolder").css('height', '0'); // Hack for IE
        } else {
            $("#exportToCountryNoCountries").hide();
            for (var i = 0; i < UNGM.ImplementingPartner.selectedExportCountries.length; i++) {
                holder.append(UNGM.ImplementingPartner.renderExportCountry(UNGM.ImplementingPartner.selectedExportCountries[i]));
            }
            $("#exportToCountryHolder").css('height', ''); // Hack for IE
        }
    },
    renderExportCountry: function (country) {
        var elem = $("<div class='exportToCountry editableListItem'></div>");
        var name = $("<span class='exportToCountryName'></span>");
        var options = $("<span class='options'></span>");
        if (!UNGM.ImplementingPartner.countriesReadonly) {
            var remove = $("<a href='javascript:;' class='btn btn-small'>" + UNGM.ImplementingPartner.removeCountryButtonText + "</a>");
            remove.data("countryId", country.Id);
            remove.bind("click", UNGM.ImplementingPartner.removeExportCountry);
            options.append(remove);
        }

        name.html(country.Name);
        var newCountryHidden = $("<input type='hidden' value='" + country.Id + "' name='CountryIds'/>");
        var clearElement = $("<div class='clear'></div>");
        elem.append(name).append(options).append(newCountryHidden).append(clearElement);
        return elem;
    },
    removeExportCountry: function (evt) {
        var sender = $(evt.currentTarget);
        var countryId = sender.data("countryId");

        for (var i = 0; i < UNGM.ImplementingPartner.selectedExportCountries.length; i++) {
            if (UNGM.ImplementingPartner.selectedExportCountries[i].Id == countryId) {
                UNGM.ImplementingPartner.selectedExportCountries.splice(i, 1);
            }
        }
        UNGM.ImplementingPartner.bindExportCountries();
    },
    onRemoveAllCountriesClicked: function () {
        UNGM.ImplementingPartner.selectedExportCountries = [];
        UNGM.ImplementingPartner.bindExportCountries();
    },
    onSelectAllCountriesClicked: function () {
        UNGM.ImplementingPartner.selectedExportCountries = [];
        $("#DummyCountryId option:not(:first)").each(function (i, o) {
            var country = {
                Id: $(o).val(),
                Name: $(o).text()
            };
            UNGM.ImplementingPartner.selectedExportCountries.push(country);
        });
        UNGM.ImplementingPartner.bindExportCountries();
    },
    declarationOfEligibilityClicked: function () {
        if ($(this).val() === "Yes") {
            $("#eligibilityCommentsDiv").hide();
        } else {
            $("#eligibilityCommentsDiv").show();
        }
    },
    onFormSubmitted: function (e) {
        e.preventDefault();
        var form = $(e.currentTarget);
        var numberOfDocuments = $('.docslist span.selectedDocumentFilename').length;
        var isDocumentAvailable = false;

        if (numberOfDocuments > 0) {
            isDocumentAvailable = true
        } else {
            isDocumentAvailable = false;
        }
        

        if (!form.valid()) {
            return false;
        }
        if (form.attr('id') === "frmGeneral") {
            if (!UNGM.ImplementingPartner.companyNameIsAvailable || !isDocumentAvailable) {
                return false;
            }
            if ((UNGM.ImplementingPartner.hasGeneralCountryChanged === true)
                && UNGM.ImplementingPartner.AtLeastOneActiveSubmission) {
                UNGM.ImplementingPartner.saveAndConfirmCountryOrIndividualConsultantTypeChange();
                return;
            }
        }

        UNGM.ImplementingPartner.submitForm(form);
    },
    submitForm: function (form) {
        UNGM.Throbber.Push();
        $.ajax({
            url: form.attr("action"),
            type: "POST",
            data: form.serialize(),
            global: false,
            success: function (response) {
                if (form.find("#Surname").length) {
                    // Reload declaration of eligibility
                    $("#vr-declaration-panel").data("reload", true);
                }

                UNGM.ImplementingPartner.updateCompletion(response);
            },
            complete: UNGM.Throbber.Pop
        });
    },
    goToTab: function (tab) {
        var currentActive = $(".tab.step-tab-active");
        currentActive.removeClass("step-tab-active");
        tab.addClass("step-tab-active");
        UNGM.ImplementingPartner.setCurrentStep(tab);
        window.scrollTo(0, 0);

        if (tab.data("tab") === "general-tab") {
            return;
        }

        if (tab.data("tab") === "unspsc-tab") {
            UNGM.ImplementingPartner.initUnspscTab();
            return;
        }

        if (tab.data("tab") === "what-next-tab") {
            UNGM.ImplementingPartner.getAgencyMyAgencyRegistration();
            return;
        }
        UNGM.reloadTab(tab);
    },
    getAgencyMyAgencyRegistration: function () {
        $.ajax({
            url: UNGM.siteRoot + 'ImplementingPartner/Home/MyAgencyRegistration',
            type: 'POST',
            success: function (registeredCount) {
                UNGM.ImplementingPartner.updateRegistrationMessage(`${UNGM.ImplementingPartner.IPRegistrationCompleteMessage1} ${registeredCount} ${UNGM.ImplementingPartner.IPRegistrationCompleteMessage2}`);
            },
            
        });
    },
    updateRegistrationMessage: function (newMessage) {
        $("#registrationCompleteMessage").html(newMessage + "<br />" +
            '<a target="_blank" href="/ImplementingPartner/OrganizationRegistration" onclick="UNGM.gaEvent(\'Manage Submissions\', \'Click\', \'What Next - Manage Submissions clicked\')" style="font-weight: 500; white-space: nowrap;">' +
            UNGM.ImplementingPartner.IpManageAgencySubmissionsLink + '</a>');
    },

    goToCorrespondingTab: function(e) {
        var sender = $(e.currentTarget);
        var parent = sender.closest("#vendor-registration-steps .progress-steps__step");

        UNGM.ImplementingPartner.goToTab($(".tab[data-tab='" + parent.data("tab") + "']"));
    },
    goToPreviousTab: function (e) {
        var currentActive = $(".tab.step-tab-active");
        var previousTab = currentActive.prev();
        UNGM.ImplementingPartner.goToTab(previousTab);
    },
    updateCompletion: function (response) {
        if (response.CompletionPercent === 100) {
            $(".incomplete-registration").removeClass('incomplete-registration').addClass('complete-registration');
        } else {
            $(".complete-registration").removeClass('complete-registration').addClass('incomplete-registration');
        }

        var lastActiveStep = UNGM.ImplementingPartner.findLastActiveStep(response);
        UNGM.ImplementingPartner.goToTab($(".tab[data-tab='" + lastActiveStep.data("tab") + "']"));
    },
    findLastActiveStep: function (response) {

        var lastActiveStep = $(".general-info-step");
        if (response.IsGeneralInfoComplete) {
            lastActiveStep = $(".address-step");
            lastActiveStep.addClass("progress-steps__step--active");

        } else {
            return lastActiveStep;
        }

        if (response.IsAddressInfoComplete) {
            lastActiveStep = $(".registration-type-step");
            lastActiveStep.addClass("progress-steps__step--active");
        } else {
            return lastActiveStep;
        }

        if (response.IsRegistrationTypeInfoComplete) {
            lastActiveStep = $(".contact-step");
            lastActiveStep.addClass("progress-steps__step--active");
        } else {
            return lastActiveStep;
        }

        if (response.IsContactInfoComplete) {
            lastActiveStep = $(".unspsc-step");
            lastActiveStep.addClass("progress-steps__step--active");
        } else {
            return lastActiveStep;
        }

        if (response.IsCodingInfoComplete) {
            lastActiveStep = $(".declaration-step");
            lastActiveStep.addClass("progress-steps__step--active");
        } else {
            return lastActiveStep;
        }

        if (response.IsDeclarationOfEligibilityInfoComplete) {
            lastActiveStep = $(".whatnext-step");
            lastActiveStep.addClass("progress-steps__step--active");
        } else {
            return lastActiveStep;
        }

        return lastActiveStep;
    },
    setCurrentStep: function (currentTab) {
        var currentStep = $("#vendor-registration-steps .progress-steps__step[data-tab='" + currentTab.data("tab") + "']");
        $("#vendor-registration-steps .progress-steps__step").removeClass("progress-steps__step--current-step");
        currentStep.addClass("progress-steps__step--current-step");
        var currentStepButtonId = currentTab.attr("aria-labelledby");
        $(`.progress-steps__step-actions:not(#${currentStepButtonId})`).attr("aria-expanded", false);
        $(`#${currentStepButtonId}`).attr("aria-expanded", true);
    },
    setCountryPicker: function (picker, optionValue) {
        picker.val(optionValue); //change the select box
        picker.parent('.formRow').find('.ui-autocomplete-input').val(picker.find("option[value='" + optionValue + "']").text());
    },
    saveAndConfirmCountryOrIndividualConsultantTypeChange: function (e) {
        UNGM.Throbber.Push();
        var postObj = {
            generalCountryId: $("#GeneralCountryId").val(),
            individualConsultantTypeId: $("input[name=IndividualConsultantTypeId]:checked").val() !== undefined ? $("input[name=IndividualConsultantTypeId]:checked").val() : ""
        };

        $.ajax({
            url: UNGM.siteRoot + 'Vendor/Registration/UpdateSensitiveData',
            type: 'POST',
            data: postObj,
            success: function (data) {
                UNGM.ImplementingPartner.reloadAgencySubmissionTab();
                UNGM.ImplementingPartner.submitForm($("#frmGeneral"));
                UNGM.Throbber.Pop();
            },
            traditional: true
        });
    },
    postForm: function (evt, form) {
        var sender = null;

        if (form === undefined) {
            form = $(evt.currentTarget).parents('form');
            sender = $(evt.currentTarget);
        }
        else {
            sender = form.find("input[type=submit]");
        }

        var nexttab = sender.data("nexttab");
        if (form.valid() && !form.find("#companyExists:visible").length) {      // valid() returns true when a company exists
            UNGM.throbOver(form);

            if (form.attr('action').indexOf("/General") > 0
                && (UNGM.ImplementingPartner.hasGeneralCountryChanged === true || UNGM.ImplementingPartner.hasIndividualConsultantTypeChanged === true)
                && UNGM.ImplementingPartner.AtLeastOneActiveSubmission) {
                UNGM.ImplementingPartner.saveAndConfirmCountryOrIndividualConsultantTypeChange();
                return;
            }

            $.ajax({
                type: "POST",
                url: form.attr('action'),
                data: form.serialize(),
                success: function (response) {
                    // If the country has changed or individual consultant change, the Vendor-Agency match may have changed too
                    if (form.attr('action').indexOf("/General") > 0
                        && UNGM.ImplementingPartner.hasGeneralCountryChanged == true || UNGM.ImplementingPartner.hasIndividualConsultantTypeChanged == true) {
                        UNGM.ImplementingPartner.reloadAgencySubmissionTab();
                    }
                   
                    UNGM.ImplementingPartner.updateCompletion();
                    UNGM.hideThrobber();
                    if (nexttab) {
                        $(".tabHeader").eq(nexttab).click();
                        $(".tabHeader").scrollintoview();
                    }
                }
            });
        }
        else {
            UNGM.hideThrobber();
        }
    },

    handleNotSubmittedAgencyWarning: function () {
        if ($(".chkNotSubmittedAgency:checked").length > 0) {
            $("#divAgencyNotSelected").hide();
        }
        else if (UNGM.ImplementingPartner.completionPercent == 100) {
            $("#divAgencyNotSelected").show();
        }
    },

    // Company Available 
    resendInvitation: function (evt) {
        // Get the Id of the cancelled invite
        var button = $(evt.currentTarget);
        var Id = button.data('invitee-id');

        UNGM.throbOver();
        $.ajax({
            type: "POST",
            url: UNGM.siteRoot + 'ImplementingPartner/Contacts/ResendInvitation?inviteId=' + Id,
            success: UNGM.ImplementingPartner.displayPendingInvites
        });
    },
    inviteUser: function (evt) {
        var winHeight = $(window).height();
        $('#emailBox').val('');
        $('#Language').val(UNGM.currentuserCookieLanguage);
        $('#InviteText').val('');
        $("#userInviteForm").dialog({
            modal: true,
            title: $("#inviteUserDialogTitle").val(),
            width: 700,
            hide: { effect: 'fade', duration: 100 },
            show: { effect: 'fade', duration: 100 },
            open: function () {
                $("#inviteContactForm").off("submit").on("submit", UNGM.ImplementingPartner.sendInviteValidation);
            }
        });
    },
    cancelInvite: function (evt) {
        // Get the Id of the cancelled invite
        var button = $(evt.currentTarget);
        var Id = button.data('invitee-id');

        var deleteOk = function () {
            UNGM.throbOver();
            $.ajax({
                type: "POST",
                url: UNGM.siteRoot + 'ImplementingPartner/Contacts/CancelInvitation?inviteId=' + Id,
                success: UNGM.ImplementingPartner.displayPendingInvites
            });
        };

        // confirmation
        $.confirm(
            UNGM.ImplementingPartner.DeleteInviteConfirmationTitle,
            UNGM.ImplementingPartner.DeleteInviteConfirmationMessage,
            UNGM.ImplementingPartner.DeleteInviteConfirmationYesButton,
            UNGM.ImplementingPartner.DeleteInviteConfirmationNoButton,
            deleteOk
        );
    },
    displayPendingInvites: function (data) {
        try {
            $('#pendingInvites').html(data);
            //now rebind the click handlers
            $(".tabs").off("click", ".btnResendInvitation");
            $(".tabs").off("click", ".btnCancelInvitation");
            $(".btnCancelInvitation").off("click").on("click", UNGM.ImplementingPartner.cancelInvite);
            $(".btnResendInvitation").off("click").on("click", UNGM.ImplementingPartner.resendInvitation);
            
        }
        finally {
            UNGM.hideThrobber();
        }
    },
    sendInviteValidation: function (evt) {
        evt.preventDefault();
        var form = $(evt.currentTarget);

        if (!UNGM.EmailValidation.verified) {
            UNGM.EmailValidation.verifyEmailAvailability(false);
        }
        if (!form.valid() || !UNGM.EmailValidation.verified) {
            return false;
        }

        grecaptcha.execute();
        UNGM.GoogleRecaptcha.successCallback = UNGM.ImplementingPartner.sendInvite;

        return true;
    },
    sendInvite: function () {
        UNGM.throbOver(form);
        var form = $("#inviteContactForm");
        $.ajax({
            type: "POST",
            url: form.attr('action'),
            data: form.serialize(),
            success: UNGM.ImplementingPartner.inviteSent
        });
    },
    inviteSent: function (data) {
        try {
            // Close the dialog
            $('#userInviteForm').dialog('close');
            UNGM.ImplementingPartner.displayPendingInvites(data);
        }
        finally {
            UNGM.hideThrobber();
        }
    },
    showDetails: function (evt) {
        // Get the agency Object
        var sender = $(evt.currentTarget);
        var parentRow = sender;//.parents("tr:first");
        var contactObject = sender.data("object");
        //open the dialog box, showing all the Details
        var winHeight = $(window).height();
        $("#contactDetails").dialog({
            modal: true,
            open: function () {
                $("#viewUserTitle").html(contactObject.UserTitleLocalName);
                $("#viewFirstName").html(contactObject.FirstName);
                $("#viewMiddleName").html(contactObject.MiddleName);
                $("#viewSurname").html(contactObject.Surname);
                $("#viewCompanyPosition").html(contactObject.CompanyPosition);
                $("#viewCountryName").html(contactObject.CountryName);
                $("#viewEmail").html(contactObject.Email);
                $("#viewTelephoneCountryName").html(contactObject.ContactTelephoneCountryName);
                $("#viewTelephoneNumber").html(contactObject.TelephoneNumber);
                $("#viewTelephoneExtension").html(contactObject.TelephoneExtension);
                $("#viewMobileCountryName").html(contactObject.MobileCountryName);
                $("#viewMobileNumber").html(contactObject.MobileNumber);
            },
            title: contactObject.UserTitleName + " " + contactObject.FirstName + " " + contactObject.Surname,
            width: '550px',
            height: winHeight - (winHeight * 0.45),
            hide: { effect: 'fade', duration: 100 },
            show: { effect: 'fade', duration: 100 }
        });
    },
    deleteContact: function (evt) {
        // Stop the even propagation
        evt.stopPropagation();
        var deleteOk = function () {
            // Carry out the delete
            // Get the Id of the cancelled invite
            var button = $(evt.currentTarget);
            var id = button.data('contact-id');

            var postObject = {};
            postObject.Id = id;
            UNGM.throbOver();
            $.ajax({
                type: "POST",
                url: UNGM.siteRoot + 'ImplementingPartner/Contacts/DeactivateUser',
                contentType: 'application/json',
                data: JSON.stringify(postObject),
                success: UNGM.ImplementingPartner.onDeleteContact
            });

        };
        //are you sure?
        $.confirm(
            $("#delConfirmationTitle").val(), // Title
            $("#delConfirmationMessage").val(), // Message
            $("#delConfirmationDeleteText").val(), //yes button text (blank hides button)
            $("#delConfirmationCancelText").val(), //no button text (blank hides button)
            deleteOk //"yes" callback
        );
    },
    onDeleteContact: function (data) {
        // If user has deleted themsevles, go to the main page
        if (data.length === undefined) {
            // User has deleted themsevles, go to the main page
            location.href = $("#RedirectToHome").val();
        }
        else {
            // User deleted a different contact, refresh the contacts data
            try {
                $('#allContacts').html(data);
            }
            finally {
                UNGM.hideThrobber();
            }
        }
    },
    editContact: function (evt) {
        // Get the agency Object
        var sender = $(evt.currentTarget);
        var parentRow = sender.parents("tr:first");
        var contactObject = parentRow.data("object");
        //open the dialog box, showing all the Details
        var winHeight = $(window).height();
        //Have to remove all script elements, as the autocompletes have already been run
        //jQuery re-calls document.Ready once it's created the dialog, so autocompletes were being set twice.
        $("#contactEditor").find("script").remove();
        $("#contactEditor").dialog({
            modal: true,
            open: function () {
                $("#btnCancelEdit").on("click", UNGM.ImplementingPartner.cancelEdit);
                $("#btnSaveContact").on("click", UNGM.ImplementingPartner.saveContact);
                $("#contactEditForm #Id").val(contactObject.Id);
                $("#contactEditForm #UserTitle").val(contactObject.UserTitleName);
                $("#contactEditForm #FirstName").val(contactObject.FirstName);
                $("#contactEditForm #MiddleName").val(contactObject.MiddleName);
                $("#contactEditForm #Surname").val(contactObject.Surname);
                $("#contactEditForm #CompanyPosition").val(contactObject.CompanyPosition);
                UNGM.ImplementingPartner.setCountryPicker($("#contactEditForm #CountryId"), contactObject.CountryId);
                //$("#contactEditForm #CountryId").val(contactObject.CountryId);
                $("#contactEditForm #Email").val(contactObject.Email);
                UNGM.ImplementingPartner.setCountryPicker($("#contactEditForm #ContactTelephoneCountryId"), contactObject.ContactTelephoneCountryId);
                //$("#contactEditForm #ContactTelephoneCountryId").val(contactObject.ContactTelephoneCountryId);
                $("#contactEditForm #TelephoneNumber").val(contactObject.TelephoneNumber);
                $("#contactEditForm #TelephoneExtension").val(contactObject.TelephoneExtension);
                UNGM.ImplementingPartner.setCountryPicker($("#contactEditForm #MobileCountryId"), contactObject.MobileCountryId);
                //$("#contactEditForbtnSaveContactm #MobileCountryId").val(contactObject.MobileCountryId);
                $("#contactEditForm #MobileNumber").val(contactObject.MobileNumber);
                $("#contactEditForm .validationIcon, #contactEditForm .field-validation-error").hide();
            },
            title: UNGM.ImplementingPartner.editContactDialogTitle + " - " + contactObject.UserTitleName + " " + contactObject.FirstName + " " + contactObject.Surname,
            width: '750px',
            height: winHeight - (winHeight * 0.15),
            hide: { effect: 'fade', duration: 100 },
            show: { effect: 'fade', duration: 100 }
        });
        evt.stopPropagation();
    },
    setAsPrimaryContact: function (evt) {
        evt.stopPropagation();

        var button = $(evt.currentTarget);
        var contactId = button.data('contact-id');

        UNGM.throbOver();
        $.ajax({
            type: "POST",
            url: "Contacts/SelectPrimaryContact?contactUserId=" + contactId,
            contentType: 'application/json',
            complete: function () {
                UNGM.hideThrobber();
                UNGM.ImplementingPartner.reloadContacts();
            }
        });
    },
    cancelEdit: function (evt) {
        //just close the dialog.
        $("#contactEditor").dialog('close');
    },
    saveContact: function (evt) {
        evt.preventDefault();

        var form = $(evt.currentTarget).parents('form');

        if (!form.valid()) {
            return false;
        }

        UNGM.throbOver(form);
        $.ajax({
            url: form.attr('action'),
            type: 'POST',
            data: form.serialize(),
            success: UNGM.ImplementingPartner.onSavedContact
        });
    },
    onSavedContact: function (response) {
        $("#contactEditor").dialog('close');
        UNGM.ImplementingPartner.updateCompletion(response);
        UNGM.ImplementingPartner.reloadContacts();
    },
    reloadContacts: function () {
        $.ajax({
            url: UNGM.siteRoot + "ImplementingPartner/Contacts/ContactList?id=" + UNGM.ImplementingPartner.currentImplementingPartnerId,
            type: 'GET',
            contentType: 'application/json',
            success: function (data) {
                $('#allContacts').html(data);
                $(".btnSaveContact").off("click").on("click", UNGM.ImplementingPartner.saveContact);
                $(".btnSetAsPrimaryContact").off("click").on("click", UNGM.ImplementingPartner.setAsPrimaryContact);
                UNGM.hideThrobber();
            }
        });
    },
    // This function is called from the callback: UNGM.UNSPSC.saveCallback in file: UNGM.Web/Areas/Vendor/Views/UNSPSC/Index.cshtml
    // Also when the the country in the General tab changes
    reloadAgencySubmissionTab: function () {
        UNGM.Throbber.Push();
        $.ajax({
            type: "GET",
            url: UNGM.siteRoot + "Vendor/VendorAgency/Index",
            success: function (response) {
                $("#divAgencySelection").html(response);
                UNGM.ImplementingPartner.handleNotSubmittedAgencyWarning();
            },
            complete: function () {
                UNGM.ImplementingPartner.hasGeneralCountryChanged = false;
                UNGM.ImplementingPartner.hasIndividualConsultantTypeChanged = false;
                UNGM.Throbber.Pop();
            }
        });
    },
    submitRegistration: function () {
        var submitOk = function () {
            UNGM.throbOver($('#centre'));
            $.ajax({
                type: "POST",
                url: UNGM.siteRoot + 'ImplementingPartner/Registration/SubmitRegistration?vendorId=' + UNGM.ImplementingPartner.currentImplementingPartnerId,
                success: function () {
                    window.location.href = UNGM.siteRoot + "ImplementingPartner/Registration/Registration";
                }
            });
        };

        //are you sure?
        $.confirm(
            UNGM.ImplementingPartner.submitConfirmationTitle, // Title
            UNGM.ImplementingPartner.submitConfirmationMessage, // Message
            UNGM.ImplementingPartner.submitConfirmationYesText, //yes button text (blank hides button)
            UNGM.ImplementingPartner.submitConfirmationCancelText, //no button text (blank hides button)
            submitOk //"yes" callback
        );
    },
    resubmitRegistration: function () {
        var clickedOnOk = function () {
            UNGM.throbOver($('#vendorRegistration').prev());
            $.ajax({
                type: "POST",
                url: UNGM.siteRoot + 'ImplementingPartner/Registration/ResubmitRegistration',
                success: function () {
                    window.location.href = UNGM.siteRoot + "ImplementingPartner/Registration/Registration";
                }
            });
        };

        //are you sure?
        $.confirm(
            UNGM.ImplementingPartner.resubmitConfirmationTitle, // Title
            UNGM.ImplementingPartner.resubmitConfirmationMessage, // Message
            UNGM.ImplementingPartner.resubmitConfirmationYesText, //yes button text (blank hides button)
            UNGM.ImplementingPartner.resubmitConfirmationCancelText, //no button text (blank hides button)
            clickedOnOk //"yes" callback
        );
    },
    companyNameFocusOut: function (event) {
        var companyName = $(event.currentTarget);
        var checkingAvailability = companyName.siblings(".checkingAvailability");
        var companyExists = companyName.siblings("#companyExists");
        checkingAvailability.show();
        UNGM.ImplementingPartner.checkCompanyNameAvailable(companyName.val()).then(function (isAvailable) {
            companyExists.toggle(!isAvailable);
            UNGM.ImplementingPartner.companyNameIsAvailable = isAvailable;
            checkingAvailability.hide();
        });
    },
    checkCompanyNameAvailable: function (companyName) {
        var deferred = $.Deferred();
        $.ajax({
            url: UNGM.siteRoot + 'Account/Registration/IsCompanyNameAvailable?companyName=' + encodeURIComponent(companyName) + "&vendorId=" + UNGM.ImplementingPartner.currentImplementingPartnerId,
            type: 'GET',
            contentType: 'application/json',
            success: function (response) { deferred.resolve(response.isAvailable); }
        });
        return deferred.promise();
    },
    changeCompanyNameLostFocus: function (e) {
        var sender = $(e.currentTarget);
        var newCompanyName = UNGM.ImplementingPartner.normalizeCompanyName(sender.val());
        sender.val(newCompanyName);

        if (sender.valid()) {
            if (!newCompanyName.length) {
                return false;
            }
            if (UNGM.ImplementingPartner.isNewCompanyNameEqualToOldCompanyName()) {
                sender.siblings(".noChangeInCompanyName").show();
                return false;
            }
            sender.siblings(".noChangeInCompanyName").hide();

            sender.siblings(".checkingAvailability").show();
            $.ajax({
                url: UNGM.siteRoot + 'Account/Registration/IsCompanyNameAvailable?companyName=' + encodeURIComponent(newCompanyName) + "&vendorId=" + UNGM.ImplementingPartner.currentImplementingPartnerId,
                type: 'GET',
                contentType: 'application/json',
                success: UNGM.ImplementingPartner.onCheckedCompany
            });
        }
    },
    onCheckedCompany: function (response) {
        var box = $("#CompanyName");
        $(".checkingAvailability").hide();

        if (response.isAvailable) {
            UNGM.Validation.markElementValid(box);
            $("#frmCompanyNameChange .companyExists").hide();
            UNGM.ImplementingPartner.companyNameIsAvailable = true;
            UNGM.Validation.validateElement(box);
        } else {
            UNGM.Validation.markElementInvalid(box);
            UNGM.ImplementingPartner.companyNameIsAvailable = false;
            $("#frmCompanyNameChange .companyExists").show();
        }
    },
    changeName: function () {

        UNGM.throbOver($("#frmGeneral"));
        var postObj = { 'currentCompanyName': $("#CompanyName").val() };
        $.ajax({
            type: 'POST',
            url: UNGM.siteRoot + 'Vendor/Registration/CompanyNameChange',
            data: postObj,
            success: function (data) {
                var newForm = $(data);
                elements.contextForm = newForm;
                UNGM.hideThrobber();
                UNGM.Validation.initForElement(elements.contextForm);
                $("#divNameChange").html(elements.contextForm);
                $("#divNameChange").find("#btnSaveChangeName").off("click").on("click", UNGM.ImplementingPartner.saveChangeName);
                $("#divNameChange").find("#ChangeCompanyBox").off("focusout").on("focusout", UNGM.ImplementingPartner.changeCompanyNameLostFocus);
                $("#divNameChange").find("#ChangeCompanyBox").off("focusin").on("focusin", UNGM.ImplementingPartner.companyGotFocus);
                $("#divNameChange").dialog({
                    modal: true,
                    width: '80%',
                    hide: { effect: 'fade', duration: 100 },
                    show: { effect: 'fade', duration: 100 }
                });
                $("#divNameChange").css('maxHeight', $(window).height() * 0.8);
            }
        });
    },
    commentsLostFocus: function (evt) {
        var sender = $("#Comments");
        if ($("#Reason option:selected").val() != "Other") {
            UNGM.Validation.markElementValid(sender);
        }
    },
    reasonChange: function (evt) {
        var sender = $("#Comments");
        UNGM.Validation.markElementValid(sender);
    },
    saveChangeName: function (evt) {
        var docElement = $("#CertificateOfIncorporationDocumentId");
        if (docElement.length > 0 && docElement.val() === "") {
            $(".requiredDocument").show();
            err = true;
            return;
        }
        else {
            $(".requiredDocument").hide();
        }
        if (!UNGM.ImplementingPartner.companyNameIsAvailable) {
            err = true;
            return;
        }

        if ($("#frmCompanyNameChange").valid() && !UNGM.ImplementingPartner.isNewCompanyNameEqualToOldCompanyName()) {
            var obj = {};
            obj.CompanyName = $("#OldCompanyName").val();
            obj.Reason = $("#Reason option:selected").val();
            obj.Comments = $("#Comments").val();
            obj.CertificateOfIncorporationDocumentId = $("#CertificateOfIncorporationDocumentId").val();
            obj.VendorId = UNGM.ImplementingPartner.currentImplementingPartnerId;
            obj.NewCompanyName = $("#ChangeCompanyBox").val(); // Save current company name as change company name

            UNGM.throbOver($("#divNameChange"));

            $.ajax({
                url: UNGM.siteRoot + 'Vendor/Registration/SaveCompanyNameChange',
                type: 'POST',
                contentType: 'application/json',
                data: JSON.stringify(obj),
                success: function () {
                    window.location.href = window.location.href;
                }
            });
        }
    },
    normalizeCompanyName: function (companyName) {
        return $.trim(companyName.replace(/\s+/g, ' '));
    },
    isNewCompanyNameEqualToOldCompanyName: function () {
        var oldCompanyName = $("#OldCompanyName").val();
        var newCompanyName = $("#ChangeCompanyBox").val();
        return oldCompanyName === newCompanyName.trim();
    },
    acceptRegistrationInvitation: function (evt) {
        var form = $(evt.currentTarget).parents('form');
        if ($("#CodeOfConduct:checked").length == 0) {
            evt.preventDefault();
            $("#divCocRejected").show();
            $("#divCoc").hide();
            return;
        }
        if (form.valid()) {
            var postObject = {};
            postObject.UserName = form.find("#UserName").val();
            postObject.CompanyName = form.find("#CompanyName").val();
            postObject.FirstName = form.find("#FirstName").val();
            postObject.LastName = form.find("#LastName").val();
            postObject.CountryId = form.find("#CountryId").val();
            postObject.Password = form.find("#Password").val();
            postObject.CompanyDirectorFirstName = form.find("#CompanyDirectorFirstName").val();
            postObject.CompanyDirectorLastName = form.find("#CompanyDirectorLastName").val();
            postObject.CodeOfConduct = true;
            UNGM.throbOver(form);
            $.ajax({
                type: "POST",
                url: form.attr('action'),
                contentType: 'application/json',
                data: JSON.stringify(postObject),
                success: UNGM.ImplementingPartner.acceptRegistrationComplete,
                complete: function () { UNGM.hideThrobber(); }
            });
        }
    },
    acceptRegistrationComplete: function (data) {
        UNGM.hideThrobber();
        if (data.success) {
            // Show welcome popup
            var OkHandler = function () {
                // Redirect to Home
                location.href = $("#RedirectToHome").val();
            };
            $.confirm(data.title, data.message, data.okButton, "", OkHandler);
        }
        else {
            $.confirm(data.title, data.message, data.okButton, "", function () { });
        }
    },
    checkCountryAndFiscalCodeUnique: function (e) {
        UNGM.ImplementingPartner.hasGeneralCountryChanged = true;
        UNGM.ImplementingPartner.isGeneralCountryChangedBackToInitialValue(e);
        UNGM.VendorAccountRegistration.checkCountryAndFiscalCodeUnique(e);
    },
    onIndividualConsultantTypeClicked: function (e) {
        UNGM.ImplementingPartner.hasIndividualConsultantTypeChanged = true;
        if ($('#individualConsultantTypeDescription').is(":visible") == false) {
            $('#individualConsultantTypeDescription').show();
        }
        $('#individualConsultantTypeDescription').text($(this).attr('data-description'));
        UNGM.ImplementingPartner.isIndividualConsultantTypeChangedBackToInitialValue(e);
    },
    isGeneralCountryChangedBackToInitialValue: function (e) {
        var sender = $(e.currentTarget);
        if (sender.val() == $('#OldGeneralCountryId').val()) {
            UNGM.ImplementingPartner.hasGeneralCountryChanged = false;
        }
    },
    isIndividualConsultantTypeChangedBackToInitialValue: function (e) {
        var sender = $(e.currentTarget);
        if (sender.val() == $('#OldIndividualConsultantTypeId').val()) {
            UNGM.ImplementingPartner.hasIndividualConsultantTypeChanged = false;
        }
    },
    onCompanyOwnershipTypeChanged: function () {
        var elements = $('[data-enable-if-ownership-type]');
        elements.each(function (_index, item) {
            var element = $(item);
            var enable = UNGM.ImplementingPartner.isOwnershipTypeEnabled(element);
            if (enable) {
                element.slideDown(300);
            } else {
                element.slideUp(300);
            }
        });
        setTimeout(UNGM.ImplementingPartner.onCompanyWomenOwnershipChanged, 400);
    },
    onCompanyWomenOwnershipChanged: function () {
        var elements = $('[data-enable-if-women-ownership]');
        elements.each(function (_index, item) {
            var element = $(item);
            var enable = UNGM.ImplementingPartner.isWomenOwnershipEnabled(element);
            if (enable) {
                element.slideDown(300);
            } else {
                element.slideUp(300);
            }
        });
    },
    isOwnershipTypeEnabled: function (element) {
        var ownerships = JSON.parse(element.attr('data-enable-if-ownership-type'));
        var ownershipType = $('[name=OwnershipType]').filter(function (_index, item) { return $(item).prop('checked'); }).val();
        return $.inArray(ownershipType, ownerships) !== -1;
    },
    isWomenOwnershipEnabled: function (element) {
        var womenOwnerships = JSON.parse(element.attr('data-enable-if-women-ownership'));
        var womenOwnership = $('[name=WomenOwnership]').filter(function (_index, item) { return $(item).prop('checked'); }).val();
        return $('[name=WomenOwnership]').is(':visible') && $.inArray(womenOwnership, womenOwnerships) !== -1;
    },
    onTenderAlertServiceTabClicked: function () {
        UNGM.ImplementingPartner.tenderAlertServiceTabCallback();
    },
    setTenderAlertServiceTabCallback: function (callback) {
        UNGM.ImplementingPartner.tenderAlertServiceTabCallback = callback;
    },
    onImplementingPartnerTypeChanged: function() {
        var selectedValue = $(this).val();
        $(".typeDescription").hide();
        $("#" + selectedValue).show();
    }
};;
window.UNGM.VendorAccountRegistration = {
    companyInvalid: true,
    countryAndFiscalCodeInvalid: false,
    init: function () {
        $("#CompanyName").on("focusin", UNGM.VendorAccountRegistration.companyGotFocus);
        $("#CompanyName").on("focusout", UNGM.VendorAccountRegistration.companyLostFocus);
        $("#autoPopulateUserDetails").bind("change", UNGM.VendorAccountRegistration.autoPopulateUserDetailsChanged);
        $("#Password").bind("keyup", UNGM.ManageAccount.onPasswordKeyUp);
        $("#formSubmit").on("click",
            function() {
                $("form").submit();
            });
        $("form").bind("submit", UNGM.VendorAccountRegistration.validateForm);
        $("#FiscalCode").on("focusout", UNGM.VendorAccountRegistration.checkCountryAndFiscalCodeUnique);
        $("#GeneralCountryId").on("change", UNGM.VendorAccountRegistration.checkCountryAndFiscalCodeUnique);        
        $("input[name=IndividualConsultantTypeId]:radio").on("click", UNGM.VendorAccountRegistration.onIndividualConsultantTypeClicked);        
        $("#CodeOfConduct").bind("change", UNGM.VendorAccountRegistration.codeOfConductChanged);

    },
    validateForm: function(e) {
        e.preventDefault();
        var form = $(e.currentTarget);
        UNGM.removeError();

        if (!$("#CodeOfConduct").prop("checked")) {
            $("#CodeOfConduct-error").parent().css("display", "block");
        }

        if (($("#CompanyName").length && UNGM.VendorAccountRegistration.companyInvalid) ||
            !UNGM.EmailValidation.verified ||
            UNGM.VendorAccountRegistration.countryAndFiscalCodeInvalid ||
            !form.valid() ||
            !$("#CodeOfConduct").is(":checked")) {
            return false;
        }

        grecaptcha.execute();

        return true;
    },
    submitForm: function () {
        UNGM.throbOver();
        var form = $("#frmVendorAccount");
        var data = form.serialize();
        var dateAdClicked = localStorage.getItem('dateAdClicked');
        if (dateAdClicked) {
            data += `&DateAdClicked=${encodeURIComponent(dateAdClicked)}`;
        }

        $.ajax({
            url: form.attr("action"),
            type: 'POST',
            data: data,
            global: false,  // Disable global events, as UNGM.ajaxErrorHandler 
            success: function () {
                window.location = UNGM.siteRoot + "Account/Registration/ActivatePending";
            },
            error: function (response) {
                UNGM.appendErrorTo(form, response.responseJSON);
                UNGM.hideThrobber();
            }
        });
    },
    companyGotFocus: function () {
        $(".checkingAvailability, #companyExists").hide();
    },
    companyLostFocus: function (e) {
        var sender = $(e.currentTarget);
        var company = sender.val();

        if (!sender.valid() || !company.length) {
            return;
        }

        sender.siblings(".checkingAvailability").show();
        $.ajax({
            url: UNGM.siteRoot + 'Account/Registration/IsCompanyNameAvailable?companyName=' + encodeURIComponent(company) + "&vendorId=" + UNGM.VendorRegistration.currentVendorId,
            type: 'GET',
            contentType: 'application/json',
            success: UNGM.VendorAccountRegistration.onCheckedCompany
        });
    },
    onCheckedCompany: function (response) {
        var box = $("#CompanyName");
        $(".checkingAvailability").hide();

        if (response.isAvailable) {
            UNGM.Validation.markElementValid(box);
            box.attr("aria-invalid", false);
            $("#companyExists").hide();
            UNGM.VendorAccountRegistration.companyInvalid = false;
            UNGM.Validation.validateElement(box);
        } else {
            UNGM.Validation.markElementInvalid(box);
            box.attr("aria-invalid", true);
            UNGM.VendorAccountRegistration.companyInvalid = true;
            $("#companyExists").show();

            var ariaDescribedby = box.attr("aria-describedby");
            if (ariaDescribedby.indexOf("companyExists") === -1) {
                box.attr("aria-describedby", ariaDescribedby + " companyExists");
            }
        }
    },
    autoPopulateUserDetailsChanged: function (e) {
        var checkbox = $(e.currentTarget);

        if (checkbox.is(":checked")) {
            $("#FirstName").val($("#CompanyDirectorFirstName").val());
            $("#LastName").val($("#CompanyDirectorLastName").val());
        }
        else {
            $("#FirstName, #LastName").val("");
        }
    },
    checkCountryAndFiscalCodeUnique: function (e) {
        var sender = $(e.currentTarget);

        if (!sender.valid() || !sender.val()) {
            $(".duplicateOfCountryAndFiscalCode").hide();
            return;
        }

        sender.siblings(".checkingForUnique").show();
        var generalCountryId = $("#GeneralCountryId").val();
        var fiscalCode = $("#FiscalCode").val();
        if (generalCountryId.length > 0 && fiscalCode.length > 0) {
            $.ajax({
                url: UNGM.siteRoot + 'Account/Registration/IsCombinationOfCountryAndFiscalCodeUnique',
                data: {
                    generalCountryId: generalCountryId,
                    fiscalCode: fiscalCode,
                    vendorId: UNGM.VendorRegistration.currentVendorId
                },
                type: 'GET',
                contentType: 'application/json',                
                success: function (response) {
                    sender.siblings(".checkingForUnique").hide();
                    if (response == false) {                        
                        UNGM.Validation.markElementInvalid($("#GeneralCountryId"));
                        UNGM.Validation.markElementInvalid($("#FiscalCode"));
                        $("#FiscalCode,#GeneralCountryId").attr("aria-invalid", true);
                        UNGM.VendorAccountRegistration.countryAndFiscalCodeInvalid = true;
                        $(".duplicateOfCountryAndFiscalCode").show();

                        var ariaDescribedby = $("#FiscalCode").attr("aria-describedby");
                        if (ariaDescribedby.indexOf("duplicateOfCountryAndFiscalCode-error") === -1) {
                            $("#FiscalCode").attr("aria-describedby", ariaDescribedby + " duplicateOfCountryAndFiscalCode-error");
                        }
                    } else {                                                
                        UNGM.Validation.markElementValid(sender);
                        $("#FiscalCode,#GeneralCountryId").attr("aria-invalid", false);
                        UNGM.VendorAccountRegistration.countryAndFiscalCodeInvalid = false;
                        $(".duplicateOfCountryAndFiscalCode").hide();                        
                    }
                }
            });
        }
        else {
            sender.siblings(".checkingForUnique").hide();            
        }        
    },
    onIndividualConsultantTypeClicked: function () {
        $('#individualConsultantTypeDescription').show();
        $('#individualConsultantTypeDescription').text($(this).attr('data-description'));        
    }, 
    codeOfConductChanged: function() {
        $("#CodeOfConduct-error").parent().hide();
    }
}
;
window.UNGM.AcceptInvitation = {
    invalidInvitationTitle: '',
    invalidInvitationButton: '',
    unknownErrorMessage: '',
    invalidInvitationText: '',
    activeEmailExistsText: '',
    inviteSuccessfullyAcceptedTitle: '',
    inviteSuccessfullyAcceptedButton: '',
    inviteSuccessfullyAcceptedText: '',
    init: function () {
        $("#btnSave").on("click", UNGM.AcceptInvitation.saveClicked);
        $("#Password").off("keyup").on("keyup", UNGM.ManageAccount.onPasswordKeyUp);
    },
    saveClicked: function (evt) {
        var form = $(evt.currentTarget).parents('form');
        if (form.valid()) {

            var Info = {
                Id: form.find("#Id").val(),
                UserTitle: form.find("#Info_UserTitle").val(),
                FirstName: form.find("#Info_FirstName").val(),
                MiddleName: form.find("#Info_MiddleName").val(),
                Surname: form.find("#Info_Surname").val(),
                CompanyPosition: form.find("#Info_CompanyPosition").val(),
                Position: form.find("#Info_Position").val(),
                CountryId: form.find("#Info_CountryId").val(),
                Email: form.find("#Info_Email").val(),
                ContactTelephoneCountryId: form.find("#Info_ContactTelephoneCountryId").val(),
                TelephoneNumber: form.find("#Info_TelephoneNumber").val(),
                TelephoneExtension: form.find("#Info_TelephoneExtension").val(),
                MobileCountryId: form.find("#Info_MobileCountryId").val(),
                MobileNumber: form.find("#Info_MobileNumber").val(),
                ReceiveMarketingEmails: form.find("input[name='Info.ReceiveMarketingEmails']:checked").val()
            };
            var postObject = {
                Info: Info,
                Password: form.find("#Password").val(),
                ConfirmPassword: form.find("#ConfirmPassword").val(),
                InviteToken: $('#InviteToken').val(),
                ReceiveMarketingEmails: form.find("input[name='ReceiveMarketingEmails']:checked").val()
            };
            

            UNGM.throbOver(form);
            $.ajax({
                type: "POST",
                url: form.attr('action'),
                contentType: 'application/json',
                data: JSON.stringify(postObject),
                success: UNGM.AcceptInvitation.saveComplete,
                global: false,  // Disable global events, as UNGM.ajaxErrorHandler 
                error: function (response) {
                    UNGM.appendErrorTo(form, response.responseJSON);
                    UNGM.hideThrobber();
                },
                complete: function () { UNGM.hideThrobber(); }
            });
        }
    },
    saveComplete: function (data) {
        UNGM.hideThrobber();
        if (data.success) {
            // Show welcome popup
            var OkHandler = function () {
                // Redirect to Home
                location.href = UNGM.siteRoot + 'Account/Account/CheckUser?' + $("#RedirectToHome").val();
            };
            $.confirm(UNGM.AcceptInvitation.inviteSuccessfullyAcceptedTitle,
                UNGM.AcceptInvitation.inviteSuccessfullyAcceptedText,
                UNGM.AcceptInvitation.inviteSuccessfullyAcceptedButton,
                "",
                OkHandler);
        }
        else {
            var msg = '';
            switch(data.reason)
            {
                case "ActiveEmailExists":
                    msg = UNGM.AcceptInvitation.activeEmailExistsText;
                    break;
                case "Unknown":
                    msg = UNGM.AcceptInvitation.unknownErrorMessage;
                    break;
                case "InvalidInvitation":
                    msg = UNGM.AcceptInvitation.invalidInvitationText;
                    break;
            }

            $.confirm(UNGM.AcceptInvitation.invalidInvitationTitle,
                    msg,
                    UNGM.AcceptInvitation.invalidInvitationButton,
                    "",
                    function () { });
        }
    }
}
;
UNGM.TASDashboard = {
    generalFolder: {
        pageIndex: 0,
        prevPageIndex: 0,
        paging: false,
        inSearch: false,
        folderId: ""
    },
    tasVoucherFolder: {
        pageIndex: 0,
        prevPageIndex: 0,
        paging: false,
        inSearch: false,
        folderId: "tasVoucherList",
        isContentLoaded: false
    },
    tabToggledCallback: {},
    updatePlansCallback: null,
    init: function () {
        $(".lnkShowUsers").bind("click", UNGM.TASDashboard.onLnkShowUsersClicked);
        $("#txtDateFrom, #txtDateTo").bind("change", UNGM.TASDashboard.refreshReport);

        // Set default dates
        var day1OfThisMonth = new Date(new Date().setDate(1));
        $("#txtDateFrom").datepicker('setDate', day1OfThisMonth);
        $("#txtDateTo").datepicker('setDate', new Date());

        $(".tabHeader").bind("click", UNGM.TASDashboard.toggleTab);
    },
    setTabToggledCallback: function (tab, callback) {
        UNGM.TASDashboard.tabToggledCallback[tab] = callback;
    },
    setUpdatePlansCallback: function (callback) {
        UNGM.TASDashboard.updatePlansCallback = callback;
    },
    triggerUpdatePlans: function (plans) {
        if (UNGM.TASDashboard.updatePlansCallback) {
            UNGM.TASDashboard.updatePlansCallback(plans);
        }
    },
    toggleTab: function (e) {
        var toggledTab = $(e.currentTarget).data("tabid");
        $.each(UNGM.TASDashboard.tabToggledCallback, function (tab) {
            var callback = UNGM.TASDashboard.tabToggledCallback[tab];
            callback(tab === toggledTab);
        });
    },
    OnGotData: function (response) {
        UNGM.TASDashboard.generalFolder.prevPageIndex = UNGM.TASDashboard.generalFolder.pageIndex;
        if (response.length) {
            var $folderContainer = $("#" + UNGM.TASDashboard.generalFolder.folderId + "Folder")
            var $tableBody = $folderContainer.find(".tableBody");
            $tableBody.children("script").remove();

            if (UNGM.TASDashboard.generalFolder.paging) {
                $tableBody.append(response);
                UNGM.TASDashboard.generalFolder.paging = false;
            }
            else {
                $tableBody.html(response);
            }

            UNGM.ieHackTableCells();
        }

        var showing = $tableBody.find(".tableRow").length;
        $folderContainer.find(".showing").html(showing);

        if (showing > 0) {
            $folderContainer.find("#" + UNGM.TASDashboard.generalFolder.folderId + "Empty").hide();
            $folderContainer.find(".resultsContainer").show();
        }
        else {
            $folderContainer.find("#" + UNGM.TASDashboard.generalFolder.folderId + "Empty").show();
            $folderContainer.find(".resultsContainer").hide();
        }

        UNGM.TASDashboard.setWaypoints();
        UNGM.hideThrobber();
    },
    setWaypoints: function () {
        // Only set the waypoints if there are more items to load
        var $folder = $("#" + UNGM.TASDashboard.generalFolder.folderId + "Folder");

        if ($folder.find(".showing").html() == $folder.find(".searchTotal").html()) {
            return;
        }

        $folder.find(".folderHolder").waypoint(function (direction) {
            if (direction === 'down') {
                if (!UNGM.TASDashboard.generalFolder.inSearch) {
                    $.waypoints('destroy');
                    UNGM.TASDashboard.generalFolder.inSearch = true;
                    UNGM.TASDashboard.generalFolder.pageIndex = UNGM.TASDashboard.generalFolder.prevPageIndex + 1;
                    UNGM.TASDashboard.generalFolder.paging = true;
                    UNGM.TASDashboard.searchFunction();
                }
            }
        }, { offset: 'bottom-in-view' });
        UNGM.TASDashboard.generalFolder.inSearch = false;
    },
    buildOptions: function () {
        var opts = {
            dateFrom: UNGM.getDatepickerVal("#txtDateFrom"),
            dateTo: UNGM.getDatepickerVal("#txtDateTo"),
        };

        return opts;
    },
    refreshReport: function () {
        var opts = UNGM.TASDashboard.buildOptions();

        UNGM.throbOver(".tasReports");
        $.ajax({
            url: UNGM.siteRoot + 'Admin/TASDashboard/TenderAlertServiceReport',
            type: 'POST',
            contentType: 'application/json',
            data: JSON.stringify(opts),
            success: UNGM.TASDashboard.onGotReportData
        });
    },
    onGotReportData: function (data) {
        $("#tenderAlertServiceReports").html(data);
        $(".lnkShowUsers").off("click").on("click", UNGM.TASDashboard.onLnkShowUsersClicked);

        UNGM.hideThrobber();
    },
    onLnkShowUsersClicked: function (e) {
        UNGM.throbOver(".tasReports");

        var $link = $(e.currentTarget);
        var title = $link.parents(".reportRow").find("label").text();
        var reportName = $link.data("reportname");

        var opts = UNGM.TASDashboard.buildOptions();

        $.ajax({
            url: UNGM.siteRoot + 'Admin/TASDashboard/' + reportName + '?dateFrom=' + opts.dateFrom + '&dateTo=' + opts.dateTo,
            type: 'GET',
            contentType: 'application/json',
            success: function (data) {
                UNGM.TASDashboard.onGotUsersData(data, title, reportName);
            }
        });
    },
    onGotUsersData: function (data, title, reportName) {
        $("<div>").html(data).dialog({
            title: title,
            modal: true,
            width: '80%',
            height: "600",
            hide: { effect: 'fade', duration: 100 },
            show: { effect: 'fade', duration: 100 },
            open: function () {
                $("#btnExportToExcel").data("reportName", reportName).bind("click", UNGM.TASDashboard.onBtnExportToExcelClicked);
                UNGM.ieHackTableHeader();
                UNGM.hideThrobber();
            },
            close: function () {
                $(this).dialog('destroy').remove();
            }
        });
    },
    onBtnExportToExcelClicked: function (e) {
        // Have to use a GET as we can't get a binary response via jQuery AJAX and we can't send a POST using window.location.href
        var opts = UNGM.TASDashboard.buildOptions();
        var reportName = $(e.currentTarget).data("reportName");
        window.location.href = UNGM.siteRoot + 'Admin/TASDashboard/' + reportName + 'ToExcel?dateFrom=' + opts.dateFrom + '&dateTo=' + opts.dateTo;
    }
};
window.UNGM.AcceptRegistration = {
    init: function () {
        $("#btnCancel").bind("click", UNGM.AcceptRegistration.cancelClicked);
        $("#btnSave").bind("click", UNGM.AcceptRegistration.saveClicked);
        $("#Password").off("keyup").on("keyup", UNGM.ManageAccount.onPasswordKeyUp);
    },
    saveClicked: function (evt) {
        var form = $(evt.currentTarget).parents('form');
        if (form.valid()) {

            var Info = {
                Id: form.find("#Id").val(),
                UserTitle: form.find("#Info_UserTitle").val(),
                FirstName: form.find("#Info_FirstName").val(),
                MiddleName: form.find("#Info_MiddleName").val(),
                Surname: form.find("#Info_Surname").val(),
                CompanyPosition: form.find("#Info_CompanyPosition").val(),
                CountryId: form.find("#Info_CountryId").val(),
                Email: form.find("#Info_Email").val(),
                ContactTelephoneCountryId: form.find("#Info_ContactTelephoneCountryId").val(),
                TelephoneNumber: form.find("#Info_TelephoneNumber").val(),
                TelephoneExtension: form.find("#Info_TelephoneExtension").val(),
                MobileCountryId: form.find("#Info_MobileCountryId").val(),
                MobileNumber: form.find("#Info_MobileNumber").val()
            };
            var postObject = {
                Info: Info,
                Password: form.find("#Password").val(),
                ConfirmPassword: form.find("#ConfirmPassword").val(),
                ActivationCode: $('#ActivationCode').val()
            };

            UNGM.throbOver(form);
            $.ajax({
                type: "POST",
                url: form.attr('action'),
                contentType: 'application/json',
                data: JSON.stringify(postObject),
                success: UNGM.AcceptRegistration.saveComplete,
                complete: function () { UNGM.hideThrobber(); }
            });
        }
    },
    saveComplete: function (data) {
        UNGM.hideThrobber();
        if (data.success) {
            // Show welcome popup
            var OkHandler = function () {
                // Redirect to Home
                location.href = UNGM.siteRoot + 'Account/Account/CheckUser?';
            };
            $.confirm(data.title, data.message, data.okButton, "", OkHandler);
        }
        else {
            $.confirm(data.title, data.message, data.okButton, "", function () { });
        }
    }
};
(function (namespace, undefined) {

    ////////////////////////////////////////////////////////////////////////////////
    //
    // Detail
    //

    namespace.Detail = function (element) {
        $this = this;
        this.element = element;
        this.children = this.element.find(".children-area");
        this.childrenRefreshUrl = this.children.data("children-refresh-url");
        this.childrenEmptyMessage = this.children.find(".children-empty-message");
        this.childrenListArea = this.children.find(".children-list-area");
        this.childrenList = this.children.find(".children-list");
        this.childTemplate = new ChildTemplate(this.children.find(".child.template"));
        this.btnReset = this.element.find("#btnReset");
        this.btnSearch = this.element.find("#btnSearch");
        this.txtKeywords = this.element.find("#txtKeywords");
        this.btnReset.off("click").on("click", function () { location.reload() } );
        this.btnSearch.off("click").on("click", this.doSearch(element));
        this.txtKeywords.off("keypress").on("keypress", function (e) {
            if (e.keyCode == 13) {
                $this.doSearch(element).call();
    }
        });
    }

    namespace.Detail.prototype.SetCallbackOnChildRender = function (callbackOnChildRender) {
        this.callbackOnChildRender = callbackOnChildRender;
    }

    namespace.Detail.prototype.RefreshChildren = function () {
        var deferred = $.Deferred();
        var $this = this;
        UNGM.Throbber.Push();
        $.post(this.childrenRefreshUrl, function (children) {
            if (typeof (children) == "string") { children = JSON.parse(children); }
            $this.RenderChildren(children);
            deferred.resolve(children);
            UNGM.Throbber.Pop();
        });
        return deferred.promise();
    }

    namespace.Detail.prototype.RenderChildren = function (children) {
        if (typeof (children) == "string") { children = JSON.parse(children); }
        var $this = this;
        this.childrenList.empty();
        if (children.length === 0) {
            this.childrenEmptyMessage.show();
            this.childrenListArea.hide();
        } else {
            $.each(children, function (index, child) {
                var row = $this.childTemplate.Render(child);
                if ($this.callbackOnChildRender !== undefined) { $this.callbackOnChildRender(row); }
                $this.childrenList.append(row);
            });
            this.childrenEmptyMessage.hide();
            this.childrenListArea.show();
        }
    }

    namespace.Detail.prototype.BindAction = function (element, callbackOnDialogLoaded, callbackOnActionTaken) {
        var $this = this;
        element.click(function (event) {
            var button = $(this);
            var url = button.data("action-url");
            if (button.hasClass("display-in-dialog")) {
                var title = button.data("dialog-title");
                $this.OpenDialog(title, url, callbackOnDialogLoaded);
            } else if (button.hasClass("action-no-dialog")) {
                var data = {};
                var key = button.data("action-data-key");
                if (key !== undefined) { data[key] = button.data("action-data-value"); }
                $this.TakeAction(url, data, button, callbackOnActionTaken);
            } else {
                location.href = url;
            }
        });
    }

    namespace.Detail.prototype.OpenDialog = function (title, url, callbackOnDialogLoaded) {
        var $this = this;
        UNGM.Throbber.Push();
        UNGM.initJQueryUIDialogWithCKEDITOR();
        $.get(url, function (result) {
            var childFormDialog = namespace.Detail.GetChildDialogHolder();
            childFormDialog.html(result).dialog({
                modal: true,
                title: title,
                width: "50%",
                height: "auto",
                hide: { effect: "fade", duration: 100 },
                show: { effect: "fade", duration: 100 }
            });
            if (callbackOnDialogLoaded !== undefined) { callbackOnDialogLoaded(childFormDialog); }
            UNGM.Throbber.Pop();
        });
    }

    namespace.Detail.prototype.TakeAction = function (url, data, button, callbackOnActionTaken) {
        var $this = this;
        UNGM.Throbber.Push();
        $.post(url, data, function (result) {
            if (callbackOnActionTaken !== undefined) { callbackOnActionTaken(button); };
            UNGM.Throbber.Pop();
        });
    }

    namespace.Detail.GetChildDialogHolder = function () {
        //
        // static function to reuse dialog holder
        //
        // NOTE: This is required because CKEDITOR is in used for the child form.
        // If there are multiple dialog holders, the code would fail the second time
        // the form is loaded because CKEDITOR has already been initialised for the
        // textarea with the same id.
        //
        return this.childDialogHolder = this.childDialogHolder || $("<div></div>");
    }

    ////////////////////////////////////////////////////////////////////////////////
    //
    // ChildTemplate
    //

    function ChildTemplate(element) {
        this.template = element.removeClass("template")[0];
    }

    ChildTemplate.prototype.Render = function (child) {
        var regex = new RegExp("{{\\s*(\\w+)\\s*([|]\\s*(\\w+)\\s*)?}}", "g"); // matching {{ key | filter }}
        var html = this.template.outerHTML.replace(regex, function (match, key, _, filter, _, _) {
            var value = child[key];
            if (value === undefined) { return match; }
            if (filter !== undefined) {
                switch (filter.toLowerCase()) {
                    case "replace_line_break_with_br": return value.replace(/\n/g, "<br />");
                    case "strip_tags_and_trim": return UNGM.Forum.Formatter.StripTagAndTrim(value, 120);
                    case "datetime": return UNGM.Forum.Formatter.FormatDateTime(value);
                    case "date": return UNGM.Forum.Formatter.FormatDate(value);
                    case "time": return UNGM.Forum.Formatter.FormatTime(value);
                    case "bool": return value == true ? "Yes" : "No";
                }
            }
            return value;
        });
        var renderredElement = $(html);
        renderredElement.find("[data-render-if]").each(function (_index, item) {
            var renderIf = eval($(item).data("render-if"));
            var render = renderIf === true || renderIf === "true";
            if (!render) { $(item).remove(); }
            $(item).removeAttr("data-render-if");
        });
        return renderredElement;
    }

    namespace.Detail.prototype.doSearch = function (element) {
        return function () {            
            var keywords = element.find("#txtKeywords").val().trim();
            var cleanText = keywords.replace(/<\/?[^>]+(>|$)/g, "");
            if (cleanText.trim().length > 0) {
                UNGM.Throbber.Push();
                var url = UNGM.siteRoot + "Shared/Forum/Search";
                    $.get(url, { id: element.attr("data-forum-id"), keywords: cleanText })
                .success(function (response) {
                        element.find(".search-area").html(response);
                    element.find(".children-area").hide();
                })
                .always(function () { 
                    UNGM.Throbber.Pop(); 
                });
            }
        }            
    }   

})(window.UNGM.Forum = window.UNGM.Forum || {});
;
(function (namespace, undefined) {

    ////////////////////////////////////////////////////////////////////////////////
    //
    // Form
    //

    namespace.Form = function (element) {
        this.form = element;
        this.submit = this.form.find("input[type='submit']");

        var $this = this;
        this.submit.click(function (event) { $this.Submit(event); });

        this.ckeditor = new CkeditorAdapter(this.form.find(".ckeditor"), UNGM.standardToolbarWithSource, this.form);
    }

    namespace.Form.prototype.SetCallbackOnSuccess = function (callbackOnSuccess) {
        this.callbackOnSuccess = callbackOnSuccess;
    }

    namespace.Form.prototype.Submit = function (event) {
        event.preventDefault();
        this.ckeditor.UpdateElement();
        if (this.form.valid()) {
            UNGM.Throbber.Push();
            var data = {};
            var inputs = this.form.find("input[type='hidden'], input[type='text'], textarea");
            inputs.each(function (index, input) {
                var key = $(input).attr('name');
                var value = $(input).val();
                data[key] = value;
            });
            var $this = this;
            $.post(this.form.attr("action"), data, function (result) {
                if ($this.callbackOnSuccess !== undefined) { $this.callbackOnSuccess(result); }
                UNGM.Throbber.Pop();
            });
        }
    }

    ////////////////////////////////////////////////////////////////////////////////
    //
    // CkeditorAdapter
    //

    function CkeditorAdapter(element, toolbar, form) {
        this.element = element;
        this.enabled = this.element.length !== 0;
        if (this.enabled) {
            this.ckeditor = CKEDITOR.replace(this.element.get(0), { toolbar: toolbar });
            this.validator = form.validate();
            this.validator.settings.ignore = "";

            var $this = this;
            this.ckeditor.on("blur", function () { $this.UpdateElement(); });
        }
    }

    CkeditorAdapter.prototype.UpdateElement = function () {
        if (this.enabled) {
            this.ckeditor.updateElement();
            this.validator.element(this.element);
        }
    }

})(window.UNGM.Forum = window.UNGM.Forum || {});
;
(function (namespace, undefined) {

    ////////////////////////////////////////////////////////////////////////////////
    //
    // Formatter
    //

    namespace.Formatter = function () {}

    namespace.Formatter.StripTagAndTrim = function (value, maxLength) {
        var text = value.trim().startsWith("<") ? $(value).text() : value;
        return text.length < maxLength ? text : text.substr(0, maxLength) + "...";
    }

    namespace.Formatter.FormatDateTime = function (value) {
        return namespace.Formatter.FormatDate(value) + " " + namespace.Formatter.FormatTime(value);
    }

    namespace.Formatter.FormatDate = function (value) {
        var datetime = new Date(value);
        return $.datepicker.formatDate("dd-M-yy", datetime);
    }

    namespace.Formatter.FormatTime = function (value) {
        var datetime = new Date(value);
        return datetime.toLocaleTimeString(namespace.Formatter.GetLocale(), { hour12: false });
    }

    namespace.Formatter.GetLocale = function () {
        return namespace.Formatter.locale = namespace.Formatter.locale || UNGM.currentuserCookieLanguage;
    }

})(window.UNGM.Forum = window.UNGM.Forum || {});
;
(function (namespace, undefined) {

    namespace.Search = function (element) {
        this.searchResults = element.find(".search-results");
        this.keywords = element.find("#txtKeywords");        
	    
        if (this.searchResults.length > 0 && this.keywords.val().trim().length > 0) {
            Highlight(this.searchResults, this.keywords);
	    }
	    
        function Highlight(element, keywords) {
	        var htmlElement = element.html();
                var term = keywords.val().trim().split(' ');
	        $.each(term, function (index, value) {
	            term = value.replace(/(\s+)/, "(<[^>]+>)*$1(<[^>]+>)*");        
	            var pattern = new RegExp("(" + term + ")(?!([^<]+)?>)", "gi");	        

	            htmlElement = htmlElement.replace(pattern, "<mark>$1</mark>");
	            htmlElement = htmlElement.replace(/(<mark>[^<>]*)((<[^>]+>)+)([^<>]*<\/mark>)/, "$1</mark>$2<mark>$4");
	        });	        
	        element.html(htmlElement);
	        element.find(".result-label").each(function (index) {	            
	            $(this).text($(this).text());// unhighlight	result labels           
	        });
	    }   
    }
})(window.UNGM.Forum = window.UNGM.Forum || {});;
(function (namespace, undefined) {

    namespace.Push = function () {
        namespace.Counter().Increase();
        namespace.Render();
    }

    namespace.Pop = function () {
        namespace.Counter().Decrease();
        namespace.DelayRender();
    }

    namespace.Reset = function () {
        // this function shouldn't be called if the throbber is maintained correctly
        namespace.Counter().Reset();
        UNGM.hideThrobber();
    }

    namespace.Render = function () {
        if (namespace.Counter().GetCount() > 0) {
            UNGM.throbOver();
            if (namespace.Counter().GetCount() === 1) {
                namespace.PleaseWait().Init();
            }
        } else {
            UNGM.hideThrobber();
            namespace.PleaseWait().Clear();
        }
    }
    
    namespace.DelayRender = function () {
        namespace.renderTimeoutId = namespace.renderTimeoutId || null;
        clearTimeout(namespace.renderTimeoutId);
        namespace.renderTimeoutId = setTimeout(namespace.Render, 300);
    }

    namespace.Counter = function () {
        return namespace.counter = namespace.counter || new Counter();
    }

    namespace.PleaseWait = function () {
        return namespace.pleaseWait = namespace.pleaseWait || new PleaseWait();
    }

    ////////////////////////////////////////////////////////////////////////////////
    //
    // Counter
    //

    function Counter() {
        this.counter = 0;
    }

    Counter.prototype.Increase = function () {
        ++this.counter;
    }
    
    Counter.prototype.Decrease = function () {
        this.counter = Math.max(this.counter - 1, 0);
    }
 
    Counter.prototype.GetCount = function () {
        return this.counter;
    }

    Counter.prototype.Reset = function () {
        // this function shouldn't be called if the throbber is maintained correctly
        this.counter = 0;
    }

    ////////////////////////////////////////////////////////////////////////////////
    //
    // Please Wait message
    //

    function PleaseWait() {
        this.Timeout = null;
    }

    PleaseWait.prototype.Init = function() {
        this.Timeout = setTimeout(UNGM.showPleaseWaitMessage, 7000);
        UNGM.hidePleaseWaitMessage();
    }

    PleaseWait.prototype.Clear = function () {
        clearTimeout(this.Timeout);
        UNGM.hidePleaseWaitMessage();
    }

})(window.UNGM.Throbber = window.UNGM.Throbber || {});
;
(function (namespace, undefined) {

    namespace.Map = function (parameter) {
        var $this = this;

        this.SearchFilter = new SearchFilter(parameter.SearchFilter);
        this.SearchFilter.OnChange(function () {
            $this.Search();
            $this.UpdateExecutiveSummaryContainer();
        });
        this.MapContainerId = parameter.MapContainerId;
        this.Gmap = null;
        this.Markers = [];
        this.Coordinates = [];
        this.MapOptionsZoom = parameter.MapOptionsZoom || 2;
        // Center the map in Algeria by default (it shows Denmark center-on top)
        this.MapOptionsLat = parameter.MapOptionsLat || 28.033;
        this.MapOptionsLon = parameter.MapOptionsLon || 1.659;
        this.MapDialogContent = parameter.MapDialogContent;
        this.MapLegend = parameter.MapLegend;
        this.MapLegendTextAmountInMillions = parameter.MapLegendTextAmountInMillions;
        this.MapLegendTextAmount = parameter.MapLegendTextAmount;
        // executive summary  
        this.DdlReportsForDownloadSelector = $(parameter.DdlReportsForDownloadSelector);
        this.DdlReportsForDownloadSelector.change(function (event) { $this.DownloadReport(event); });
        this.PdfContainerSelector = parameter.PdfContainerSelector;
        this.ExecutiveSummary2017Title = parameter.ExecutiveSummary2017Title;
        this.ExecutiveSummary2016Title = parameter.ExecutiveSummary2016Title;
        this.ExecutiveSummary2015Title = parameter.ExecutiveSummary2015Title;
        this.ExecutiveSummary2014Title = parameter.ExecutiveSummary2014Title;
        this.ExecutiveSummary2013Title = parameter.ExecutiveSummary2013Title;
        this.ExecutiveSummary2017Link = parameter.ExecutiveSummary2017Link;
        this.ExecutiveSummary2016Link = parameter.ExecutiveSummary2016Link;
        this.ExecutiveSummary2015Link = parameter.ExecutiveSummary2015Link;
        this.ExecutiveSummary2014Link = parameter.ExecutiveSummary2014Link;
        this.ExecutiveSummary2013Link = parameter.ExecutiveSummary2013Link;
        this.ExecutiveSummaryNotAvailableInfo = parameter.ExecutiveSummaryNotAvailableInfo;
        this.ExecutiveSummaryNotAvailableHolderSelector = parameter.ExecutiveSummaryNotAvailableHolderSelector;
        $this.UpdateExecutiveSummaryContainer();
    }

    namespace.Map.prototype.InitMap = function () {
        var $this = this;

        var mapOptions = {
            center: { lat: $this.MapOptionsLat, lng: $this.MapOptionsLon },
            zoom: $this.MapOptionsZoom,
            mapTypeId: google.maps.MapTypeId.ROADMAP
        };

        $this.Gmap = new google.maps.Map(document.getElementById($this.MapContainerId), mapOptions);
    }

    namespace.Map.prototype.Search = function () {
        var $this = this;
        UNGM.Throbber.Push();

        $this.ResetMarkers();

        // Get markers
        var data = $this.SearchFilter.GetData();
        $.ajax({
            url: UNGM.siteRoot + "Public/ASRDataArchive/GetVolumeOfAreaByYear",
            type: "POST",
            data: JSON.stringify({ year: data.Year, area: data.Area }),
            contentType: "application/json",
            success: function (response) {
                $this.LoadCoordinates(response);
                $this.RenderMarkers();
                UNGM.Throbber.Pop();
            }
        });
    }

    namespace.Map.prototype.Init = function () {
        var $this = this;

        UNGM.Throbber.Push();
        $this.InitMap();
        $this.Search();
        UNGM.Throbber.Pop();
    }

    namespace.Map.prototype.LoadCoordinates = function (response) {
        var $this = this;

        if (typeof response != 'object') { response = JSON.parse(response); }

        $this.Coordinates = response;
    }

    namespace.Map.prototype.RenderMarkers = function () {
        var $this = this;
        var createInfoWindows = $this.Coordinates.length < 40;

        $(this.MapLegend + " div").empty();
        $(this.MapLegend).fadeOut();

        for (var i = 0; i < $this.Coordinates.length; i++) {
            if ($this.Coordinates[i].Lat === null) {
                var amountInM = $this.Coordinates[i].Amount / 1000000;
                var text = "";
                if (amountInM > 0.1) {
                    text = this.MapLegendTextAmountInMillions.replace("[AREANAME]", $this.Coordinates[i].Name).replace("[AMOUNTINMILLIONS]", amountInM.toFixed(1));
                } else {
                    text = this.MapLegendTextAmount.replace("[AREANAME]", $this.Coordinates[i].Name).replace("[AMOUNT]", $this.Coordinates[i].Amount.toFixed(1));
                }
                $(this.MapLegend + " div").append(text + " <br/>");
                $(this.MapLegend).fadeIn();
                continue;
            }

            var marker = new google.maps.Marker({
                position: new google.maps.LatLng($this.Coordinates[i].Lat, $this.Coordinates[i].Lng),
                map: $this.Gmap,
                name: $this.Coordinates[i].Name,
                amount: $this.Coordinates[i].Amount,
                icon: $this.GetCircle($this.Coordinates[i].Amount)
            });

            if (createInfoWindows) {
                marker['infowindow'] = new google.maps.InfoWindow({
                    content: $this.Coordinates[i].Name
                });

                google.maps.event.addListener(marker, 'mouseover', function () {
                    this['infowindow'].open($this.Gmap, this);
                });

                google.maps.event.addListener(marker, 'mouseout', function () {
                    this['infowindow'].close();
                });
            }

            $this.Markers.push(marker);

            marker.addListener('click', function () {
                $this.OnMarkerClicked(this.name, this.amount);
            });
        }
    }

    namespace.Map.prototype.GetCircle = function (amount) {
        var scale = amount / 30000000;

        var circle = {
            path: google.maps.SymbolPath.CIRCLE,
            scale: scale > 10 ? scale : 10,
            fillOpacity: .5,
            fillColor: "blue",
            strokeColor: "white",
            strokeWeight: .8
        };

        return circle;
    }

    namespace.Map.prototype.OnMarkerClicked = function (name, amount) {
        var $this = this;

        $this.ShowMarkerDetail($this.SearchFilter.Year.GetData(), name, amount);
    }

    namespace.Map.prototype.ShowMarkerDetail = function (year, name, amount) {
        UNGM.Throbber.Push();
        var $this = this;

        var pdfUrl = UNGM.siteRoot + "Areas/Public/Downloads/ASR/" + year + "/Country/" + encodeURIComponent(name.replace(/ /g, '')).replace(/'/g, escape) + year + ".pdf#view=FitH";
        var dialogContent = "";
        var dialogDiv = $("<div>");

        $.ajax({
            url: pdfUrl,
            type: 'HEAD',   // Gets only size of the header, not the actual file
            global: false,  // Disable global events, as UNGM.ajaxErrorHandler 
            error: function () {
                var amountInM = amount / 1000000;
                dialogContent = "<div class='info'>" + $this.MapDialogContent.replace("{0}", name).replace("{1}", amountInM.toFixed(1)) + "</div>";
            },
            success: function () {
                var pdfViewer = UNGM.siteRoot + "Scripts/PDF/web/viewer.html?file=";
                dialogContent = "<iframe src='" + pdfViewer + pdfUrl + "' style='width: " + 0.6 * $(window).width() + "px; height: " + 0.7 * $(window).height() + "px;'></iframe>";
            },
            complete: function () {
                dialogDiv.html(dialogContent);
                dialogDiv.dialog({
                    modal: true,
                    title: name,
                    width: "auto",
                    height: "auto",
                    hide: { effect: 'fade', duration: 100 },
                    show: { effect: 'fade', duration: 100 }
                });
                UNGM.Throbber.Pop();
            }
        });
    }

    namespace.Map.prototype.ResetMarkers = function () {
        var $this = this;

        // Remove markers from map
        for (var i = 0; i < $this.Markers.length; i++) {
            $this.Markers[i].setMap(null);
        }

        $this.Markers = [];
    }

    namespace.Map.prototype.UpdateExecutiveSummaryContainer = function () {
        var $this = this;
        var selectedYear = $this.SearchFilter.Year.GetData();

        var executiveSummaryTitle = "";
        var executiveSummaryLink = "";

        // Unfortunately every year this needs to be updated
        if (selectedYear === "2017") {
            executiveSummaryTitle = $this.ExecutiveSummary2017Title;
            executiveSummaryLink = UNGM.siteRoot + $this.ExecutiveSummary2017Link;
        }
        if (selectedYear === "2016") {
            executiveSummaryTitle = $this.ExecutiveSummary2016Title;
            executiveSummaryLink = UNGM.siteRoot + $this.ExecutiveSummary2016Link;
        }
        if (selectedYear === "2015") {
            executiveSummaryTitle = $this.ExecutiveSummary2015Title;
            executiveSummaryLink = UNGM.siteRoot + $this.ExecutiveSummary2015Link;
        }
        if (selectedYear === "2014") {
            executiveSummaryTitle = $this.ExecutiveSummary2014Title;
            executiveSummaryLink = UNGM.siteRoot + $this.ExecutiveSummary2014Link;
        } else if (selectedYear === "2013") {
            executiveSummaryTitle = $this.ExecutiveSummary2013Title;
            executiveSummaryLink = UNGM.siteRoot + $this.ExecutiveSummary2013Link;
        }

        if (executiveSummaryTitle !== "" && executiveSummaryLink !== "") {
            $($this.ExecutiveSummaryNotAvailableHolderSelector).hide();
            $(".executiveSummaryHolder .executiveSummaryTitle").show().text(executiveSummaryTitle);
            $($this.PdfContainerSelector).show().prop("src", UNGM.siteRoot + "Scripts/PDF/web/viewer.html?file=" + executiveSummaryLink);
        } else {
            $(".executiveSummaryHolder .executiveSummaryTitle").hide();
            $($this.PdfContainerSelector).hide();
            $($this.ExecutiveSummaryNotAvailableHolderSelector).show().text($this.ExecutiveSummaryNotAvailableInfo.replace("[year]", selectedYear));
        }
    }

    namespace.Map.prototype.DownloadReport = function () {
        var $this = this;
        var selectedReportOption = $this.DdlReportsForDownloadSelector.find(":selected");

        if (selectedReportOption.val() === "") {
            // The first empty option has been selected
            return;
        }

        // Log google analytics
        var gaInfo = selectedReportOption.data("gainfo");
        try {
            // ga is not defined in dev environment
            UNGM.gaEvent('StatReports', 'Download', gaInfo);
        }
        catch (ex) {
            console.log("Error logging the Google analytics download for: " + gaInfo);
        }

        // Download the file
        var pdfLink = UNGM.siteRoot + selectedReportOption.val();
        window.open(pdfLink);
    }

    //
    // SearchFilter
    //

    function SearchFilter(params) {
        this.Year = new Year(params.Year);
        this.Area = new Area(params.Area);
    }

    SearchFilter.prototype.GetData = function () {
        var data = {
            Year: this.Year.GetData(),
            Area: this.Area.GetData()
        };

        return data;
    }

    SearchFilter.prototype.OnChange = function (callback) {
        this.Year.OnChange(callback);
        this.Area.OnChange(callback);
    }

    //
    // Year
    //

    function Year(params) {
        this.Element = $(params.Selector);
        this.Default = this.Element.val();
    }

    Year.prototype.GetData = function () {
        return this.Element.val();
    }

    Year.prototype.OnChange = function (callback) {
        this.Element.change(callback);
    }

    //
    // Area
    //

    function Area(params) {
        this.Element = $(params.Selector);
    }

    Area.prototype.GetData = function () {
        return this.Element.filter(":checked").val();
    }

    Area.prototype.OnChange = function (callback) {
        this.Element.click(callback);
    }

}(window.UNGM.OnlineASR = window.UNGM.OnlineASR || {}));
;
window.UNGM.OnlineASR = window.UNGM.OnlineASR || {};

(function (namespace, undefined) {

    ////////////////////////////////////////////////////////////////////////////////
    //
    // YearSelector
    //

    namespace.YearSelector = function () {
        this.element = null;
        this.callbacks = [];
        this.url = "";
    }

    namespace.YearSelector.GetInstance = function () {
        return this.instance = this.instance || new namespace.YearSelector();
    }

    namespace.YearSelector.prototype.SetElement = function (element) {
        var $this = this;
        if (this.element) { this.element.unbind("change"); }
        this.element = element;
        this.element.change(function () { $this.Change(); });
    }

    namespace.YearSelector.prototype.GetYear = function () {
        return this.element.val();
    }

    namespace.YearSelector.prototype.AttachCallbackOnChange = function (callback) {
        this.callbacks.push(callback);
    }

    namespace.YearSelector.prototype.Change = function () {
        var $this = this;
        var year = this.element.val();
        $.each(this.callbacks, function (index, callback) { callback(year); });
    }

    ////////////////////////////////////////////////////////////////////////////////
    //
    // TabHeader
    //

    namespace.TabHeader = function (element) {
        namespace.TabHeader.instances = namespace.TabHeader.instances || [];
        var instances = $.grep(namespace.TabHeader.instances, function (instance) { return instance.element[0] === element[0] });
        if (instances.length !== 0) {
            return instances[0];
        } else {
            var instance = new TabHeader(element);
            namespace.TabHeader.instances.push(instance);
            return instance;
        }
    }

    function TabHeader(element) {
        this.element = element;
        this.callbacksOnActive = [];
        this.callbacksOnInactive = [];
        this.element.click(function (event) {
            $.each(namespace.TabHeader.instances, function (index, instance) {
                var isActive = instance.element[0] === event.currentTarget;
                if (isActive) {
                    instance.NotifyCallbackOnActive();
                } else {
                    instance.NotifyCallbackOnInactive();
                }
            });
        });
    }

    TabHeader.prototype.IsActive = function () {
        return this.element.hasClass("activeTab");
    }

    TabHeader.prototype.AttachCallbackOnActive = function (callback) {
        this.callbacksOnActive.push(callback);
        if (this.IsActive()) { callback(); }
    }

    TabHeader.prototype.AttachCallbackOnInactive = function (callback) {
        this.callbacksOnInactive.push(callback);
        if (!this.IsActive()) { callback(); }
    }

    TabHeader.prototype.NotifyCallbackOnActive = function () {
        $.each(this.callbacksOnActive, function (index, callback) { callback(); });
    }

    TabHeader.prototype.NotifyCallbackOnInactive = function () {
        $.each(this.callbacksOnInactive, function (index, callback) { callback(); });
    }

    ////////////////////////////////////////////////////////////////////////////////
    //
    // Search
    //

    namespace.Search = function (element) {
        this.element = element;
        this.legend = element.find(".legend");
        this.content = element.children().not(".legend");
        this.filters = new SearchFilterWrapper(element.find(".search-filters"));
        this.sorters = new SearchSorterWrapper(element.find(".search-sorters"));
        this.results = new SearchResultWrapper(element.find(".search-results"));
        this.paginationEnabled = false;
        this.pageCurrentIndex = -1;
        this.lastPageReached = false;
        this.isSearching = false;
        this.isSearchingTotal = false;
        this.isSearchingTotalUnspecified = false;
        this.requireSearchTotal = false;
        this.expanded = true;
        this.url = null;
        this.totalUrl = null;
        this.totalUnspecifiedUrl = null;

        var $this = this;
        this.delayedSearch = UNGM.ViewModel.DelayedFunction(function () { $this.SearchImpl() });
        this.filters.AttachCallbackOnChange(function () { $this.Refresh(); });
        this.sorters.AttachCallbackOnChange(function () { $this.Refresh(); });
    }

    namespace.Search.prototype.SetResourceUrl = function (url) {
        this.url = url;
    }

    namespace.Search.prototype.SetTotalResourceUrl = function (url) {
        this.totalUrl = url;
    }

    namespace.Search.prototype.SetTotalUnspecifiedResourceUrl = function (url) {
        this.totalUnspecifiedUrl = url;
    }

    namespace.Search.prototype.SetResource = function (resource) {
        var data = resource.hasOwnProperty("Data") ? resource.Data : resource;
        var total = resource.hasOwnProperty("Total") ? resource.Total : null;
        if (this.pageCurrentIndex === -1) {
            this.results.SetData(data);
        } else {
            this.results.AddData(data);
        }
        this.results.SetTotal(total);
        this.results.Render();
    }

    namespace.Search.prototype.SetTotalResource = function (resource) {
        this.results.SetTotalData(resource);
        this.results.Render();
    }

    namespace.Search.prototype.SetTotalUnspecifiedResource = function (resource) {
        this.results.SetTotalUnspecifiedData(resource);
        this.results.Render();
    }

    namespace.Search.prototype.SetDefaultSort = function (field, descending) {
        this.sorters.SetDefaultSort(field, descending);
    }

    namespace.Search.prototype.CreateHiddenSearchFilter = function (selector) {
        return this.filters.CreateHiddenSearchFilter(selector);
    }

    namespace.Search.prototype.CreateMultipleResourceSearchFilter = function (selector, params) {
        return this.filters.CreateMultipleResourceSearchFilter(selector, params);
    }

    namespace.Search.prototype.CreateUNSPSCSearchFilter = function (selector, params) {
        return this.filters.CreateUNSPSCSearchFilter(selector, params);
    }

    namespace.Search.prototype.ClearAllFilters = function (selector, params) {
        this.filters.ClearAllFilters(selector, params);
    }

    namespace.Search.prototype.EnablePagination = function () {
        this.paginationEnabled = true;
        this.CreateSearchWaypoint();
    }

    namespace.Search.prototype.DisablePagination = function () {
        this.paginationEnabled = false;
        this.DestroySearchWaypoint();
    }

    namespace.Search.prototype.EnableToggling = function () {
        var $this = this;
        this.legend.click(function () { $this.Toggle(); });
    }

    namespace.Search.prototype.Toggle = function () {
        var $this = this;
        this.expanded = !this.expanded;
        if ($this.expanded) {
            $this.legend.addClass("expanded");
        } else {
            $this.legend.removeClass("expanded");
        }
        this.content.slideToggle({
            complete: function () {
                if ($this.paginationEnabled) {
                    if ($this.expanded) {
                        $this.CreateSearchWaypoint();
                    } else {
                        $this.DestroySearchWaypoint();
                    }
                }
            }
        });
    }

    namespace.Search.prototype.Refresh = function () {
        this.pageCurrentIndex = -1;
        this.lastPageReached = false;
        this.requireSearchTotal = true;
        this.Search();
    }

    namespace.Search.prototype.Search = function () {
        this.delayedSearch.invoke();
    }

    namespace.Search.prototype.SearchImpl = function () {
        this.CallServerSearch();
        this.CallServerTotal();
        this.CallServerTotalUnspecified();
    }

    namespace.Search.prototype.CallServerSearch = function () {
        if (!this.isSearching) {
            this.isSearching = true;
            UNGM.Throbber.Push();
            var $this = this;
            $.ajax({
                url: this.url,
                type: "POST",
                data: JSON.stringify(this.GetSearchOptions()),
                contentType: "application/json"
            }).success(function (response) {
                if (typeof (response) !== "object") { response = JSON.parse(response); }
                $this.SetResource(response);
                $this.SetPdfUrl();
                $this.lastPageReached = $this.results.GetCount() === $this.results.GetTotal();
                if (!$this.lastPageReached) {
                    $this.pageCurrentIndex += 1;
                    $this.CreateSearchWaypoint();
                }
            }).always(function () {
                UNGM.Throbber.Pop();
                $this.isSearching = false;
            });
        }
    }

    namespace.Search.prototype.CallServerTotal = function () {
        if (!this.isSearchingTotal && this.requireSearchTotal && this.totalUrl !== null) {
            this.isSearchingTotal = true;
            UNGM.Throbber.Push();
            var $this = this;
            $.ajax({
                url: this.totalUrl,
                type: "POST",
                data: JSON.stringify(this.GetSearchOptions()),
                contentType: "application/json"
            }).success(function (response) {
                if (typeof (response) !== "object") { response = JSON.parse(response); }
                $this.SetTotalResource(response);
            }).always(function () {
                UNGM.Throbber.Pop();
                $this.isSearchingTotal = false;
                $this.requireSearchTotal = false;
            });
        }
    }

    namespace.Search.prototype.CallServerTotalUnspecified = function () {
        if (!this.isSearchingTotalUnspecified && this.totalUnspecifiedUrl !== null) {
            this.isSearchingTotalUnspecified = true;
            UNGM.Throbber.Push();
            var $this = this;
            $.ajax({
                url: this.totalUnspecifiedUrl,
                type: "POST",
                data: JSON.stringify(this.GetSearchOptions()),
                contentType: "application/json"
            }).success(function (response) {
                if (typeof (response) !== "object") { response = JSON.parse(response); }
                $this.SetTotalUnspecifiedResource(response);
            }).always(function () {
                UNGM.Throbber.Pop();
                $this.isSearchingTotalUnspecified = false;
            });
        }
    }

    namespace.Search.prototype.GetSearchOptions = function () {
        var options = {};
        $.extend(options, this.filters.GetFilterOptions());
        $.extend(options, this.sorters.GetSortOptions());
        $.extend(options, { PageIndex: this.pageCurrentIndex + 1 });
        return options;
    }

    namespace.Search.prototype.CreateSearchWaypoint = function () {
        if (this.paginationEnabled && this.expanded && !this.lastPageReached) {
            var $this = this;
            this.DestroySearchWaypoint();
            this.results.element.waypoint(function (direction) {
                if (direction === "down") {
                    $this.DestroySearchWaypoint();
                    $this.Search();
                }
            }, { offset: 'bottom-in-view' });
        }
    }

    namespace.Search.prototype.DestroySearchWaypoint = function () {
        this.results.element.waypoint("destroy");
    }

    namespace.Search.prototype.SetPdfUrl = function () {        
        this.element.find(".search-result-template").on("click", function () {
            if ($(this).attr("data-agency-name") !== undefined) {
                UNGM.OnlineASR.ProcurementReports.OpenAgencyPdf($(this).attr("data-agency-name"));
            }
            else if ($(this).attr("data-country-name") !== undefined) {
                UNGM.OnlineASR.ProcurementReports.OpenCountryPdf($(this).attr("data-country-name"));
            }
        });
    }

    ////////////////////////////////////////////////////////////////////////////////
    //
    // SearchSorterWrapper
    //

    function SearchSorterWrapper(element) {
        this.element = element;
        this.sorters = element.find(".sortable");
        this.sortField = "";
        this.sortDescending = null;
        this.callbacks = [];

        var $this = this;
        this.sorters.click(function (event) {
            var sorter = $(event.currentTarget);
            var sortField = sorter.data("sort-field");
            $this.UpdateSortField(sortField);
        });
    }

    SearchSorterWrapper.prototype.SetDefaultSort = function (field, descending) {
        this.sortField = field;
        this.sortDescending = descending;
        this.Render();
    }

    SearchSorterWrapper.prototype.UpdateSortField = function (sortField) {
        if (this.sortField !== sortField) {
            this.sortField = sortField;
            this.sortDescending = false;
        } else {
            this.sortDescending = !this.sortDescending;
        }
        this.Render();
        this.NotifyCallbackOnChange();
    }

    SearchSorterWrapper.prototype.Render = function () {
        this.sorters
            .removeClass("sortedAsc sortedDesc")
            .filter("[data-sort-field='" + this.sortField + "']")
            .addClass(this.sortDescending ? "sortedDesc" : "sortedAsc");
    }

    SearchSorterWrapper.prototype.GetSortOptions = function () {
        return { SortField: this.sortField, SortDescending: this.sortDescending };
    }

    SearchSorterWrapper.prototype.AttachCallbackOnChange = function (callback) {
        this.callbacks.push(callback);
    }

    SearchSorterWrapper.prototype.NotifyCallbackOnChange = function () {
        $.each(this.callbacks, function (index, callback) { callback(); });
    }

    ////////////////////////////////////////////////////////////////////////////////
    //
    // SearchFilterWrapper
    //

    function SearchFilterWrapper(element) {
        this.element = element;
        this.callbacks = [];

        var $this = this;
        this.element.find(".search-filter").change(function () { $this.NotifyCallbackOnChange(); });
    }

    SearchFilterWrapper.prototype.CreateHiddenSearchFilter = function (selector) {
        var $this = this;
        var hiddenSearchFilter = new HiddenSearchFilter(this.element.find(selector));
        hiddenSearchFilter.AttachCallbackOnChange(function () { $this.NotifyCallbackOnChange(); });
        return hiddenSearchFilter;
    }

    SearchFilterWrapper.prototype.CreateMultipleResourceSearchFilter = function (selector, params) {
        var $this = this;
        var multipleResourcePicker = new MultipleResourceSearchFilter(this.element.find(selector));
        multipleResourcePicker.SetResourceParams(params);
        multipleResourcePicker.AttachCallbackOnChange(function () { $this.NotifyCallbackOnChange(); });
        return multipleResourcePicker;
    }

    SearchFilterWrapper.prototype.CreateUNSPSCSearchFilter = function (selector, params) {
        var $this = this;
        var unspscSearchFilter = new UNSPSCSearchFilter(this.element.find(selector), params);
        unspscSearchFilter.AttachCallbackOnChange(function () { $this.NotifyCallbackOnChange(); });
        return unspscSearchFilter;
    }

    SearchFilterWrapper.prototype.GetFilterOptions = function () {
        var $this = this;
        var options = {};
        $.each(this.element.find(".search-filter"), function (index, filter) {
            var element = $(filter);
            if (element.attr("type") === "checkbox" && !element.prop("checked")) { return; }
            var key = element.attr("name");
            var value = element.val();
            if (element.hasClass("multiple")) {
                options[key] = options[key] || [];
                options[key].push(value);
            } else {
                options[key] = value;
            }
        });
        return options;
    }

    SearchFilterWrapper.prototype.ClearAllFilters = function (selector, params) {
        var $this = this;
        this.element.find(selector).click(function () {
            params.ASRCountriesSearchFilter.ClearAllFilters();
            params.ASRAgenciesSearchFilter.ClearAllFilters();
            params.ASRUNSPSCSearchFilter.ClearAllFilters();
            $this.NotifyCallbackOnChange();
        });
    }

    SearchFilterWrapper.prototype.AttachCallbackOnChange = function (callback) {
        this.callbacks.push(callback);
    }

    SearchFilterWrapper.prototype.NotifyCallbackOnChange = function () {
        $.each(this.callbacks, function (index, callback) { callback(); });
    }

    ////////////////////////////////////////////////////////////////////////////////
    //
    // SearchResultWrapper
    //

    function SearchResultWrapper(element) {
        this.element = element;
        this.searchResultsEmpty = element.find(".search-results-empty");
        this.searchResultsFound = element.find(".search-results-found");
        this.searchResultsCount = element.find(".search-results-count");
        this.searchResultsCountTemplate = this.searchResultsCount.html();
        var totalElement = element.find(".search-result-total");
        if (totalElement.length !== 0) {
            this.bondTotal = UNGM.ViewModel.Binder()
                .filter("in_USD", function (value) {
                    var number = parseFloat(value);
                    if (isNaN(number)) { return ""; }
                    if (number < 0) { return "-$" + Math.abs(number).toLocaleString("en", { minimumFractionDigits: 2, maximumFractionDigits: 2, useGrouping: true }); }
                    return "$" + number.toLocaleString("en", { minimumFractionDigits: 2, maximumFractionDigits: 2, useGrouping: true });
                })
                .filter("in_percentage", function (value) {
                    var number = parseFloat(value);
                    if (isNaN(number)) { return ""; }
                    var string = number.toLocaleString("en", { minimumFractionDigits: 2, maximumFractionDigits: 2, useGrouping: true }) + "%";
                    return (string == "0.00%") ? "< 0.01%" : string;
                }).bind(totalElement);
        }
        var unspecifiedTotalElement = element.find(".search-result-total-unspecified");
        if (unspecifiedTotalElement.length !== 0) {
            this.bondUnspecifiedTotal = UNGM.ViewModel.Binder()
                .filter("in_USD", function (value) {
                    var number = parseFloat(value);
                    if (isNaN(number)) { return ""; }
                    if (number < 0) { return "-$" + Math.abs(number).toLocaleString("en", { minimumFractionDigits: 2, maximumFractionDigits: 2, useGrouping: true }); }
                    return "$" + number.toLocaleString("en", { minimumFractionDigits: 2, maximumFractionDigits: 2, useGrouping: true });
                })
                .filter("in_percentage", function (value) {
                    var number = parseFloat(value);
                    if (isNaN(number)) { return ""; }
                    var string = number.toLocaleString("en", { minimumFractionDigits: 2, maximumFractionDigits: 2, useGrouping: true }) + "%";
                    return string;
                }).bind(unspecifiedTotalElement);
        }
        UNGM.ViewModel.Filter("in_USD", function (value) {
            var number = parseFloat(value);
            if (isNaN(number)) { return ""; }
            if (number < 0) { return "-$" + Math.abs(number).toLocaleString("en", { minimumFractionDigits: 2, maximumFractionDigits: 2, useGrouping: true }); }
            return "$" + number.toLocaleString("en", { minimumFractionDigits: 2, maximumFractionDigits: 2, useGrouping: true });
        });
        UNGM.ViewModel.Filter("in_percentage", function (value) {
            var number = parseFloat(value);
            if (isNaN(number)) { return ""; }
            var string = number.toLocaleString("en", { minimumFractionDigits: 2, maximumFractionDigits: 2, useGrouping: true }) + "%";
            return (string == "0.00%") ? "< 0.01%" : string;
        });
        this.repeat = UNGM.ViewModel.Repeat(element.find(".search-result-template"));
        this.repeat.setIndex("Index", 1);
        this.total = 0;
    }

    SearchResultWrapper.prototype.SetData = function (data) {
        this.repeat.data(data);
    }

    SearchResultWrapper.prototype.AddData = function (data) {
        this.repeat.data(this.repeat.data().concat(data))
    }

    SearchResultWrapper.prototype.SetTotal = function (total) {
        this.total = total;
    }

    SearchResultWrapper.prototype.SetTotalData = function (total) {
        if (this.bondTotal) {
            this.bondTotal.data(total);
        }
    }

    SearchResultWrapper.prototype.SetTotalUnspecifiedData = function (totalUnspecified) {
        if (this.bondUnspecifiedTotal) {
            this.bondUnspecifiedTotal.data(totalUnspecified);
        }
    }

    SearchResultWrapper.prototype.GetTotal = function (total) {
        return this.total;
    }

    SearchResultWrapper.prototype.Render = function (result) {
        var count = this.GetCount();
        var total = this.GetTotal();
        if (count !== 0) {
            if (this.searchResultsCountTemplate) {
                var message = this.searchResultsCountTemplate
                    .replace(/{{\s*count\s*}}/gi, count)
                    .replace(/{{\s*total\s*}}/gi, this.total);
                this.searchResultsCount.html(message);
                this.searchResultsCount.show();
            }
            this.searchResultsEmpty.hide();
            this.searchResultsFound.show();
        } else {
            this.searchResultsEmpty.show();
            this.searchResultsCount.hide();
            this.searchResultsFound.hide();
        }
    }

    SearchResultWrapper.prototype.GetCount = function () {
        return this.repeat.data().length;
    }

    ////////////////////////////////////////////////////////////////////////////////
    //
    // HiddenSearchFilter
    //

    function HiddenSearchFilter(element) {
        var $this = this;
        this.element = element;
        this.callbacks = [];
    }

    HiddenSearchFilter.prototype.Change = function (value) {
        this.element.val(value);
        this.NotifyCallbackOnChange();
    }

    HiddenSearchFilter.prototype.AttachCallbackOnChange = function (callback) {
        this.callbacks.push(callback);
    }

    HiddenSearchFilter.prototype.NotifyCallbackOnChange = function () {
        $.each(this.callbacks, function (index, callback) { callback(); });
    }

    ////////////////////////////////////////////////////////////////////////////////
    //
    // MultipleResourceSearchFilter
    //

    function MultipleResourceSearchFilter(element) {
        var $this = this;
        this.element = element;
        this.element.removeClass("search-filter");
        this.usingIE = (/msie/.test(navigator.userAgent.toLowerCase()) && parseInt(navigator.appVersion, 10) <= 6);
        if (this.usingIE) {
            this.element.on("change", function (event) {
                $this.Select($this.element.find("option:selected").text());
                $this.element.val("");
            })
        } else {
            this.autocompleteElement = this.element.siblings(".ui-autocomplete-input");
            if (this.autocompleteElement.length === 0) {
                this.element.selectToAutocomplete();
                this.autocompleteElement = this.element.siblings(".ui-autocomplete-input");
            }
            this.autocompleteElement.on("autocompleteselect", function (event, ui) { $this.Select(ui.item.label); });
            this.autocompleteElement.on("blur", function () { $this.autocompleteElement.val(""); });
        }
        this.selectedLabels = [];
        this.callbacks = [];
        this.url = null;
        this.valueField = null;
        this.textField = null;
    }

    MultipleResourceSearchFilter.prototype.SetResourceParams = function (params) {
        if (params) {
            this.url = params.Url;
            this.valueField = params.ValueField;
            this.textField = params.TextField;
        }
    }

    MultipleResourceSearchFilter.prototype.DisplayAllOptionsOnFocus = function () {
        var $this = this;
        if (!this.usingIE) {
            this.autocompleteElement.on("focus", function () {
                $this.autocompleteElement.autocomplete("search", " ");
            })
        }
    }

    MultipleResourceSearchFilter.prototype.Refresh = function (params) {
        if (this.url) {
            UNGM.Throbber.Push();
            var $this = this;
            this.ClearAllFilters();
            $.ajax({
                url: this.url,
                type: "POST",
                data: JSON.stringify(params),
                contentType: "application/json"
            }).success(function (response) {
                if (typeof (response) !== "object") { response = JSON.parse(response); }
                $this.UpdateOptions(response);
                $this.UpdateAutocompleteElementSource(response);
            }).always(function () { UNGM.Throbber.Pop(); });
        }
    }

    MultipleResourceSearchFilter.prototype.ClearAllFilters = function () {
        this.selectedLabels = [];
        this.RedrawSelectedLabels();
    }

    MultipleResourceSearchFilter.prototype.UpdateOptions = function (response) {
        var $this = this;
        this.element.empty();
        this.element.append($("<option></option>"));
        $.each(response, function (index, item) {
            var option = $("<option value='" + item[$this.valueField] + "'>" + item[$this.textField] + "</option>");
            $this.element.append(option);
        });
    }

    MultipleResourceSearchFilter.prototype.GetValue = function (label) {
        var option = this.element.find("option").filter(function () { return $(this).html() == label; });
        return option.val();
    }

    MultipleResourceSearchFilter.prototype.UpdateAutocompleteElementSource = function (response) {
        if (!this.usingIE) {
            var $this = this;
            var source = $.map(response, function (item) { return item[$this.textField]; });
            this.autocompleteElement.autocomplete("option", "source", source);
        }
    }

    MultipleResourceSearchFilter.prototype.Select = function (label) {
        if ($.trim(label).length !== 0 && $.inArray(label, this.selectedLabels) === -1) {
            this.selectedLabels.push(label);
            this.selectedLabels.sort();
            this.selectedLabels.reverse();
            this.RedrawSelectedLabels();
            this.NotifyCallbackOnChange();
        }
    }

    MultipleResourceSearchFilter.prototype.Remove = function (label) {
        var index = $.inArray(label, this.selectedLabels);
        this.selectedLabels.splice(index, 1);
        this.RedrawSelectedLabels();
        this.NotifyCallbackOnChange();
    }

    MultipleResourceSearchFilter.prototype.RedrawSelectedLabels = function () {
        var $this = this;
        var name = this.element.attr("name");
        this.element.siblings('.filterDiv').remove();
        var textbox = this.element.siblings('input:text');
        $.each(this.selectedLabels, function (index, label) {
            var value = $this.GetValue(label);
            var element = $("<div class='filterDiv'></div>");
            var valueElement = $("<input type='hidden' class='search-filter multiple' name='" + name + "' value='" + value + "' />");
            var labelElement = $("<span>" + label + "</span>");
            var removeElement = $("<a href='javascript:void(0)' class='lnkRemoveUnspscFilter'>(remove)</a>");
            element.append(valueElement);
            element.append(labelElement);
            element.append(removeElement);
            removeElement.click(function () { $this.Remove(label); });
            if ($this.usingIE) {
                element.insertAfter($this.element);
            } else {
                element.insertAfter(textbox);
            }
        });
    }

    MultipleResourceSearchFilter.prototype.AttachCallbackOnChange = function (callback) {
        this.callbacks.push(callback);
    }

    MultipleResourceSearchFilter.prototype.NotifyCallbackOnChange = function () {
        $.each(this.callbacks, function (index, callback) { callback(); });
    }

    ////////////////////////////////////////////////////////////////////////////////
    //
    // UNSPSCSearchFilter
    //

    function UNSPSCSearchFilter(element, params) {
        var $this = this;
        this.callbacks = [];
        this.SelectedUNSPSCs = [];
        this.LinkSelector = element;
        this.UNSPSCSelector = null;
        this.UNSPSCHolder = params.UNSPSCSelectorHolder;
        this.Url = params.Url;
        this.LinkSelector.click(function () { $this.ShowUNSPSC() });
    }

    UNSPSCSearchFilter.prototype.ShowUNSPSC = function () {
        var $this = this;
        UNGM.UNSPSC.saveCallback = function () { $this.UNSPSCSaveCallback(); };

        //refresh the picker selection
        var picker = this.UNSPSCSelector.find(".unspsc");
        UNGM.UNSPSC.bindSelectedCodes(picker);

        var winHeight = $(window).height();

        this.UNSPSCSelector.dialog({
            modal: true,
            title: 'UNSPSC',
            width: $(window).width() < 480 ? '100%' : '66%',
            height: $(window).width() < 480 ? $(window).height() : winHeight - (winHeight * 0.2),
            hide: { effect: 'fade', duration: 100 },
            show: { effect: 'fade', duration: 100 }
        });
    }

    UNSPSCSearchFilter.prototype.UNSPSCSaveCallback = function () {
        //Add selected UNSPSC to place holder
        var $this = this;
        this.LinkSelector.siblings('.filterDiv').remove();
        var unspscId = null;
        var Code = null;
        var UNSPSCName = null;
        this.SelectedUNSPSCs = [];

        for (var i = 0; i < UNGM.UNSPSC.selectedCodes.length; i++) {
            unspscId = parseInt(UNGM.UNSPSC.selectedCodes[i].Id, 10);
            Code = UNGM.UNSPSC.selectedCodes[i].Code;
            UNSPSCName = UNGM.UNSPSC.selectedCodes[i].Name;
            this.SelectedUNSPSCs.push(unspscId);

            // redraw elements
            var element = $("<div class='filterDiv'></div>");
            var valueElement = $("<input type='hidden' class='search-filter multiple' name='ASRUNSPSCs' value='" + unspscId + "' />");
            var labelElement = $("<span>" + Code + " - " + UNSPSCName + "</span>");
            var removeElement = $("<a href='javascript:void(0)' class='lnkRemoveUnspscFilter'>(remove)</a>");
            element.append(valueElement);
            element.append(labelElement);
            element.append(removeElement);
            removeElement.click(function (event) { $this.RemoveUNSPSC(event) });
            element.insertAfter(this.LinkSelector);
        }

        if (this.UNSPSCSelector.is(':data(dialog)') || this.UNSPSCSelector.hasClass('ui-dialog-content')) {
            this.UNSPSCSelector.dialog("close");
        }
        this.NotifyCallbackOnChange();
    }

    UNSPSCSearchFilter.prototype.RemoveUNSPSC = function (event) {
        var removeElement = $(event.currentTarget);
        var removedArray = this.SelectedUNSPSCs;

        var removedId = removeElement.siblings("input").val();
        this.SelectedUNSPSCs = $.grep(removedArray, function (value) { return value != removedId; });

        UNGM.UNSPSC.removeCode(removedId);

        // Remove selected UNSPSCs from place holder
        removeElement.siblings().remove();
        removeElement.remove();
        this.NotifyCallbackOnChange();
    }

    UNSPSCSearchFilter.prototype.RefreshUNSPSCSearchFilter = function (params) {
        UNGM.Throbber.Push();
        var $this = this;

        this.ClearAllFilters();

        $.ajax({
            url: $this.Url,
            type: "POST",
            data: JSON.stringify(params),
            contentType: "application/json"
        }).success(function (response) {
            $this.UNSPSCHolder.html(response);
            $this.UNSPSCSelector = $this.UNSPSCHolder.children("div");
        }).always(function () { UNGM.Throbber.Pop(); });
    }

    UNSPSCSearchFilter.prototype.ClearAllFilters = function () {
        this.LinkSelector.siblings('.filterDiv').remove();
        $.each(this.SelectedUNSPSCs, function (index, value) {
            UNGM.UNSPSC.removeCode(value);
        });
        this.SelectedUNSPSCs = [];
    }

    UNSPSCSearchFilter.prototype.AttachCallbackOnChange = function (callback) {
        this.callbacks.push(callback);
    }

    UNSPSCSearchFilter.prototype.NotifyCallbackOnChange = function () {
        $.each(this.callbacks, function (index, callback) { callback(); });
    }

    ////////////////////////////////////////////////////////////////////////////////
    //
    // OpenCountryPdf, OpenAgencyPdf 
    //

    namespace.OpenCountryPdf = function (country) {
        var year = UNGM.OnlineASR.ProcurementReports.YearSelector.GetInstance().GetYear();
        this.OpenCountryPdfByYear(country, year);
    }

    namespace.OpenCountryPdfByYear = function (country, year) {
        var pdfUrl = this.GetCountryPdfUrl(country, year);
        PdfDialog.GetInstance().Open(country, pdfUrl);
    }

    namespace.GetCountryPdfUrl = function (country, year) {
        return this.GetCountryPdfPath(year) + encodeURIComponent(this.GetCountryPdfName(country, year)).replace(/'/g, escape);
    }

    namespace.GetCountryPdfPath = function (year) {
        return UNGM.siteRoot + "Areas/Public/Downloads/ASR/" + year + "/Country/";
    }

    namespace.GetCountryPdfName = function (country, year) {
        return (country + year + ".pdf").replace(/ /g, "");
    }

    namespace.OpenAgencyPdf = function (agency) {
        var year = UNGM.OnlineASR.ProcurementReports.YearSelector.GetInstance().GetYear();        
        this.OpenAgencyPdfByYear(agency, year);
    }

    namespace.OpenAgencyPdfByYear = function (agency, year) {
        var pdfUrl = this.GetAgencyPdfUrl(agency, year);
        PdfDialog.GetInstance().Open(agency, pdfUrl);
    }

    namespace.GetAgencyPdfUrl = function (agency, year) {
        return this.GetAgencyPdfPath(year) + encodeURIComponent(this.GetAgencyPdfName(agency, year)).replace(/'/g, escape);
    }

    namespace.GetAgencyPdfPath = function (year) {
        return UNGM.siteRoot + "Areas/Public/Downloads/ASR/" + year + "/Agency/";
    }

    namespace.GetAgencyPdfName = function (agency, year) {
        return (agency + "_" + year + ".pdf");
    }

    ////////////////////////////////////////////////////////////////////////////////
    //
    // PdfDialog
    //

    function PdfDialog() {
        this.element = $("<div></div>");
    }

    PdfDialog.GetInstance = function () {
        return this.instance = this.instance || new PdfDialog();
    }

    PdfDialog.prototype.Open = function (title, pdfUrl) {
        UNGM.Throbber.Push();
        this.element.empty();
        var $this = this;
        $.ajax({
            url: pdfUrl,
            type: 'HEAD',   // Gets only size of the header, not the actual file
            global: false,  // Disable global events, as UNGM.ajaxErrorHandler 
            error: function () {
                dialogContent = "<div class='info'>The document is not yet avaiable.</div>";
            },
            success: function () {
                var pdfViewer = UNGM.siteRoot + "Scripts/PDF/web/viewer.html?file=";
                dialogContent = "<iframe src='" + pdfViewer + pdfUrl + "' style='width: " + 0.6 * $(window).width() + "px; height: " + 0.7 * $(window).height() + "px;'></iframe>";
            },
            complete: function () {
                $this.element.html(dialogContent);
                $this.element.dialog({
                    modal: true,
                    title: title,
                    width: "auto",
                    height: "auto",
                    hide: { effect: 'fade', duration: 100 },
                    show: { effect: 'fade', duration: 100 }
                });
                UNGM.Throbber.Pop();
            }
        });
    }

})(window.UNGM.OnlineASR.ProcurementReports = window.UNGM.OnlineASR.ProcurementReports || {});
/*! gridster.js - v0.5.6 - 2014-09-25
* http://gridster.net/
* Copyright (c) 2014 ducksboard; Licensed MIT */

;(function(root, factory) {

    if (typeof define === 'function' && define.amd) {
        define('gridster-coords', ['jquery'], factory);
    } else {
       root.GridsterCoords = factory(root.$ || root.jQuery);
    }

}(this, function($) {
    /**
    * Creates objects with coordinates (x1, y1, x2, y2, cx, cy, width, height)
    * to simulate DOM elements on the screen.
    * Coords is used by Gridster to create a faux grid with any DOM element can
    * collide.
    *
    * @class Coords
    * @param {HTMLElement|Object} obj The jQuery HTMLElement or a object with: left,
    * top, width and height properties.
    * @return {Object} Coords instance.
    * @constructor
    */
    function Coords(obj) {
        if (obj[0] && $.isPlainObject(obj[0])) {
            this.data = obj[0];
        }else {
            this.el = obj;
        }

        this.isCoords = true;
        this.coords = {};
        this.init();
        return this;
    }


    var fn = Coords.prototype;


    fn.init = function(){
        this.set();
        this.original_coords = this.get();
    };


    fn.set = function(update, not_update_offsets) {
        var el = this.el;

        if (el && !update) {
            this.data = el.offset();
            this.data.width = el.width();
            this.data.height = el.height();
        }

        if (el && update && !not_update_offsets) {
            var offset = el.offset();
            this.data.top = offset.top;
            this.data.left = offset.left;
        }

        var d = this.data;

        typeof d.left === 'undefined' && (d.left = d.x1);
        typeof d.top === 'undefined' && (d.top = d.y1);

        this.coords.x1 = d.left;
        this.coords.y1 = d.top;
        this.coords.x2 = d.left + d.width;
        this.coords.y2 = d.top + d.height;
        this.coords.cx = d.left + (d.width / 2);
        this.coords.cy = d.top + (d.height / 2);
        this.coords.width  = d.width;
        this.coords.height = d.height;
        this.coords.el  = el || false ;

        return this;
    };


    fn.update = function(data){
        if (!data && !this.el) {
            return this;
        }

        if (data) {
            var new_data = $.extend({}, this.data, data);
            this.data = new_data;
            return this.set(true, true);
        }

        this.set(true);
        return this;
    };


    fn.get = function(){
        return this.coords;
    };

    fn.destroy = function() {
        this.el.removeData('coords');
        delete this.el;
    };

    //jQuery adapter
    $.fn.coords = function() {
        if (this.data('coords') ) {
            return this.data('coords');
        }

        var ins = new Coords(this, arguments[0]);
        this.data('coords', ins);
        return ins;
    };

    return Coords;

}));

;(function(root, factory) {

    if (typeof define === 'function' && define.amd) {
        define('gridster-collision', ['jquery', 'gridster-coords'], factory);
    } else {
        root.GridsterCollision = factory(root.$ || root.jQuery,
            root.GridsterCoords);
    }

}(this, function($, Coords) {

    var defaults = {
        colliders_context: document.body,
        overlapping_region: 'C'
        // ,on_overlap: function(collider_data){},
        // on_overlap_start : function(collider_data){},
        // on_overlap_stop : function(collider_data){}
    };


    /**
    * Detects collisions between a DOM element against other DOM elements or
    * Coords objects.
    *
    * @class Collision
    * @uses Coords
    * @param {HTMLElement} el The jQuery wrapped HTMLElement.
    * @param {HTMLElement|Array} colliders Can be a jQuery collection
    *  of HTMLElements or an Array of Coords instances.
    * @param {Object} [options] An Object with all options you want to
    *        overwrite:
    *   @param {String} [options.overlapping_region] Determines when collision
    *    is valid, depending on the overlapped area. Values can be: 'N', 'S',
    *    'W', 'E', 'C' or 'all'. Default is 'C'.
    *   @param {Function} [options.on_overlap_start] Executes a function the first
    *    time each `collider ` is overlapped.
    *   @param {Function} [options.on_overlap_stop] Executes a function when a
    *    `collider` is no longer collided.
    *   @param {Function} [options.on_overlap] Executes a function when the
    * mouse is moved during the collision.
    * @return {Object} Collision instance.
    * @constructor
    */
    function Collision(el, colliders, options) {
        this.options = $.extend(defaults, options);
        this.$element = el;
        this.last_colliders = [];
        this.last_colliders_coords = [];
        this.set_colliders(colliders);

        this.init();
    }

    Collision.defaults = defaults;

    var fn = Collision.prototype;


    fn.init = function() {
        this.find_collisions();
    };


    fn.overlaps = function(a, b) {
        var x = false;
        var y = false;

        if ((b.x1 >= a.x1 && b.x1 <= a.x2) ||
            (b.x2 >= a.x1 && b.x2 <= a.x2) ||
            (a.x1 >= b.x1 && a.x2 <= b.x2)
        ) { x = true; }

        if ((b.y1 >= a.y1 && b.y1 <= a.y2) ||
            (b.y2 >= a.y1 && b.y2 <= a.y2) ||
            (a.y1 >= b.y1 && a.y2 <= b.y2)
        ) { y = true; }

        return (x && y);
    };


    fn.detect_overlapping_region = function(a, b){
        var regionX = '';
        var regionY = '';

        if (a.y1 > b.cy && a.y1 < b.y2) { regionX = 'N'; }
        if (a.y2 > b.y1 && a.y2 < b.cy) { regionX = 'S'; }
        if (a.x1 > b.cx && a.x1 < b.x2) { regionY = 'W'; }
        if (a.x2 > b.x1 && a.x2 < b.cx) { regionY = 'E'; }

        return (regionX + regionY) || 'C';
    };


    fn.calculate_overlapped_area_coords = function(a, b){
        var x1 = Math.max(a.x1, b.x1);
        var y1 = Math.max(a.y1, b.y1);
        var x2 = Math.min(a.x2, b.x2);
        var y2 = Math.min(a.y2, b.y2);

        return $({
            left: x1,
            top: y1,
             width : (x2 - x1),
            height: (y2 - y1)
          }).coords().get();
    };


    fn.calculate_overlapped_area = function(coords){
        return (coords.width * coords.height);
    };


    fn.manage_colliders_start_stop = function(new_colliders_coords, start_callback, stop_callback){
        var last = this.last_colliders_coords;

        for (var i = 0, il = last.length; i < il; i++) {
            if ($.inArray(last[i], new_colliders_coords) === -1) {
                start_callback.call(this, last[i]);
            }
        }

        for (var j = 0, jl = new_colliders_coords.length; j < jl; j++) {
            if ($.inArray(new_colliders_coords[j], last) === -1) {
                stop_callback.call(this, new_colliders_coords[j]);
            }

        }
    };


    fn.find_collisions = function(player_data_coords){
        var self = this;
        var overlapping_region = this.options.overlapping_region;
        var colliders_coords = [];
        var colliders_data = [];
        var $colliders = (this.colliders || this.$colliders);
        var count = $colliders.length;
        var player_coords = self.$element.coords()
                             .update(player_data_coords || false).get();

        while(count--){
          var $collider = self.$colliders ?
                           $($colliders[count]) : $colliders[count];
          var $collider_coords_ins = ($collider.isCoords) ?
                  $collider : $collider.coords();
          var collider_coords = $collider_coords_ins.get();
          var overlaps = self.overlaps(player_coords, collider_coords);

          if (!overlaps) {
            continue;
          }

          var region = self.detect_overlapping_region(
              player_coords, collider_coords);

            //todo: make this an option
            if (region === overlapping_region || overlapping_region === 'all') {

                var area_coords = self.calculate_overlapped_area_coords(
                    player_coords, collider_coords);
                var area = self.calculate_overlapped_area(area_coords);
                var collider_data = {
                    area: area,
                    area_coords : area_coords,
                    region: region,
                    coords: collider_coords,
                    player_coords: player_coords,
                    el: $collider
                };

                if (self.options.on_overlap) {
                    self.options.on_overlap.call(this, collider_data);
                }
                colliders_coords.push($collider_coords_ins);
                colliders_data.push(collider_data);
            }
        }

        if (self.options.on_overlap_stop || self.options.on_overlap_start) {
            this.manage_colliders_start_stop(colliders_coords,
                self.options.on_overlap_start, self.options.on_overlap_stop);
        }

        this.last_colliders_coords = colliders_coords;

        return colliders_data;
    };


    fn.get_closest_colliders = function(player_data_coords){
        var colliders = this.find_collisions(player_data_coords);

        colliders.sort(function(a, b) {
            /* if colliders are being overlapped by the "C" (center) region,
             * we have to set a lower index in the array to which they are placed
             * above in the grid. */
            if (a.region === 'C' && b.region === 'C') {
                if (a.coords.y1 < b.coords.y1 || a.coords.x1 < b.coords.x1) {
                    return - 1;
                }else{
                    return 1;
                }
            }

            if (a.area < b.area) {
                return 1;
            }

            return 1;
        });
        return colliders;
    };


    fn.set_colliders = function(colliders) {
        if (typeof colliders === 'string' || colliders instanceof $) {
            this.$colliders = $(colliders,
                 this.options.colliders_context).not(this.$element);
        }else{
            this.colliders = $(colliders);
        }
    };


    //jQuery adapter
    $.fn.collision = function(collider, options) {
          return new Collision( this, collider, options );
    };

    return Collision;

}));

;(function(window, undefined) {

    /* Delay, debounce and throttle functions taken from underscore.js
     *
     * Copyright (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and
     * Investigative Reporters & Editors
     *
     * Permission is hereby granted, free of charge, to any person
     * obtaining a copy of this software and associated documentation
     * files (the "Software"), to deal in the Software without
     * restriction, including without limitation the rights to use,
     * copy, modify, merge, publish, distribute, sublicense, and/or sell
     * copies of the Software, and to permit persons to whom the
     * Software is furnished to do so, subject to the following
     * conditions:
     *
     * The above copyright notice and this permission notice shall be
     * included in all copies or substantial portions of the Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
     * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
     * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     * OTHER DEALINGS IN THE SOFTWARE.
     */

    window.delay = function(func, wait) {
        var args = Array.prototype.slice.call(arguments, 2);
        return setTimeout(function(){ return func.apply(null, args); }, wait);
    };

    window.debounce = function(func, wait, immediate) {
        var timeout;
        return function() {
          var context = this, args = arguments;
          var later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
          };
          if (immediate && !timeout) func.apply(context, args);
          clearTimeout(timeout);
          timeout = setTimeout(later, wait);
        };
    };

    window.throttle = function(func, wait) {
        var context, args, timeout, throttling, more, result;
        var whenDone = debounce(
            function(){ more = throttling = false; }, wait);
        return function() {
          context = this; args = arguments;
          var later = function() {
            timeout = null;
            if (more) func.apply(context, args);
            whenDone();
          };
          if (!timeout) timeout = setTimeout(later, wait);
          if (throttling) {
            more = true;
          } else {
            result = func.apply(context, args);
          }
          whenDone();
          throttling = true;
          return result;
        };
    };

})(window);

;(function(root, factory) {

    if (typeof define === 'function' && define.amd) {
        define('gridster-draggable', ['jquery'], factory);
    } else {
        root.GridsterDraggable = factory(root.$ || root.jQuery);
    }

}(this, function($) {

    var defaults = {
        items: 'li',
        distance: 1,
        limit: true,
        offset_left: 0,
        autoscroll: true,
        ignore_dragging: ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON'], // or function
        handle: null,
        container_width: 0,  // 0 == auto
        move_element: true,
        helper: false,  // or 'clone'
        remove_helper: true
        // drag: function(e) {},
        // start : function(e, ui) {},
        // stop : function(e) {}
    };

    var $window = $(window);
    var dir_map = { x : 'left', y : 'top' };
    var isTouch = !!('ontouchstart' in window);

    var capitalize = function(str) {
        return str.charAt(0).toUpperCase() + str.slice(1);
    };

    var idCounter = 0;
    var uniqId = function() {
        return ++idCounter + '';
    }

    /**
    * Basic drag implementation for DOM elements inside a container.
    * Provide start/stop/drag callbacks.
    *
    * @class Draggable
    * @param {HTMLElement} el The HTMLelement that contains all the widgets
    *  to be dragged.
    * @param {Object} [options] An Object with all options you want to
    *        overwrite:
    *    @param {HTMLElement|String} [options.items] Define who will
    *     be the draggable items. Can be a CSS Selector String or a
    *     collection of HTMLElements.
    *    @param {Number} [options.distance] Distance in pixels after mousedown
    *     the mouse must move before dragging should start.
    *    @param {Boolean} [options.limit] Constrains dragging to the width of
    *     the container
    *    @param {Object|Function} [options.ignore_dragging] Array of node names
    *      that sould not trigger dragging, by default is `['INPUT', 'TEXTAREA',
    *      'SELECT', 'BUTTON']`. If a function is used return true to ignore dragging.
    *    @param {offset_left} [options.offset_left] Offset added to the item
    *     that is being dragged.
    *    @param {Number} [options.drag] Executes a callback when the mouse is
    *     moved during the dragging.
    *    @param {Number} [options.start] Executes a callback when the drag
    *     starts.
    *    @param {Number} [options.stop] Executes a callback when the drag stops.
    * @return {Object} Returns `el`.
    * @constructor
    */
    function Draggable(el, options) {
      this.options = $.extend({}, defaults, options);
      this.$document = $(document);
      this.$container = $(el);
      this.$dragitems = $(this.options.items, this.$container);
      this.is_dragging = false;
      this.player_min_left = 0 + this.options.offset_left;
      this.id = uniqId();
      this.ns = '.gridster-draggable-' + this.id;
      this.init();
    }

    Draggable.defaults = defaults;

    var fn = Draggable.prototype;

    fn.init = function() {
        var pos = this.$container.css('position');
        this.calculate_dimensions();
        this.$container.css('position', pos === 'static' ? 'relative' : pos);
        this.disabled = false;
        this.events();

        $(window).bind(this.nsEvent('resize'),
            throttle($.proxy(this.calculate_dimensions, this), 200));
    };

    fn.nsEvent = function(ev) {
        return (ev || '') + this.ns;
    };

    fn.events = function() {
        this.pointer_events = {
            start: this.nsEvent('touchstart') + ' ' + this.nsEvent('mousedown'),
            move: this.nsEvent('touchmove') + ' ' + this.nsEvent('mousemove'),
            end: this.nsEvent('touchend') + ' ' + this.nsEvent('mouseup'),
        };

        this.$container.on(this.nsEvent('selectstart'),
            $.proxy(this.on_select_start, this));

        this.$container.on(this.pointer_events.start, this.options.items,
            $.proxy(this.drag_handler, this));

        this.$document.on(this.pointer_events.end, $.proxy(function(e) {
            this.is_dragging = false;
            if (this.disabled) { return; }
            this.$document.off(this.pointer_events.move);
            if (this.drag_start) {
                this.on_dragstop(e);
            }
        }, this));
    };

    fn.get_actual_pos = function($el) {
        var pos = $el.position();
        return pos;
    };


    fn.get_mouse_pos = function(e) {
        if (e.originalEvent && e.originalEvent.touches) {
            var oe = e.originalEvent;
            e = oe.touches.length ? oe.touches[0] : oe.changedTouches[0];
        }

        return {
            left: e.clientX,
            top: e.clientY
        };
    };


    fn.get_offset = function(e) {
        e.preventDefault();
        var mouse_actual_pos = this.get_mouse_pos(e);
        var diff_x = Math.round(
            mouse_actual_pos.left - this.mouse_init_pos.left);
        var diff_y = Math.round(mouse_actual_pos.top - this.mouse_init_pos.top);

        var left = Math.round(this.el_init_offset.left +
            diff_x - this.baseX + $(window).scrollLeft() - this.win_offset_x);
        var top = Math.round(this.el_init_offset.top +
            diff_y - this.baseY + $(window).scrollTop() - this.win_offset_y);

        if (this.options.limit) {
            if (left > this.player_max_left) {
                left = this.player_max_left;
            } else if(left < this.player_min_left) {
                left = this.player_min_left;
            }
        }

        return {
            position: {
                left: left,
                top: top
            },
            pointer: {
                left: mouse_actual_pos.left,
                top: mouse_actual_pos.top,
                diff_left: diff_x + ($(window).scrollLeft() - this.win_offset_x),
                diff_top: diff_y + ($(window).scrollTop() - this.win_offset_y)
            }
        };
    };


    fn.get_drag_data = function(e) {
        var offset = this.get_offset(e);
        offset.$player = this.$player;
        offset.$helper = this.helper ? this.$helper : this.$player;

        return offset;
    };


    fn.set_limits = function(container_width) {
        container_width || (container_width = this.$container.width());
        this.player_max_left = (container_width - this.player_width +
            - this.options.offset_left);

        this.options.container_width = container_width;

        return this;
    };


    fn.scroll_in = function(axis, data) {
        var dir_prop = dir_map[axis];

        var area_size = 50;
        var scroll_inc = 30;

        var is_x = axis === 'x';
        var window_size = is_x ? this.window_width : this.window_height;
        var doc_size = is_x ? $(document).width() : $(document).height();
        var player_size = is_x ? this.$player.width() : this.$player.height();

        var next_scroll;
        var scroll_offset = $window['scroll' + capitalize(dir_prop)]();
        var min_window_pos = scroll_offset;
        var max_window_pos = min_window_pos + window_size;

        var mouse_next_zone = max_window_pos - area_size;  // down/right
        var mouse_prev_zone = min_window_pos + area_size;  // up/left

        var abs_mouse_pos = min_window_pos + data.pointer[dir_prop];

        var max_player_pos = (doc_size - window_size + player_size);

        if (abs_mouse_pos >= mouse_next_zone) {
            next_scroll = scroll_offset + scroll_inc;
            if (next_scroll < max_player_pos) {
                $window['scroll' + capitalize(dir_prop)](next_scroll);
                this['scroll_offset_' + axis] += scroll_inc;
            }
        }

        if (abs_mouse_pos <= mouse_prev_zone) {
            next_scroll = scroll_offset - scroll_inc;
            if (next_scroll > 0) {
                $window['scroll' + capitalize(dir_prop)](next_scroll);
                this['scroll_offset_' + axis] -= scroll_inc;
            }
        }

        return this;
    };


    fn.manage_scroll = function(data) {
        this.scroll_in('x', data);
        this.scroll_in('y', data);
    };


    fn.calculate_dimensions = function(e) {
        this.window_height = $window.height();
        this.window_width = $window.width();
    };


    fn.drag_handler = function(e) {
        var node = e.target.nodeName;
        // skip if drag is disabled, or click was not done with the mouse primary button
        if (this.disabled || e.which !== 1 && !isTouch) {
            return;
        }

        if (this.ignore_drag(e)) {
            return;
        }

        var self = this;
        var first = true;
        this.$player = $(e.currentTarget);

        this.el_init_pos = this.get_actual_pos(this.$player);
        this.mouse_init_pos = this.get_mouse_pos(e);
        this.offsetY = this.mouse_init_pos.top - this.el_init_pos.top;

        this.$document.on(this.pointer_events.move, function(mme) {
            var mouse_actual_pos = self.get_mouse_pos(mme);
            var diff_x = Math.abs(
                mouse_actual_pos.left - self.mouse_init_pos.left);
            var diff_y = Math.abs(
                mouse_actual_pos.top - self.mouse_init_pos.top);
            if (!(diff_x > self.options.distance ||
                diff_y > self.options.distance)
                ) {
                return false;
            }

            if (first) {
                first = false;
                self.on_dragstart.call(self, mme);
                return false;
            }

            if (self.is_dragging === true) {
                self.on_dragmove.call(self, mme);
            }

            return false;
        });

        if (!isTouch) { return false; }
    };


    fn.on_dragstart = function(e) {
        e.preventDefault();

        if (this.is_dragging) { return this; }

        this.drag_start = this.is_dragging = true;
        var offset = this.$container.offset();
        this.baseX = Math.round(offset.left);
        this.baseY = Math.round(offset.top);
        this.initial_container_width = this.options.container_width || this.$container.width();

        if (this.options.helper === 'clone') {
            this.$helper = this.$player.clone()
                .appendTo(this.$container).addClass('helper');
            this.helper = true;
        } else {
            this.helper = false;
        }

        this.win_offset_y = $(window).scrollTop();
        this.win_offset_x = $(window).scrollLeft();
        this.scroll_offset_y = 0;
        this.scroll_offset_x = 0;
        this.el_init_offset = this.$player.offset();
        this.player_width = this.$player.width();
        this.player_height = this.$player.height();

        this.set_limits(this.options.container_width);

        if (this.options.start) {
            this.options.start.call(this.$player, e, this.get_drag_data(e));
        }
        return false;
    };


    fn.on_dragmove = function(e) {
        var data = this.get_drag_data(e);

        this.options.autoscroll && this.manage_scroll(data);

        if (this.options.move_element) {
            (this.helper ? this.$helper : this.$player).css({
                'position': 'absolute',
                'left' : data.position.left,
                'top' : data.position.top
            });
        }

        var last_position = this.last_position || data.position;
        data.prev_position = last_position;

        if (this.options.drag) {
            this.options.drag.call(this.$player, e, data);
        }

        this.last_position = data.position;
        return false;
    };


    fn.on_dragstop = function(e) {
        var data = this.get_drag_data(e);
        this.drag_start = false;

        if (this.options.stop) {
            this.options.stop.call(this.$player, e, data);
        }

        if (this.helper && this.options.remove_helper) {
            this.$helper.remove();
        }

        return false;
    };

    fn.on_select_start = function(e) {
        if (this.disabled) { return; }

        if (this.ignore_drag(e)) {
            return;
        }

        return false;
    };

    fn.enable = function() {
        this.disabled = false;
    };

    fn.disable = function() {
        this.disabled = true;
    };

    fn.destroy = function() {
        this.disable();

        this.$container.off(this.ns);
        this.$document.off(this.ns);
        $(window).off(this.ns);

        $.removeData(this.$container, 'drag');
    };

    fn.ignore_drag = function(event) {
        if (this.options.handle) {
            return !$(event.target).is(this.options.handle);
        }

        if ($.isFunction(this.options.ignore_dragging)) {
            return this.options.ignore_dragging(event);
        }

        return $(event.target).is(this.options.ignore_dragging.join(', '));
    };

    //jQuery adapter
    $.fn.drag = function ( options ) {
        return new Draggable(this, options);
    };

    return Draggable;

}));

;(function(root, factory) {

    if (typeof define === 'function' && define.amd) {
        define(['jquery', 'gridster-draggable', 'gridster-collision'], factory);
    } else {
        root.Gridster = factory(root.$ || root.jQuery, root.GridsterDraggable,
            root.GridsterCollision);
    }

 }(this, function($, Draggable, Collision) {

    var defaults = {
        namespace: '',
        widget_selector: 'li',
        widget_margins: [10, 10],
        widget_base_dimensions: [400, 225],
        extra_rows: 0,
        extra_cols: 0,
        min_cols: 1,
        max_cols: Infinity,
        min_rows: 15,
        max_size_x: false,
        autogrow_cols: false,
        autogenerate_stylesheet: true,
        avoid_overlapped_widgets: true,
        auto_init: true,
        serialize_params: function($w, wgd) {
            return {
                col: wgd.col,
                row: wgd.row,
                size_x: wgd.size_x,
                size_y: wgd.size_y
            };
        },
        collision: {},
        draggable: {
            items: '.gs-w',
            distance: 4,
            ignore_dragging: Draggable.defaults.ignore_dragging.slice(0)
        },
        resize: {
            enabled: false,
            axes: ['both'],
            handle_append_to: '',
            handle_class: 'gs-resize-handle',
            max_size: [Infinity, Infinity],
            min_size: [1, 1]
        }
    };

    /**
    * @class Gridster
    * @uses Draggable
    * @uses Collision
    * @param {HTMLElement} el The HTMLelement that contains all the widgets.
    * @param {Object} [options] An Object with all options you want to
    *        overwrite:
    *    @param {HTMLElement|String} [options.widget_selector] Define who will
    *     be the draggable widgets. Can be a CSS Selector String or a
    *     collection of HTMLElements
    *    @param {Array} [options.widget_margins] Margin between widgets.
    *     The first index for the horizontal margin (left, right) and
    *     the second for the vertical margin (top, bottom).
    *    @param {Array} [options.widget_base_dimensions] Base widget dimensions
    *     in pixels. The first index for the width and the second for the
    *     height.
    *    @param {Number} [options.extra_cols] Add more columns in addition to
    *     those that have been calculated.
    *    @param {Number} [options.extra_rows] Add more rows in addition to
    *     those that have been calculated.
    *    @param {Number} [options.min_cols] The minimum required columns.
    *    @param {Number} [options.max_cols] The maximum columns possible (set to null
    *     for no maximum).
    *    @param {Number} [options.min_rows] The minimum required rows.
    *    @param {Number} [options.max_size_x] The maximum number of columns
    *     that a widget can span.
    *    @param {Boolean} [options.autogenerate_stylesheet] If true, all the
    *     CSS required to position all widgets in their respective columns
    *     and rows will be generated automatically and injected to the
    *     `<head>` of the document. You can set this to false, and write
    *     your own CSS targeting rows and cols via data-attributes like so:
    *     `[data-col="1"] { left: 10px; }`
    *    @param {Boolean} [options.avoid_overlapped_widgets] Avoid that widgets loaded
    *     from the DOM can be overlapped. It is helpful if the positions were
    *     bad stored in the database or if there was any conflict.
    *    @param {Boolean} [options.auto_init] Automatically call gridster init
    *     method or not when the plugin is instantiated.
    *    @param {Function} [options.serialize_params] Return the data you want
    *     for each widget in the serialization. Two arguments are passed:
    *     `$w`: the jQuery wrapped HTMLElement, and `wgd`: the grid
    *     coords object (`col`, `row`, `size_x`, `size_y`).
    *    @param {Object} [options.collision] An Object with all options for
    *     Collision class you want to overwrite. See Collision docs for
    *     more info.
    *    @param {Object} [options.draggable] An Object with all options for
    *     Draggable class you want to overwrite. See Draggable docs for more
    *     info.
    *       @param {Object|Function} [options.draggable.ignore_dragging] Note that
    *        if you use a Function, and resize is enabled, you should ignore the
    *        resize handlers manually (options.resize.handle_class).
    *    @param {Object} [options.resize] An Object with resize config options.
    *       @param {Boolean} [options.resize.enabled] Set to true to enable
    *        resizing.
    *       @param {Array} [options.resize.axes] Axes in which widgets can be
    *        resized. Possible values: ['x', 'y', 'both'].
    *       @param {String} [options.resize.handle_append_to] Set a valid CSS
    *        selector to append resize handles to.
    *       @param {String} [options.resize.handle_class] CSS class name used
    *        by resize handles.
    *       @param {Array} [options.resize.max_size] Limit widget dimensions
    *        when resizing. Array values should be integers:
    *        `[max_cols_occupied, max_rows_occupied]`
    *       @param {Array} [options.resize.min_size] Limit widget dimensions
    *        when resizing. Array values should be integers:
    *        `[min_cols_occupied, min_rows_occupied]`
    *       @param {Function} [options.resize.start] Function executed
    *        when resizing starts.
    *       @param {Function} [otions.resize.resize] Function executed
    *        during the resizing.
    *       @param {Function} [options.resize.stop] Function executed
    *        when resizing stops.
    *
    * @constructor
    */
    function Gridster(el, options) {
        this.options = $.extend(true, {}, defaults, options);
        this.$el = $(el);
        this.$wrapper = this.$el.parent();
        this.$widgets = this.$el.children(
            this.options.widget_selector).addClass('gs-w');
        this.widgets = [];
        this.$changed = $([]);
        this.wrapper_width = this.$wrapper.width();
        this.min_widget_width = (this.options.widget_margins[0] * 2) +
          this.options.widget_base_dimensions[0];
        this.min_widget_height = (this.options.widget_margins[1] * 2) +
          this.options.widget_base_dimensions[1];

        this.generated_stylesheets = [];
        this.$style_tags = $([]);

        this.options.auto_init && this.init();
    }

    Gridster.defaults = defaults;
    Gridster.generated_stylesheets = [];


    /**
    * Sorts an Array of grid coords objects (representing the grid coords of
    * each widget) in ascending way.
    *
    * @method sort_by_row_asc
    * @param {Array} widgets Array of grid coords objects
    * @return {Array} Returns the array sorted.
    */
    Gridster.sort_by_row_asc = function(widgets) {
        widgets = widgets.sort(function(a, b) {
            if (!a.row) {
                a = $(a).coords().grid;
                b = $(b).coords().grid;
            }

           if (a.row > b.row) {
               return 1;
           }
           return -1;
        });

        return widgets;
    };


    /**
    * Sorts an Array of grid coords objects (representing the grid coords of
    * each widget) placing first the empty cells upper left.
    *
    * @method sort_by_row_and_col_asc
    * @param {Array} widgets Array of grid coords objects
    * @return {Array} Returns the array sorted.
    */
    Gridster.sort_by_row_and_col_asc = function(widgets) {
        widgets = widgets.sort(function(a, b) {
           if (a.row > b.row || a.row === b.row && a.col > b.col) {
               return 1;
           }
           return -1;
        });

        return widgets;
    };


    /**
    * Sorts an Array of grid coords objects by column (representing the grid
    * coords of each widget) in ascending way.
    *
    * @method sort_by_col_asc
    * @param {Array} widgets Array of grid coords objects
    * @return {Array} Returns the array sorted.
    */
    Gridster.sort_by_col_asc = function(widgets) {
        widgets = widgets.sort(function(a, b) {
           if (a.col > b.col) {
               return 1;
           }
           return -1;
        });

        return widgets;
    };


    /**
    * Sorts an Array of grid coords objects (representing the grid coords of
    * each widget) in descending way.
    *
    * @method sort_by_row_desc
    * @param {Array} widgets Array of grid coords objects
    * @return {Array} Returns the array sorted.
    */
    Gridster.sort_by_row_desc = function(widgets) {
        widgets = widgets.sort(function(a, b) {
            if (a.row + a.size_y < b.row + b.size_y) {
                return 1;
            }
           return -1;
        });
        return widgets;
    };



    /** Instance Methods **/

    var fn = Gridster.prototype;

    fn.init = function() {
        this.options.resize.enabled && this.setup_resize();
        this.generate_grid_and_stylesheet();
        this.get_widgets_from_DOM();
        this.set_dom_grid_height();
        this.set_dom_grid_width();
        this.$wrapper.addClass('ready');
        this.draggable();
        this.options.resize.enabled && this.resizable();

        $(window).bind('resize.gridster', throttle(
            $.proxy(this.recalculate_faux_grid, this), 200));
    };


    /**
    * Disables dragging.
    *
    * @method disable
    * @return {Class} Returns the instance of the Gridster Class.
    */
    fn.disable = function() {
        this.$wrapper.find('.player-revert').removeClass('player-revert');
        this.drag_api.disable();
        return this;
    };


    /**
    * Enables dragging.
    *
    * @method enable
    * @return {Class} Returns the instance of the Gridster Class.
    */
    fn.enable = function() {
        this.drag_api.enable();
        return this;
    };



    /**
    * Disables drag-and-drop widget resizing.
    *
    * @method disable
    * @return {Class} Returns instance of gridster Class.
    */
    fn.disable_resize = function() {
        this.$el.addClass('gs-resize-disabled');
        this.resize_api.disable();
        return this;
    };


    /**
    * Enables drag-and-drop widget resizing.
    *
    * @method enable
    * @return {Class} Returns instance of gridster Class.
    */
    fn.enable_resize = function() {
        this.$el.removeClass('gs-resize-disabled');
        this.resize_api.enable();
        return this;
    };


    /**
    * Add a new widget to the grid.
    *
    * @method add_widget
    * @param {String|HTMLElement} html The string representing the HTML of the widget
    *  or the HTMLElement.
    * @param {Number} [size_x] The nº of rows the widget occupies horizontally.
    * @param {Number} [size_y] The nº of columns the widget occupies vertically.
    * @param {Number} [col] The column the widget should start in.
    * @param {Number} [row] The row the widget should start in.
    * @param {Array} [max_size] max_size Maximun size (in units) for width and height.
    * @param {Array} [min_size] min_size Minimum size (in units) for width and height.
    * @return {HTMLElement} Returns the jQuery wrapped HTMLElement representing.
    *  the widget that was just created.
    */
    fn.add_widget = function(html, size_x, size_y, col, row, max_size, min_size) {
        var pos;
        size_x || (size_x = 1);
        size_y || (size_y = 1);

        if (!col & !row) {
            pos = this.next_position(size_x, size_y);
        } else {
            pos = {
                col: col,
                row: row,
                size_x: size_x,
                size_y: size_y
            };

            this.empty_cells(col, row, size_x, size_y);
        }

        var $w = $(html).attr({
                'data-col': pos.col,
                'data-row': pos.row,
                'data-sizex' : size_x,
                'data-sizey' : size_y
            }).addClass('gs-w').appendTo(this.$el).hide();

        this.$widgets = this.$widgets.add($w);

        this.register_widget($w);

        this.add_faux_rows(pos.size_y);
        //this.add_faux_cols(pos.size_x);

        if (max_size) {
            this.set_widget_max_size($w, max_size);
        }

        if (min_size) {
            this.set_widget_min_size($w, min_size);
        }

        this.set_dom_grid_width();
        this.set_dom_grid_height();

        this.drag_api.set_limits(this.cols * this.min_widget_width);

        return $w.fadeIn();
    };


    /**
    * Change widget size limits.
    *
    * @method set_widget_min_size
    * @param {HTMLElement|Number} $widget The jQuery wrapped HTMLElement
    *  representing the widget or an index representing the desired widget.
    * @param {Array} min_size Minimum size (in units) for width and height.
    * @return {HTMLElement} Returns instance of gridster Class.
    */
    fn.set_widget_min_size = function($widget, min_size) {
        $widget = typeof $widget === 'number' ?
            this.$widgets.eq($widget) : $widget;

        if (!$widget.length) { return this; }

        var wgd = $widget.data('coords').grid;
        wgd.min_size_x = min_size[0];
        wgd.min_size_y = min_size[1];

        return this;
    };


    /**
    * Change widget size limits.
    *
    * @method set_widget_max_size
    * @param {HTMLElement|Number} $widget The jQuery wrapped HTMLElement
    *  representing the widget or an index representing the desired widget.
    * @param {Array} max_size Maximun size (in units) for width and height.
    * @return {HTMLElement} Returns instance of gridster Class.
    */
    fn.set_widget_max_size = function($widget, max_size) {
        $widget = typeof $widget === 'number' ?
            this.$widgets.eq($widget) : $widget;

        if (!$widget.length) { return this; }

        var wgd = $widget.data('coords').grid;
        wgd.max_size_x = max_size[0];
        wgd.max_size_y = max_size[1];

        return this;
    };


    /**
    * Append the resize handle into a widget.
    *
    * @method add_resize_handle
    * @param {HTMLElement} $widget The jQuery wrapped HTMLElement
    *  representing the widget.
    * @return {HTMLElement} Returns instance of gridster Class.
    */
    fn.add_resize_handle = function($w) {
        var append_to = this.options.resize.handle_append_to;
        $(this.resize_handle_tpl).appendTo( append_to ? $(append_to, $w) : $w);

        return this;
    };


    /**
    * Change the size of a widget. Width is limited to the current grid width.
    *
    * @method resize_widget
    * @param {HTMLElement} $widget The jQuery wrapped HTMLElement
    *  representing the widget.
    * @param {Number} size_x The number of columns that will occupy the widget.
    *  By default <code>size_x</code> is limited to the space available from
    *  the column where the widget begins, until the last column to the right.
    * @param {Number} size_y The number of rows that will occupy the widget.
    * @param {Function} [callback] Function executed when the widget is removed.
    * @return {HTMLElement} Returns $widget.
    */
    fn.resize_widget = function($widget, size_x, size_y, callback) {
        var wgd = $widget.coords().grid;
        var col = wgd.col;
        var max_cols = this.options.max_cols;
        var old_size_y = wgd.size_y;
        var old_col = wgd.col;
        var new_col = old_col;

        size_x || (size_x = wgd.size_x);
        size_y || (size_y = wgd.size_y);

        if (max_cols !== Infinity) {
            size_x = Math.min(size_x, max_cols - col + 1);
        }

        if (size_y > old_size_y) {
            this.add_faux_rows(Math.max(size_y - old_size_y, 0));
        }

        var player_rcol = (col + size_x - 1);
        if (player_rcol > this.cols) {
            this.add_faux_cols(player_rcol - this.cols);
        }

        var new_grid_data = {
            col: new_col,
            row: wgd.row,
            size_x: size_x,
            size_y: size_y
        };

        this.mutate_widget_in_gridmap($widget, wgd, new_grid_data);

        this.set_dom_grid_height();
        this.set_dom_grid_width();

        if (callback) {
            callback.call(this, new_grid_data.size_x, new_grid_data.size_y);
        }

        return $widget;
    };


    /**
    * Mutate widget dimensions and position in the grid map.
    *
    * @method mutate_widget_in_gridmap
    * @param {HTMLElement} $widget The jQuery wrapped HTMLElement
    *  representing the widget to mutate.
    * @param {Object} wgd Current widget grid data (col, row, size_x, size_y).
    * @param {Object} new_wgd New widget grid data.
    * @return {HTMLElement} Returns instance of gridster Class.
    */
    fn.mutate_widget_in_gridmap = function($widget, wgd, new_wgd) {
        var old_size_x = wgd.size_x;
        var old_size_y = wgd.size_y;

        var old_cells_occupied = this.get_cells_occupied(wgd);
        var new_cells_occupied = this.get_cells_occupied(new_wgd);

        var empty_cols = [];
        $.each(old_cells_occupied.cols, function(i, col) {
            if ($.inArray(col, new_cells_occupied.cols) === -1) {
                empty_cols.push(col);
            }
        });

        var occupied_cols = [];
        $.each(new_cells_occupied.cols, function(i, col) {
            if ($.inArray(col, old_cells_occupied.cols) === -1) {
                occupied_cols.push(col);
            }
        });

        var empty_rows = [];
        $.each(old_cells_occupied.rows, function(i, row) {
            if ($.inArray(row, new_cells_occupied.rows) === -1) {
                empty_rows.push(row);
            }
        });

        var occupied_rows = [];
        $.each(new_cells_occupied.rows, function(i, row) {
            if ($.inArray(row, old_cells_occupied.rows) === -1) {
                occupied_rows.push(row);
            }
        });

        this.remove_from_gridmap(wgd);

        if (occupied_cols.length) {
            var cols_to_empty = [
                new_wgd.col, new_wgd.row, new_wgd.size_x, Math.min(old_size_y, new_wgd.size_y), $widget
            ];
            this.empty_cells.apply(this, cols_to_empty);
        }

        if (occupied_rows.length) {
            var rows_to_empty = [new_wgd.col, new_wgd.row, new_wgd.size_x, new_wgd.size_y, $widget];
            this.empty_cells.apply(this, rows_to_empty);
        }

        // not the same that wgd = new_wgd;
        wgd.col = new_wgd.col;
        wgd.row = new_wgd.row;
        wgd.size_x = new_wgd.size_x;
        wgd.size_y = new_wgd.size_y;

        this.add_to_gridmap(new_wgd, $widget);

        $widget.removeClass('player-revert');

        //update coords instance attributes
        $widget.data('coords').update({
            width: (new_wgd.size_x * this.options.widget_base_dimensions[0] +
                ((new_wgd.size_x - 1) * this.options.widget_margins[0]) * 2),
            height: (new_wgd.size_y * this.options.widget_base_dimensions[1] +
                ((new_wgd.size_y - 1) * this.options.widget_margins[1]) * 2)
        });

        $widget.attr({
            'data-col': new_wgd.col,
            'data-row': new_wgd.row,
            'data-sizex': new_wgd.size_x,
            'data-sizey': new_wgd.size_y
        });

        if (empty_cols.length) {
            var cols_to_remove_holes = [
                empty_cols[0], new_wgd.row,
                empty_cols.length,
                Math.min(old_size_y, new_wgd.size_y),
                $widget
            ];

            this.remove_empty_cells.apply(this, cols_to_remove_holes);
        }

        if (empty_rows.length) {
            var rows_to_remove_holes = [
                new_wgd.col, new_wgd.row, new_wgd.size_x, new_wgd.size_y, $widget
            ];
            this.remove_empty_cells.apply(this, rows_to_remove_holes);
        }

        this.move_widget_up($widget);

        return this;
    };


    /**
    * Move down widgets in cells represented by the arguments col, row, size_x,
    * size_y
    *
    * @method empty_cells
    * @param {Number} col The column where the group of cells begin.
    * @param {Number} row The row where the group of cells begin.
    * @param {Number} size_x The number of columns that the group of cells
    * occupy.
    * @param {Number} size_y The number of rows that the group of cells
    * occupy.
    * @param {HTMLElement} $exclude Exclude widgets from being moved.
    * @return {Class} Returns the instance of the Gridster Class.
    */
    fn.empty_cells = function(col, row, size_x, size_y, $exclude) {
        var $nexts = this.widgets_below({
                col: col,
                row: row - size_y,
                size_x: size_x,
                size_y: size_y
            });

        $nexts.not($exclude).each($.proxy(function(i, w) {
            var wgd = $(w).coords().grid;
            if ( !(wgd.row <= (row + size_y - 1))) { return; }
            var diff =  (row + size_y) - wgd.row;
            this.move_widget_down($(w), diff);
        }, this));

        this.set_dom_grid_height();

        return this;
    };


    /**
    * Move up widgets below cells represented by the arguments col, row, size_x,
    * size_y.
    *
    * @method remove_empty_cells
    * @param {Number} col The column where the group of cells begin.
    * @param {Number} row The row where the group of cells begin.
    * @param {Number} size_x The number of columns that the group of cells
    * occupy.
    * @param {Number} size_y The number of rows that the group of cells
    * occupy.
    * @param {HTMLElement} exclude Exclude widgets from being moved.
    * @return {Class} Returns the instance of the Gridster Class.
    */
    fn.remove_empty_cells = function(col, row, size_x, size_y, exclude) {
        var $nexts = this.widgets_below({
            col: col,
            row: row,
            size_x: size_x,
            size_y: size_y
        });

        $nexts.not(exclude).each($.proxy(function(i, widget) {
            this.move_widget_up( $(widget), size_y );
        }, this));

        this.set_dom_grid_height();

        return this;
    };


    /**
    * Get the most left column below to add a new widget.
    *
    * @method next_position
    * @param {Number} size_x The nº of rows the widget occupies horizontally.
    * @param {Number} size_y The nº of columns the widget occupies vertically.
    * @return {Object} Returns a grid coords object representing the future
    *  widget coords.
    */
    fn.next_position = function(size_x, size_y) {
        size_x || (size_x = 1);
        size_y || (size_y = 1);
        var ga = this.gridmap;
        var cols_l = ga.length;
        var valid_pos = [];
        var rows_l;

        for (var c = 1; c < cols_l; c++) {
            rows_l = ga[c].length;
            for (var r = 1; r <= rows_l; r++) {
                var can_move_to = this.can_move_to({
                    size_x: size_x,
                    size_y: size_y
                }, c, r);

                if (can_move_to) {
                    valid_pos.push({
                        col: c,
                        row: r,
                        size_y: size_y,
                        size_x: size_x
                    });
                }
            }
        }

        if (valid_pos.length) {
            return Gridster.sort_by_row_and_col_asc(valid_pos)[0];
        }
        return false;
    };


    /**
    * Remove a widget from the grid.
    *
    * @method remove_widget
    * @param {HTMLElement} el The jQuery wrapped HTMLElement you want to remove.
    * @param {Boolean|Function} silent If true, widgets below the removed one
    * will not move up. If a Function is passed it will be used as callback.
    * @param {Function} callback Function executed when the widget is removed.
    * @return {Class} Returns the instance of the Gridster Class.
    */
    fn.remove_widget = function(el, silent, callback) {
        var $el = el instanceof $ ? el : $(el);
        var wgd = $el.coords().grid;

        // if silent is a function assume it's a callback
        if ($.isFunction(silent)) {
            callback = silent;
            silent = false;
        }

        this.cells_occupied_by_placeholder = {};
        this.$widgets = this.$widgets.not($el);

        var $nexts = this.widgets_below($el);

        this.remove_from_gridmap(wgd);

        $el.fadeOut($.proxy(function() {
            $el.remove();

            if (!silent) {
                $nexts.each($.proxy(function(i, widget) {
                    this.move_widget_up( $(widget), wgd.size_y );
                }, this));
            }

            this.set_dom_grid_height();

            if (callback) {
                callback.call(this, el);
            }
        }, this));

        return this;
    };


    /**
    * Remove all widgets from the grid.
    *
    * @method remove_all_widgets
    * @param {Function} callback Function executed for each widget removed.
    * @return {Class} Returns the instance of the Gridster Class.
    */
    fn.remove_all_widgets = function(callback) {
        this.$widgets.each($.proxy(function(i, el){
              this.remove_widget(el, true, callback);
        }, this));

        return this;
    };


    /**
    * Returns a serialized array of the widgets in the grid.
    *
    * @method serialize
    * @param {HTMLElement} [$widgets] The collection of jQuery wrapped
    *  HTMLElements you want to serialize. If no argument is passed all widgets
    *  will be serialized.
    * @return {Array} Returns an Array of Objects with the data specified in
    *  the serialize_params option.
    */
    fn.serialize = function($widgets) {
        $widgets || ($widgets = this.$widgets);

        return $widgets.map($.proxy(function(i, widget) {
            var $w = $(widget);
            return this.options.serialize_params($w, $w.coords().grid);
        }, this)).get();
    };


    /**
    * Returns a serialized array of the widgets that have changed their
    *  position.
    *
    * @method serialize_changed
    * @return {Array} Returns an Array of Objects with the data specified in
    *  the serialize_params option.
    */
    fn.serialize_changed = function() {
        return this.serialize(this.$changed);
    };


    /**
    * Convert widgets from DOM elements to "widget grid data" Objects.
    *
    * @method dom_to_coords
    * @param {HTMLElement} $widget The widget to be converted.
    */
    fn.dom_to_coords = function($widget) {
        return {
            'col': parseInt($widget.attr('data-col'), 10),
            'row': parseInt($widget.attr('data-row'), 10),
            'size_x': parseInt($widget.attr('data-sizex'), 10) || 1,
            'size_y': parseInt($widget.attr('data-sizey'), 10) || 1,
            'max_size_x': parseInt($widget.attr('data-max-sizex'), 10) || false,
            'max_size_y': parseInt($widget.attr('data-max-sizey'), 10) || false,
            'min_size_x': parseInt($widget.attr('data-min-sizex'), 10) || false,
            'min_size_y': parseInt($widget.attr('data-min-sizey'), 10) || false,
            'el': $widget
        };
    };


    /**
    * Creates the grid coords object representing the widget an add it to the
    * mapped array of positions.
    *
    * @method register_widget
    * @param {HTMLElement|Object} $el jQuery wrapped HTMLElement representing
    *  the widget, or an "widget grid data" Object with (col, row, el ...).
    * @return {Boolean} Returns true if the widget final position is different
    *  than the original.
    */
    fn.register_widget = function($el) {
        var isDOM = $el instanceof jQuery;
        var wgd = isDOM ? this.dom_to_coords($el) : $el;
        var posChanged = false;
        isDOM || ($el = wgd.el);

        var empty_upper_row = this.can_go_widget_up(wgd);
        if (empty_upper_row) {
            wgd.row = empty_upper_row;
            $el.attr('data-row', empty_upper_row);
            this.$el.trigger('gridster:positionchanged', [wgd]);
            posChanged = true;
        }

        if (this.options.avoid_overlapped_widgets &&
            !this.can_move_to(
             {size_x: wgd.size_x, size_y: wgd.size_y}, wgd.col, wgd.row)
        ) {
            $.extend(wgd, this.next_position(wgd.size_x, wgd.size_y));
            $el.attr({
                'data-col': wgd.col,
                'data-row': wgd.row,
                'data-sizex': wgd.size_x,
                'data-sizey': wgd.size_y
            });
            posChanged = true;
        }

        // attach Coord object to player data-coord attribute
        $el.data('coords', $el.coords());
        // Extend Coord object with grid position info
        $el.data('coords').grid = wgd;

        this.add_to_gridmap(wgd, $el);

        this.options.resize.enabled && this.add_resize_handle($el);

        return posChanged;
    };


    /**
    * Update in the mapped array of positions the value of cells represented by
    * the grid coords object passed in the `grid_data` param.
    *
    * @param {Object} grid_data The grid coords object representing the cells
    *  to update in the mapped array.
    * @param {HTMLElement|Boolean} value Pass `false` or the jQuery wrapped
    *  HTMLElement, depends if you want to delete an existing position or add
    *  a new one.
    * @method update_widget_position
    * @return {Class} Returns the instance of the Gridster Class.
    */
    fn.update_widget_position = function(grid_data, value) {
        this.for_each_cell_occupied(grid_data, function(col, row) {
            if (!this.gridmap[col]) { return this; }
            this.gridmap[col][row] = value;
        });
        return this;
    };


    /**
    * Remove a widget from the mapped array of positions.
    *
    * @method remove_from_gridmap
    * @param {Object} grid_data The grid coords object representing the cells
    *  to update in the mapped array.
    * @return {Class} Returns the instance of the Gridster Class.
    */
    fn.remove_from_gridmap = function(grid_data) {
        return this.update_widget_position(grid_data, false);
    };


    /**
    * Add a widget to the mapped array of positions.
    *
    * @method add_to_gridmap
    * @param {Object} grid_data The grid coords object representing the cells
    *  to update in the mapped array.
    * @param {HTMLElement|Boolean} value The value to set in the specified
    *  position .
    * @return {Class} Returns the instance of the Gridster Class.
    */
    fn.add_to_gridmap = function(grid_data, value) {
        this.update_widget_position(grid_data, value || grid_data.el);

        if (grid_data.el) {
            var $widgets = this.widgets_below(grid_data.el);
            $widgets.each($.proxy(function(i, widget) {
                this.move_widget_up( $(widget));
            }, this));
        }
    };


    /**
    * Make widgets draggable.
    *
    * @uses Draggable
    * @method draggable
    * @return {Class} Returns the instance of the Gridster Class.
    */
    fn.draggable = function() {
        var self = this;
        var draggable_options = $.extend(true, {}, this.options.draggable, {
            offset_left: this.options.widget_margins[0],
            offset_top: this.options.widget_margins[1],
            container_width: this.cols * this.min_widget_width,
            limit: true,
            start: function(event, ui) {
                self.$widgets.filter('.player-revert')
                    .removeClass('player-revert');

                self.$player = $(this);
                self.$helper = $(ui.$helper);

                self.helper = !self.$helper.is(self.$player);

                self.on_start_drag.call(self, event, ui);
                self.$el.trigger('gridster:dragstart');
            },
            stop: function(event, ui) {
                self.on_stop_drag.call(self, event, ui);
                self.$el.trigger('gridster:dragstop');
            },
            drag: throttle(function(event, ui) {
                self.on_drag.call(self, event, ui);
                self.$el.trigger('gridster:drag');
            }, 60)
          });

        this.drag_api = this.$el.drag(draggable_options);
        return this;
    };


    /**
    * Bind resize events to get resize working.
    *
    * @method resizable
    * @return {Class} Returns instance of gridster Class.
    */
    fn.resizable = function() {
        this.resize_api = this.$el.drag({
            items: '.' + this.options.resize.handle_class,
            offset_left: this.options.widget_margins[0],
            container_width: this.container_width,
            move_element: false,
            resize: true,
            limit: this.options.autogrow_cols ? false : true,
            start: $.proxy(this.on_start_resize, this),
            stop: $.proxy(function(event, ui) {
                delay($.proxy(function() {
                    this.on_stop_resize(event, ui);
                }, this), 120);
            }, this),
            drag: throttle($.proxy(this.on_resize, this), 60)
        });

        return this;
    };


    /**
    * Setup things required for resizing. Like build templates for drag handles.
    *
    * @method setup_resize
    * @return {Class} Returns instance of gridster Class.
    */
    fn.setup_resize = function() {
        this.resize_handle_class = this.options.resize.handle_class;
        var axes = this.options.resize.axes;
        var handle_tpl = '<span class="' + this.resize_handle_class + ' ' +
            this.resize_handle_class + '-{type}" />';

        this.resize_handle_tpl = $.map(axes, function(type) {
            return handle_tpl.replace('{type}', type);
        }).join('');

        if ($.isArray(this.options.draggable.ignore_dragging)) {
            this.options.draggable.ignore_dragging.push(
                '.' + this.resize_handle_class);
        }

        return this;
    };


    /**
    * This function is executed when the player begins to be dragged.
    *
    * @method on_start_drag
    * @param {Event} event The original browser event
    * @param {Object} ui A prepared ui object with useful drag-related data
    */
    fn.on_start_drag = function(event, ui) {
        this.$helper.add(this.$player).add(this.$wrapper).addClass('dragging');

        this.highest_col = this.get_highest_occupied_cell().col;

        this.$player.addClass('player');
        this.player_grid_data = this.$player.coords().grid;
        this.placeholder_grid_data = $.extend({}, this.player_grid_data);

        this.set_dom_grid_height(this.$el.height() +
            (this.player_grid_data.size_y * this.min_widget_height));

        this.set_dom_grid_width(this.cols);

        var pgd_sizex = this.player_grid_data.size_x;
        var cols_diff = this.cols - this.highest_col;

        if (this.options.autogrow_cols && cols_diff <= pgd_sizex) {
            this.add_faux_cols(Math.min(pgd_sizex - cols_diff, 1));
        }

        var colliders = this.faux_grid;
        var coords = this.$player.data('coords').coords;

        this.cells_occupied_by_player = this.get_cells_occupied(
            this.player_grid_data);
        this.cells_occupied_by_placeholder = this.get_cells_occupied(
            this.placeholder_grid_data);

        this.last_cols = [];
        this.last_rows = [];

        // see jquery.collision.js
        this.collision_api = this.$helper.collision(
            colliders, this.options.collision);

        this.$preview_holder = $('<' + this.$player.get(0).tagName + ' />', {
              'class': 'preview-holder',
              'data-row': this.$player.attr('data-row'),
              'data-col': this.$player.attr('data-col'),
              css: {
                  width: coords.width,
                  height: coords.height
              }
        }).appendTo(this.$el);

        if (this.options.draggable.start) {
          this.options.draggable.start.call(this, event, ui);
        }
    };


    /**
    * This function is executed when the player is being dragged.
    *
    * @method on_drag
    * @param {Event} event The original browser event
    * @param {Object} ui A prepared ui object with useful drag-related data
    */
    fn.on_drag = function(event, ui) {
        //break if dragstop has been fired
        if (this.$player === null) {
            return false;
        }

        var abs_offset = {
            left: ui.position.left + this.baseX,
            top: ui.position.top + this.baseY
        };

        // auto grow cols
        if (this.options.autogrow_cols) {
            var prcol = this.placeholder_grid_data.col +
                this.placeholder_grid_data.size_x - 1;

            // "- 1" due to adding at least 1 column in on_start_drag
            if (prcol >= this.cols - 1 && this.options.max_cols >= this.cols + 1) {
                this.add_faux_cols(1);
                this.set_dom_grid_width(this.cols + 1);
                this.drag_api.set_limits(this.container_width);
            }

            this.collision_api.set_colliders(this.faux_grid);
        }

        this.colliders_data = this.collision_api.get_closest_colliders(
            abs_offset);

        this.on_overlapped_column_change(
            this.on_start_overlapping_column, this.on_stop_overlapping_column);

        this.on_overlapped_row_change(
            this.on_start_overlapping_row, this.on_stop_overlapping_row);


        if (this.helper && this.$player) {
            this.$player.css({
                'left': ui.position.left,
                'top': ui.position.top
            });
        }

        if (this.options.draggable.drag) {
            this.options.draggable.drag.call(this, event, ui);
        }
    };


    /**
    * This function is executed when the player stops being dragged.
    *
    * @method on_stop_drag
    * @param {Event} event The original browser event
    * @param {Object} ui A prepared ui object with useful drag-related data
    */
    fn.on_stop_drag = function(event, ui) {
        this.$helper.add(this.$player).add(this.$wrapper)
            .removeClass('dragging');

        ui.position.left = ui.position.left + this.baseX;
        ui.position.top = ui.position.top + this.baseY;
        this.colliders_data = this.collision_api.get_closest_colliders(
            ui.position);

        this.on_overlapped_column_change(
            this.on_start_overlapping_column,
            this.on_stop_overlapping_column
        );

        this.on_overlapped_row_change(
            this.on_start_overlapping_row,
            this.on_stop_overlapping_row
        );

        this.$player.addClass('player-revert').removeClass('player')
            .attr({
                'data-col': this.placeholder_grid_data.col,
                'data-row': this.placeholder_grid_data.row
            }).css({
                'left': '',
                'top': ''
            });

        this.$changed = this.$changed.add(this.$player);

        this.cells_occupied_by_player = this.get_cells_occupied(
            this.placeholder_grid_data);
        this.set_cells_player_occupies(
            this.placeholder_grid_data.col, this.placeholder_grid_data.row);

        this.$player.coords().grid.row = this.placeholder_grid_data.row;
        this.$player.coords().grid.col = this.placeholder_grid_data.col;

        if (this.options.draggable.stop) {
          this.options.draggable.stop.call(this, event, ui);
        }

        this.$preview_holder.remove();

        this.$player = null;
        this.$helper = null;
        this.placeholder_grid_data = {};
        this.player_grid_data = {};
        this.cells_occupied_by_placeholder = {};
        this.cells_occupied_by_player = {};

        this.set_dom_grid_height();
        this.set_dom_grid_width();

        if (this.options.autogrow_cols) {
            this.drag_api.set_limits(this.cols * this.min_widget_width);
        }
    };


    /**
    * This function is executed every time a widget starts to be resized.
    *
    * @method on_start_resize
    * @param {Event} event The original browser event
    * @param {Object} ui A prepared ui object with useful drag-related data
    */
    fn.on_start_resize = function(event, ui) {
        this.$resized_widget = ui.$player.closest('.gs-w');
        this.resize_coords = this.$resized_widget.coords();
        this.resize_wgd = this.resize_coords.grid;
        this.resize_initial_width = this.resize_coords.coords.width;
        this.resize_initial_height = this.resize_coords.coords.height;
        this.resize_initial_sizex = this.resize_coords.grid.size_x;
        this.resize_initial_sizey = this.resize_coords.grid.size_y;
        this.resize_initial_col = this.resize_coords.grid.col;
        this.resize_last_sizex = this.resize_initial_sizex;
        this.resize_last_sizey = this.resize_initial_sizey;

        this.resize_max_size_x = Math.min(this.resize_wgd.max_size_x ||
            this.options.resize.max_size[0],
            this.options.max_cols - this.resize_initial_col + 1);
        this.resize_max_size_y = this.resize_wgd.max_size_y ||
            this.options.resize.max_size[1];

        this.resize_min_size_x = (this.resize_wgd.min_size_x ||
            this.options.resize.min_size[0] || 1);
        this.resize_min_size_y = (this.resize_wgd.min_size_y ||
            this.options.resize.min_size[1] || 1);

        this.resize_initial_last_col = this.get_highest_occupied_cell().col;

        this.set_dom_grid_width(this.cols);

        this.resize_dir = {
            right: ui.$player.is('.' + this.resize_handle_class + '-x'),
            bottom: ui.$player.is('.' + this.resize_handle_class + '-y')
        };

        this.$resized_widget.css({
            'min-width': this.options.widget_base_dimensions[0],
            'min-height': this.options.widget_base_dimensions[1]
        });

        var nodeName = this.$resized_widget.get(0).tagName;
        this.$resize_preview_holder = $('<' + nodeName + ' />', {
              'class': 'preview-holder resize-preview-holder',
              'data-row': this.$resized_widget.attr('data-row'),
              'data-col': this.$resized_widget.attr('data-col'),
              'css': {
                  'width': this.resize_initial_width,
                  'height': this.resize_initial_height
              }
        }).appendTo(this.$el);

        this.$resized_widget.addClass('resizing');

		if (this.options.resize.start) {
            this.options.resize.start.call(this, event, ui, this.$resized_widget);
        }

        this.$el.trigger('gridster:resizestart');
    };


    /**
    * This function is executed every time a widget stops being resized.
    *
    * @method on_stop_resize
    * @param {Event} event The original browser event
    * @param {Object} ui A prepared ui object with useful drag-related data
    */
    fn.on_stop_resize = function(event, ui) {
        this.$resized_widget
            .removeClass('resizing')
            .css({
                'width': '',
                'height': ''
            });

        delay($.proxy(function() {
            this.$resize_preview_holder
                .remove()
                .css({
                    'min-width': '',
                    'min-height': ''
                });

            if (this.options.resize.stop) {
                this.options.resize.stop.call(this, event, ui, this.$resized_widget);
            }

            this.$el.trigger('gridster:resizestop');
        }, this), 300);

        this.set_dom_grid_width();

        if (this.options.autogrow_cols) {
            this.drag_api.set_limits(this.cols * this.min_widget_width);
        }
    };


    /**
    * This function is executed when a widget is being resized.
    *
    * @method on_resize
    * @param {Event} event The original browser event
    * @param {Object} ui A prepared ui object with useful drag-related data
    */
    fn.on_resize = function(event, ui) {
        var rel_x = (ui.pointer.diff_left);
        var rel_y = (ui.pointer.diff_top);
        var wbd_x = this.options.widget_base_dimensions[0];
        var wbd_y = this.options.widget_base_dimensions[1];
        var margin_x = this.options.widget_margins[0];
        var margin_y = this.options.widget_margins[1];
        var max_size_x = this.resize_max_size_x;
        var min_size_x = this.resize_min_size_x;
        var max_size_y = this.resize_max_size_y;
        var min_size_y = this.resize_min_size_y;
        var autogrow = this.options.autogrow_cols;
        var width;
        var max_width = Infinity;
        var max_height = Infinity;

        var inc_units_x = Math.ceil((rel_x / (wbd_x + margin_x * 2)) - 0.2);
        var inc_units_y = Math.ceil((rel_y / (wbd_y + margin_y * 2)) - 0.2);

        var size_x = Math.max(1, this.resize_initial_sizex + inc_units_x);
        var size_y = Math.max(1, this.resize_initial_sizey + inc_units_y);

        var max_cols = (this.container_width / this.min_widget_width) -
            this.resize_initial_col + 1;
        var limit_width = ((max_cols * this.min_widget_width) - margin_x * 2);

        size_x = Math.max(Math.min(size_x, max_size_x), min_size_x);
        size_x = Math.min(max_cols, size_x);
        width = (max_size_x * wbd_x) + ((size_x - 1) * margin_x * 2);
        max_width = Math.min(width, limit_width);
        min_width = (min_size_x * wbd_x) + ((size_x - 1) * margin_x * 2);

        size_y = Math.max(Math.min(size_y, max_size_y), min_size_y);
        max_height = (max_size_y * wbd_y) + ((size_y - 1) * margin_y * 2);
        min_height = (min_size_y * wbd_y) + ((size_y - 1) * margin_y * 2);

        if (this.resize_dir.right) {
            size_y = this.resize_initial_sizey;
        } else if (this.resize_dir.bottom) {
            size_x = this.resize_initial_sizex;
        }

        if (autogrow) {
            var last_widget_col = this.resize_initial_col + size_x - 1;
            if (autogrow && this.resize_initial_last_col <= last_widget_col) {
                this.set_dom_grid_width(Math.max(last_widget_col + 1, this.cols));

                if (this.cols < last_widget_col) {
                    this.add_faux_cols(last_widget_col - this.cols);
                }
            }
        }

        var css_props = {};
        !this.resize_dir.bottom && (css_props.width = Math.max(Math.min(
            this.resize_initial_width + rel_x, max_width), min_width));
        !this.resize_dir.right && (css_props.height = Math.max(Math.min(
            this.resize_initial_height + rel_y, max_height), min_height));

        this.$resized_widget.css(css_props);

        if (size_x !== this.resize_last_sizex ||
            size_y !== this.resize_last_sizey) {

            this.resize_widget(this.$resized_widget, size_x, size_y);
            this.set_dom_grid_width(this.cols);

            this.$resize_preview_holder.css({
                'width': '',
                'height': ''
            }).attr({
                'data-row': this.$resized_widget.attr('data-row'),
                'data-sizex': size_x,
                'data-sizey': size_y
            });
        }

        if (this.options.resize.resize) {
            this.options.resize.resize.call(this, event, ui, this.$resized_widget);
        }

        this.$el.trigger('gridster:resize');

        this.resize_last_sizex = size_x;
        this.resize_last_sizey = size_y;
    };


    /**
    * Executes the callbacks passed as arguments when a column begins to be
    * overlapped or stops being overlapped.
    *
    * @param {Function} start_callback Function executed when a new column
    *  begins to be overlapped. The column is passed as first argument.
    * @param {Function} stop_callback Function executed when a column stops
    *  being overlapped. The column is passed as first argument.
    * @method on_overlapped_column_change
    * @return {Class} Returns the instance of the Gridster Class.
    */
    fn.on_overlapped_column_change = function(start_callback, stop_callback) {
        if (!this.colliders_data.length) {
            return this;
        }
        var cols = this.get_targeted_columns(
            this.colliders_data[0].el.data.col);

        var last_n_cols = this.last_cols.length;
        var n_cols = cols.length;
        var i;

        for (i = 0; i < n_cols; i++) {
            if ($.inArray(cols[i], this.last_cols) === -1) {
                (start_callback || $.noop).call(this, cols[i]);
            }
        }

        for (i = 0; i< last_n_cols; i++) {
            if ($.inArray(this.last_cols[i], cols) === -1) {
                (stop_callback || $.noop).call(this, this.last_cols[i]);
            }
        }

        this.last_cols = cols;

        return this;
    };


    /**
    * Executes the callbacks passed as arguments when a row starts to be
    * overlapped or stops being overlapped.
    *
    * @param {Function} start_callback Function executed when a new row begins
    *  to be overlapped. The row is passed as first argument.
    * @param {Function} end_callback Function executed when a row stops being
    *  overlapped. The row is passed as first argument.
    * @method on_overlapped_row_change
    * @return {Class} Returns the instance of the Gridster Class.
    */
    fn.on_overlapped_row_change = function(start_callback, end_callback) {
        if (!this.colliders_data.length) {
            return this;
        }
        var rows = this.get_targeted_rows(this.colliders_data[0].el.data.row);
        var last_n_rows = this.last_rows.length;
        var n_rows = rows.length;
        var i;

        for (i = 0; i < n_rows; i++) {
            if ($.inArray(rows[i], this.last_rows) === -1) {
                (start_callback || $.noop).call(this, rows[i]);
            }
        }

        for (i = 0; i < last_n_rows; i++) {
            if ($.inArray(this.last_rows[i], rows) === -1) {
                (end_callback || $.noop).call(this, this.last_rows[i]);
            }
        }

        this.last_rows = rows;
    };


    /**
    * Sets the current position of the player
    *
    * @param {Number} col
    * @param {Number} row
    * @param {Boolean} no_player
    * @method set_player
    * @return {object}
    */
    fn.set_player = function(col, row, no_player) {
        var self = this;
        if (!no_player) {
            this.empty_cells_player_occupies();
        }
        var cell = !no_player ? self.colliders_data[0].el.data : {col: col};
        var to_col = cell.col;
        var to_row = row || cell.row;

        this.player_grid_data = {
            col: to_col,
            row: to_row,
            size_y : this.player_grid_data.size_y,
            size_x : this.player_grid_data.size_x
        };

        this.cells_occupied_by_player = this.get_cells_occupied(
            this.player_grid_data);

        var $overlapped_widgets = this.get_widgets_overlapped(
            this.player_grid_data);

        var constraints = this.widgets_constraints($overlapped_widgets);

        this.manage_movements(constraints.can_go_up, to_col, to_row);
        this.manage_movements(constraints.can_not_go_up, to_col, to_row);

        /* if there is not widgets overlapping in the new player position,
         * update the new placeholder position. */
        if (!$overlapped_widgets.length) {
            var pp = this.can_go_player_up(this.player_grid_data);
            if (pp !== false) {
                to_row = pp;
            }
            this.set_placeholder(to_col, to_row);
        }

        return {
            col: to_col,
            row: to_row
        };
    };


    /**
    * See which of the widgets in the $widgets param collection can go to
    * a upper row and which not.
    *
    * @method widgets_contraints
    * @param {jQuery} $widgets A jQuery wrapped collection of
    * HTMLElements.
    * @return {object} Returns a literal Object with two keys: `can_go_up` &
    * `can_not_go_up`. Each contains a set of HTMLElements.
    */
    fn.widgets_constraints = function($widgets) {
        var $widgets_can_go_up = $([]);
        var $widgets_can_not_go_up;
        var wgd_can_go_up = [];
        var wgd_can_not_go_up = [];

        $widgets.each($.proxy(function(i, w) {
            var $w = $(w);
            var wgd = $w.coords().grid;
            if (this.can_go_widget_up(wgd)) {
                $widgets_can_go_up = $widgets_can_go_up.add($w);
                wgd_can_go_up.push(wgd);
            } else {
                wgd_can_not_go_up.push(wgd);
            }
        }, this));

        $widgets_can_not_go_up = $widgets.not($widgets_can_go_up);

        return {
            can_go_up: Gridster.sort_by_row_asc(wgd_can_go_up),
            can_not_go_up: Gridster.sort_by_row_desc(wgd_can_not_go_up)
        };
    };


    /**
    * Sorts an Array of grid coords objects (representing the grid coords of
    * each widget) in descending way.
    *
    * @method manage_movements
    * @param {jQuery} $widgets A jQuery collection of HTMLElements
    *  representing the widgets you want to move.
    * @param {Number} to_col The column to which we want to move the widgets.
    * @param {Number} to_row The row to which we want to move the widgets.
    * @return {Class} Returns the instance of the Gridster Class.
    */
    fn.manage_movements = function($widgets, to_col, to_row) {
        $.each($widgets, $.proxy(function(i, w) {
            var wgd = w;
            var $w = wgd.el;

            var can_go_widget_up = this.can_go_widget_up(wgd);

            if (can_go_widget_up) {
                //target CAN go up
                //so move widget up
                this.move_widget_to($w, can_go_widget_up);
                this.set_placeholder(to_col, can_go_widget_up + wgd.size_y);

            } else {
                //target can't go up
                var can_go_player_up = this.can_go_player_up(
                    this.player_grid_data);

                if (!can_go_player_up) {
                    // target can't go up
                    // player cant't go up
                    // so we need to move widget down to a position that dont
                    // overlaps player
                    var y = (to_row + this.player_grid_data.size_y) - wgd.row;

                    this.move_widget_down($w, y);
                    this.set_placeholder(to_col, to_row);
                }
            }
        }, this));

        return this;
    };

    /**
    * Determines if there is a widget in the row and col given. Or if the
    * HTMLElement passed as first argument is the player.
    *
    * @method is_player
    * @param {Number|HTMLElement} col_or_el A jQuery wrapped collection of
    * HTMLElements.
    * @param {Number} [row] The column to which we want to move the widgets.
    * @return {Boolean} Returns true or false.
    */
    fn.is_player = function(col_or_el, row) {
        if (row && !this.gridmap[col_or_el]) { return false; }
        var $w = row ? this.gridmap[col_or_el][row] : col_or_el;
        return $w && ($w.is(this.$player) || $w.is(this.$helper));
    };


    /**
    * Determines if the widget that is being dragged is currently over the row
    * and col given.
    *
    * @method is_player_in
    * @param {Number} col The column to check.
    * @param {Number} row The row to check.
    * @return {Boolean} Returns true or false.
    */
    fn.is_player_in = function(col, row) {
        var c = this.cells_occupied_by_player || {};
        return $.inArray(col, c.cols) >= 0 && $.inArray(row, c.rows) >= 0;
    };


    /**
    * Determines if the placeholder is currently over the row and col given.
    *
    * @method is_placeholder_in
    * @param {Number} col The column to check.
    * @param {Number} row The row to check.
    * @return {Boolean} Returns true or false.
    */
    fn.is_placeholder_in = function(col, row) {
        var c = this.cells_occupied_by_placeholder || {};
        return this.is_placeholder_in_col(col) && $.inArray(row, c.rows) >= 0;
    };


    /**
    * Determines if the placeholder is currently over the column given.
    *
    * @method is_placeholder_in_col
    * @param {Number} col The column to check.
    * @return {Boolean} Returns true or false.
    */
    fn.is_placeholder_in_col = function(col) {
        var c = this.cells_occupied_by_placeholder || [];
        return $.inArray(col, c.cols) >= 0;
    };


    /**
    * Determines if the cell represented by col and row params is empty.
    *
    * @method is_empty
    * @param {Number} col The column to check.
    * @param {Number} row The row to check.
    * @return {Boolean} Returns true or false.
    */
    fn.is_empty = function(col, row) {
        if (typeof this.gridmap[col] !== 'undefined') {
			if(typeof this.gridmap[col][row] !== 'undefined' &&
				 this.gridmap[col][row] === false
			) {
				return true;
			}
			return false;
		}
		return true;
    };


    /**
    * Determines if the cell represented by col and row params is occupied.
    *
    * @method is_occupied
    * @param {Number} col The column to check.
    * @param {Number} row The row to check.
    * @return {Boolean} Returns true or false.
    */
    fn.is_occupied = function(col, row) {
        if (!this.gridmap[col]) {
            return false;
        }

        if (this.gridmap[col][row]) {
            return true;
        }
        return false;
    };


    /**
    * Determines if there is a widget in the cell represented by col/row params.
    *
    * @method is_widget
    * @param {Number} col The column to check.
    * @param {Number} row The row to check.
    * @return {Boolean|HTMLElement} Returns false if there is no widget,
    * else returns the jQuery HTMLElement
    */
    fn.is_widget = function(col, row) {
        var cell = this.gridmap[col];
        if (!cell) {
            return false;
        }

        cell = cell[row];

        if (cell) {
            return cell;
        }

        return false;
    };


    /**
    * Determines if there is a widget in the cell represented by col/row
    * params and if this is under the widget that is being dragged.
    *
    * @method is_widget_under_player
    * @param {Number} col The column to check.
    * @param {Number} row The row to check.
    * @return {Boolean} Returns true or false.
    */
    fn.is_widget_under_player = function(col, row) {
        if (this.is_widget(col, row)) {
            return this.is_player_in(col, row);
        }
        return false;
    };


    /**
    * Get widgets overlapping with the player or with the object passed
    * representing the grid cells.
    *
    * @method get_widgets_under_player
    * @return {HTMLElement} Returns a jQuery collection of HTMLElements
    */
    fn.get_widgets_under_player = function(cells) {
        cells || (cells = this.cells_occupied_by_player || {cols: [], rows: []});
        var $widgets = $([]);

        $.each(cells.cols, $.proxy(function(i, col) {
            $.each(cells.rows, $.proxy(function(i, row) {
                if(this.is_widget(col, row)) {
                    $widgets = $widgets.add(this.gridmap[col][row]);
                }
            }, this));
        }, this));

        return $widgets;
    };


    /**
    * Put placeholder at the row and column specified.
    *
    * @method set_placeholder
    * @param {Number} col The column to which we want to move the
    *  placeholder.
    * @param {Number} row The row to which we want to move the
    *  placeholder.
    * @return {Class} Returns the instance of the Gridster Class.
    */
    fn.set_placeholder = function(col, row) {
        var phgd = $.extend({}, this.placeholder_grid_data);
        var $nexts = this.widgets_below({
                col: phgd.col,
                row: phgd.row,
                size_y: phgd.size_y,
                size_x: phgd.size_x
            });

        // Prevents widgets go out of the grid
        var right_col = (col + phgd.size_x - 1);
        if (right_col > this.cols) {
            col = col - (right_col - col);
        }

        var moved_down = this.placeholder_grid_data.row < row;
        var changed_column = this.placeholder_grid_data.col !== col;

        this.placeholder_grid_data.col = col;
        this.placeholder_grid_data.row = row;

        this.cells_occupied_by_placeholder = this.get_cells_occupied(
            this.placeholder_grid_data);

        this.$preview_holder.attr({
            'data-row' : row,
            'data-col' : col
        });

        if (moved_down || changed_column) {
            $nexts.each($.proxy(function(i, widget) {
                this.move_widget_up(
                 $(widget), this.placeholder_grid_data.col - col + phgd.size_y);
            }, this));
        }

        var $widgets_under_ph = this.get_widgets_under_player(
            this.cells_occupied_by_placeholder);

        if ($widgets_under_ph.length) {
            $widgets_under_ph.each($.proxy(function(i, widget) {
                var $w = $(widget);
                this.move_widget_down(
                 $w, row + phgd.size_y - $w.data('coords').grid.row);
            }, this));
        }

    };


    /**
    * Determines whether the player can move to a position above.
    *
    * @method can_go_player_up
    * @param {Object} widget_grid_data The actual grid coords object of the
    *  player.
    * @return {Number|Boolean} If the player can be moved to an upper row
    *  returns the row number, else returns false.
    */
    fn.can_go_player_up = function(widget_grid_data) {
        var p_bottom_row = widget_grid_data.row + widget_grid_data.size_y - 1;
        var result = true;
        var upper_rows = [];
        var min_row = 10000;
        var $widgets_under_player = this.get_widgets_under_player();

        /* generate an array with columns as index and array with upper rows
         * empty as value */
        this.for_each_column_occupied(widget_grid_data, function(tcol) {
            var grid_col = this.gridmap[tcol];
            var r = p_bottom_row + 1;
            upper_rows[tcol] = [];

            while (--r > 0) {
                if (this.is_empty(tcol, r) || this.is_player(tcol, r) ||
                    this.is_widget(tcol, r) &&
                    grid_col[r].is($widgets_under_player)
                ) {
                    upper_rows[tcol].push(r);
                    min_row = r < min_row ? r : min_row;
                } else {
                    break;
                }
            }

            if (upper_rows[tcol].length === 0) {
                result = false;
                return true; //break
            }

            upper_rows[tcol].sort(function(a, b) {
                return a - b;
            });
        });

        if (!result) { return false; }

        return this.get_valid_rows(widget_grid_data, upper_rows, min_row);
    };


    /**
    * Determines whether a widget can move to a position above.
    *
    * @method can_go_widget_up
    * @param {Object} widget_grid_data The actual grid coords object of the
    *  widget we want to check.
    * @return {Number|Boolean} If the widget can be moved to an upper row
    *  returns the row number, else returns false.
    */
    fn.can_go_widget_up = function(widget_grid_data) {
        var p_bottom_row = widget_grid_data.row + widget_grid_data.size_y - 1;
        var result = true;
        var upper_rows = [];
        var min_row = 10000;

        /* generate an array with columns as index and array with topmost rows
         * empty as value */
        this.for_each_column_occupied(widget_grid_data, function(tcol) {
            var grid_col = this.gridmap[tcol];
            upper_rows[tcol] = [];

            var r = p_bottom_row + 1;
            // iterate over each row
            while (--r > 0) {
                if (this.is_widget(tcol, r) && !this.is_player_in(tcol, r)) {
                    if (!grid_col[r].is(widget_grid_data.el)) {
                        break;
                    }
                }

                if (!this.is_player(tcol, r) &&
                    !this.is_placeholder_in(tcol, r) &&
                    !this.is_player_in(tcol, r)) {
                    upper_rows[tcol].push(r);
                }

                if (r < min_row) {
                    min_row = r;
                }
            }

            if (upper_rows[tcol].length === 0) {
                result = false;
                return true; //break
            }

            upper_rows[tcol].sort(function(a, b) {
                return a - b;
            });
        });

        if (!result) { return false; }

        return this.get_valid_rows(widget_grid_data, upper_rows, min_row);
    };


    /**
    * Search a valid row for the widget represented by `widget_grid_data' in
    * the `upper_rows` array. Iteration starts from row specified in `min_row`.
    *
    * @method get_valid_rows
    * @param {Object} widget_grid_data The actual grid coords object of the
    *  player.
    * @param {Array} upper_rows An array with columns as index and arrays
    *  of valid rows as values.
    * @param {Number} min_row The upper row from which the iteration will start.
    * @return {Number|Boolean} Returns the upper row valid from the `upper_rows`
    *  for the widget in question.
    */
    fn.get_valid_rows = function(widget_grid_data, upper_rows, min_row) {
        var p_top_row = widget_grid_data.row;
        var p_bottom_row = widget_grid_data.row + widget_grid_data.size_y - 1;
        var size_y = widget_grid_data.size_y;
        var r = min_row - 1;
        var valid_rows = [];

        while (++r <= p_bottom_row ) {
            var common = true;
            $.each(upper_rows, function(col, rows) {
                if ($.isArray(rows) && $.inArray(r, rows) === -1) {
                    common = false;
                }
            });

            if (common === true) {
                valid_rows.push(r);
                if (valid_rows.length === size_y) {
                    break;
                }
            }
        }

        var new_row = false;
        if (size_y === 1) {
            if (valid_rows[0] !== p_top_row) {
                new_row = valid_rows[0] || false;
            }
        } else {
            if (valid_rows[0] !== p_top_row) {
                new_row = this.get_consecutive_numbers_index(
                    valid_rows, size_y);
            }
        }

        return new_row;
    };


    fn.get_consecutive_numbers_index = function(arr, size_y) {
        var max = arr.length;
        var result = [];
        var first = true;
        var prev = -1; // or null?

        for (var i=0; i < max; i++) {
            if (first || arr[i] === prev + 1) {
                result.push(i);
                if (result.length === size_y) {
                    break;
                }
                first = false;
            } else {
                result = [];
                first = true;
            }

            prev = arr[i];
        }

        return result.length >= size_y ? arr[result[0]] : false;
    };


    /**
    * Get widgets overlapping with the player.
    *
    * @method get_widgets_overlapped
    * @return {jQuery} Returns a jQuery collection of HTMLElements.
    */
    fn.get_widgets_overlapped = function() {
        var $w;
        var $widgets = $([]);
        var used = [];
        var rows_from_bottom = this.cells_occupied_by_player.rows.slice(0);
        rows_from_bottom.reverse();

        $.each(this.cells_occupied_by_player.cols, $.proxy(function(i, col) {
            $.each(rows_from_bottom, $.proxy(function(i, row) {
                // if there is a widget in the player position
                if (!this.gridmap[col]) { return true; } //next iteration
                var $w = this.gridmap[col][row];
                if (this.is_occupied(col, row) && !this.is_player($w) &&
                    $.inArray($w, used) === -1
                ) {
                    $widgets = $widgets.add($w);
                    used.push($w);
                }

            }, this));
        }, this));

        return $widgets;
    };


    /**
    * This callback is executed when the player begins to collide with a column.
    *
    * @method on_start_overlapping_column
    * @param {Number} col The collided column.
    * @return {jQuery} Returns a jQuery collection of HTMLElements.
    */
    fn.on_start_overlapping_column = function(col) {
        this.set_player(col, false);
    };


    /**
    * A callback executed when the player begins to collide with a row.
    *
    * @method on_start_overlapping_row
    * @param {Number} row The collided row.
    * @return {jQuery} Returns a jQuery collection of HTMLElements.
    */
    fn.on_start_overlapping_row = function(row) {
        this.set_player(false, row);
    };


    /**
    * A callback executed when the the player ends to collide with a column.
    *
    * @method on_stop_overlapping_column
    * @param {Number} col The collided row.
    * @return {jQuery} Returns a jQuery collection of HTMLElements.
    */
    fn.on_stop_overlapping_column = function(col) {
        this.set_player(col, false);

        var self = this;
        this.for_each_widget_below(col, this.cells_occupied_by_player.rows[0],
            function(tcol, trow) {
                self.move_widget_up(this, self.player_grid_data.size_y);
        });
    };


    /**
    * This callback is executed when the player ends to collide with a row.
    *
    * @method on_stop_overlapping_row
    * @param {Number} row The collided row.
    * @return {jQuery} Returns a jQuery collection of HTMLElements.
    */
    fn.on_stop_overlapping_row = function(row) {
        this.set_player(false, row);

        var self = this;
        var cols = this.cells_occupied_by_player.cols;
        for (var c = 0, cl = cols.length; c < cl; c++) {
            this.for_each_widget_below(cols[c], row, function(tcol, trow) {
                self.move_widget_up(this, self.player_grid_data.size_y);
            });
        }
    };


    /**
    * Move a widget to a specific row. The cell or cells must be empty.
    * If the widget has widgets below, all of these widgets will be moved also
    * if they can.
    *
    * @method move_widget_to
    * @param {HTMLElement} $widget The jQuery wrapped HTMLElement of the
    * widget is going to be moved.
    * @return {Class} Returns the instance of the Gridster Class.
    */
    fn.move_widget_to = function($widget, row) {
        var self = this;
        var widget_grid_data = $widget.coords().grid;
        var diff = row - widget_grid_data.row;
        var $next_widgets = this.widgets_below($widget);

        var can_move_to_new_cell = this.can_move_to(
            widget_grid_data, widget_grid_data.col, row, $widget);

        if (can_move_to_new_cell === false) {
            return false;
        }

        this.remove_from_gridmap(widget_grid_data);
        widget_grid_data.row = row;
        this.add_to_gridmap(widget_grid_data);
        $widget.attr('data-row', row);
        this.$changed = this.$changed.add($widget);


        $next_widgets.each(function(i, widget) {
            var $w = $(widget);
            var wgd = $w.coords().grid;
            var can_go_up = self.can_go_widget_up(wgd);
            if (can_go_up && can_go_up !== wgd.row) {
                self.move_widget_to($w, can_go_up);
            }
        });

        return this;
    };


    /**
    * Move up the specified widget and all below it.
    *
    * @method move_widget_up
    * @param {HTMLElement} $widget The widget you want to move.
    * @param {Number} [y_units] The number of cells that the widget has to move.
    * @return {Class} Returns the instance of the Gridster Class.
    */
    fn.move_widget_up = function($widget, y_units) {
        var el_grid_data = $widget.coords().grid;
        var actual_row = el_grid_data.row;
        var moved = [];
        var can_go_up = true;
        y_units || (y_units = 1);

        if (!this.can_go_up($widget)) { return false; } //break;

        this.for_each_column_occupied(el_grid_data, function(col) {
            // can_go_up
            if ($.inArray($widget, moved) === -1) {
                var widget_grid_data = $widget.coords().grid;
                var next_row = actual_row - y_units;
                next_row = this.can_go_up_to_row(
                    widget_grid_data, col, next_row);

                if (!next_row) {
                    return true;
                }

                var $next_widgets = this.widgets_below($widget);

                this.remove_from_gridmap(widget_grid_data);
                widget_grid_data.row = next_row;
                this.add_to_gridmap(widget_grid_data);
                $widget.attr('data-row', widget_grid_data.row);
                this.$changed = this.$changed.add($widget);

                moved.push($widget);

                $next_widgets.each($.proxy(function(i, widget) {
                    this.move_widget_up($(widget), y_units);
                }, this));
            }
        });

    };


    /**
    * Move down the specified widget and all below it.
    *
    * @method move_widget_down
    * @param {jQuery} $widget The jQuery object representing the widget
    *  you want to move.
    * @param {Number} y_units The number of cells that the widget has to move.
    * @return {Class} Returns the instance of the Gridster Class.
    */
    fn.move_widget_down = function($widget, y_units) {
        var el_grid_data, actual_row, moved, y_diff;

        if (y_units <= 0) { return false; }

        el_grid_data = $widget.coords().grid;
        actual_row = el_grid_data.row;
        moved = [];
        y_diff = y_units;

        if (!$widget) { return false; }

        if ($.inArray($widget, moved) === -1) {

            var widget_grid_data = $widget.coords().grid;
            var next_row = actual_row + y_units;
            var $next_widgets = this.widgets_below($widget);

            this.remove_from_gridmap(widget_grid_data);

            $next_widgets.each($.proxy(function(i, widget) {
                var $w = $(widget);
                var wd = $w.coords().grid;
                var tmp_y = this.displacement_diff(
                             wd, widget_grid_data, y_diff);

                if (tmp_y > 0) {
                    this.move_widget_down($w, tmp_y);
                }
            }, this));

            widget_grid_data.row = next_row;
            this.update_widget_position(widget_grid_data, $widget);
            $widget.attr('data-row', widget_grid_data.row);
            this.$changed = this.$changed.add($widget);

            moved.push($widget);
        }
    };


    /**
    * Check if the widget can move to the specified row, else returns the
    * upper row possible.
    *
    * @method can_go_up_to_row
    * @param {Number} widget_grid_data The current grid coords object of the
    *  widget.
    * @param {Number} col The target column.
    * @param {Number} row The target row.
    * @return {Boolean|Number} Returns the row number if the widget can move
    *  to the target position, else returns false.
    */
    fn.can_go_up_to_row = function(widget_grid_data, col, row) {
        var ga = this.gridmap;
        var result = true;
        var urc = []; // upper_rows_in_columns
        var actual_row = widget_grid_data.row;
        var r;

        /* generate an array with columns as index and array with
         * upper rows empty in the column */
        this.for_each_column_occupied(widget_grid_data, function(tcol) {
            var grid_col = ga[tcol];
            urc[tcol] = [];

            r = actual_row;
            while (r--) {
                if (this.is_empty(tcol, r) &&
                    !this.is_placeholder_in(tcol, r)
                ) {
                    urc[tcol].push(r);
                } else {
                    break;
                }
            }

            if (!urc[tcol].length) {
                result = false;
                return true;
            }

        });

        if (!result) { return false; }

        /* get common rows starting from upper position in all the columns
         * that widget occupies */
        r = row;
        for (r = 1; r < actual_row; r++) {
            var common = true;

            for (var uc = 0, ucl = urc.length; uc < ucl; uc++) {
                if (urc[uc] && $.inArray(r, urc[uc]) === -1) {
                    common = false;
                }
            }

            if (common === true) {
                result = r;
                break;
            }
        }

        return result;
    };


    fn.displacement_diff = function(widget_grid_data, parent_bgd, y_units) {
        var actual_row = widget_grid_data.row;
        var diffs = [];
        var parent_max_y = parent_bgd.row + parent_bgd.size_y;

        this.for_each_column_occupied(widget_grid_data, function(col) {
            var temp_y_units = 0;

            for (var r = parent_max_y; r < actual_row; r++) {
                if (this.is_empty(col, r)) {
                    temp_y_units = temp_y_units + 1;
                }
            }

            diffs.push(temp_y_units);
        });

        var max_diff = Math.max.apply(Math, diffs);
        y_units = (y_units - max_diff);

        return y_units > 0 ? y_units : 0;
    };


    /**
    * Get widgets below a widget.
    *
    * @method widgets_below
    * @param {HTMLElement} $el The jQuery wrapped HTMLElement.
    * @return {jQuery} A jQuery collection of HTMLElements.
    */
    fn.widgets_below = function($el) {
        var el_grid_data = $.isPlainObject($el) ? $el : $el.coords().grid;
        var self = this;
        var ga = this.gridmap;
        var next_row = el_grid_data.row + el_grid_data.size_y - 1;
        var $nexts = $([]);

        this.for_each_column_occupied(el_grid_data, function(col) {
            self.for_each_widget_below(col, next_row, function(tcol, trow) {
                if (!self.is_player(this) && $.inArray(this, $nexts) === -1) {
                    $nexts = $nexts.add(this);
                    return true; // break
                }
            });
        });

        return Gridster.sort_by_row_asc($nexts);
    };


    /**
    * Update the array of mapped positions with the new player position.
    *
    * @method set_cells_player_occupies
    * @param {Number} col The new player col.
    * @param {Number} col The new player row.
    * @return {Class} Returns the instance of the Gridster Class.
    */
    fn.set_cells_player_occupies = function(col, row) {
        this.remove_from_gridmap(this.placeholder_grid_data);
        this.placeholder_grid_data.col = col;
        this.placeholder_grid_data.row = row;
        this.add_to_gridmap(this.placeholder_grid_data, this.$player);
        return this;
    };


    /**
    * Remove from the array of mapped positions the reference to the player.
    *
    * @method empty_cells_player_occupies
    * @return {Class} Returns the instance of the Gridster Class.
    */
    fn.empty_cells_player_occupies = function() {
        this.remove_from_gridmap(this.placeholder_grid_data);
        return this;
    };


    fn.can_go_up = function($el) {
        var el_grid_data = $el.coords().grid;
        var initial_row = el_grid_data.row;
        var prev_row = initial_row - 1;
        var ga = this.gridmap;
        var upper_rows_by_column = [];

        var result = true;
        if (initial_row === 1) { return false; }

        this.for_each_column_occupied(el_grid_data, function(col) {
            var $w = this.is_widget(col, prev_row);

            if (this.is_occupied(col, prev_row) ||
                this.is_player(col, prev_row) ||
                this.is_placeholder_in(col, prev_row) ||
                this.is_player_in(col, prev_row)
            ) {
                result = false;
                return true; //break
            }
        });

        return result;
    };


    /**
    * Check if it's possible to move a widget to a specific col/row. It takes
    * into account the dimensions (`size_y` and `size_x` attrs. of the grid
    *  coords object) the widget occupies.
    *
    * @method can_move_to
    * @param {Object} widget_grid_data The grid coords object that represents
    *  the widget.
    * @param {Object} col The col to check.
    * @param {Object} row The row to check.
    * @param {Number} [max_row] The max row allowed.
    * @return {Boolean} Returns true if all cells are empty, else return false.
    */
    fn.can_move_to = function(widget_grid_data, col, row, max_row) {
        var ga = this.gridmap;
        var $w = widget_grid_data.el;
        var future_wd = {
            size_y: widget_grid_data.size_y,
            size_x: widget_grid_data.size_x,
            col: col,
            row: row
        };
        var result = true;

        //Prevents widgets go out of the grid
        var right_col = col + widget_grid_data.size_x - 1;
        if (right_col > this.cols) {
            return false;
        }

        if (max_row && max_row < row + widget_grid_data.size_y - 1) {
            return false;
        }

        this.for_each_cell_occupied(future_wd, function(tcol, trow) {
            var $tw = this.is_widget(tcol, trow);
            if ($tw && (!widget_grid_data.el || $tw.is($w))) {
                result = false;
            }
        });

        return result;
    };


    /**
    * Given the leftmost column returns all columns that are overlapping
    *  with the player.
    *
    * @method get_targeted_columns
    * @param {Number} [from_col] The leftmost column.
    * @return {Array} Returns an array with column numbers.
    */
    fn.get_targeted_columns = function(from_col) {
        var max = (from_col || this.player_grid_data.col) +
            (this.player_grid_data.size_x - 1);
        var cols = [];
        for (var col = from_col; col <= max; col++) {
            cols.push(col);
        }
        return cols;
    };


    /**
    * Given the upper row returns all rows that are overlapping with the player.
    *
    * @method get_targeted_rows
    * @param {Number} [from_row] The upper row.
    * @return {Array} Returns an array with row numbers.
    */
    fn.get_targeted_rows = function(from_row) {
        var max = (from_row || this.player_grid_data.row) +
            (this.player_grid_data.size_y - 1);
        var rows = [];
        for (var row = from_row; row <= max; row++) {
            rows.push(row);
        }
        return rows;
    };

    /**
    * Get all columns and rows that a widget occupies.
    *
    * @method get_cells_occupied
    * @param {Object} el_grid_data The grid coords object of the widget.
    * @return {Object} Returns an object like `{ cols: [], rows: []}`.
    */
    fn.get_cells_occupied = function(el_grid_data) {
        var cells = { cols: [], rows: []};
        var i;
        if (arguments[1] instanceof $) {
            el_grid_data = arguments[1].coords().grid;
        }

        for (i = 0; i < el_grid_data.size_x; i++) {
            var col = el_grid_data.col + i;
            cells.cols.push(col);
        }

        for (i = 0; i < el_grid_data.size_y; i++) {
            var row = el_grid_data.row + i;
            cells.rows.push(row);
        }

        return cells;
    };


    /**
    * Iterate over the cells occupied by a widget executing a function for
    * each one.
    *
    * @method for_each_cell_occupied
    * @param {Object} el_grid_data The grid coords object that represents the
    *  widget.
    * @param {Function} callback The function to execute on each column
    *  iteration. Column and row are passed as arguments.
    * @return {Class} Returns the instance of the Gridster Class.
    */
    fn.for_each_cell_occupied = function(grid_data, callback) {
        this.for_each_column_occupied(grid_data, function(col) {
            this.for_each_row_occupied(grid_data, function(row) {
                callback.call(this, col, row);
            });
        });
        return this;
    };


    /**
    * Iterate over the columns occupied by a widget executing a function for
    * each one.
    *
    * @method for_each_column_occupied
    * @param {Object} el_grid_data The grid coords object that represents
    *  the widget.
    * @param {Function} callback The function to execute on each column
    *  iteration. The column number is passed as first argument.
    * @return {Class} Returns the instance of the Gridster Class.
    */
    fn.for_each_column_occupied = function(el_grid_data, callback) {
        for (var i = 0; i < el_grid_data.size_x; i++) {
            var col = el_grid_data.col + i;
            callback.call(this, col, el_grid_data);
        }
    };


    /**
    * Iterate over the rows occupied by a widget executing a function for
    * each one.
    *
    * @method for_each_row_occupied
    * @param {Object} el_grid_data The grid coords object that represents
    *  the widget.
    * @param {Function} callback The function to execute on each column
    *  iteration. The row number is passed as first argument.
    * @return {Class} Returns the instance of the Gridster Class.
    */
    fn.for_each_row_occupied = function(el_grid_data, callback) {
        for (var i = 0; i < el_grid_data.size_y; i++) {
            var row = el_grid_data.row + i;
            callback.call(this, row, el_grid_data);
        }
    };



    fn._traversing_widgets = function(type, direction, col, row, callback) {
        var ga = this.gridmap;
        if (!ga[col]) { return; }

        var cr, max;
        var action = type + '/' + direction;
        if (arguments[2] instanceof $) {
            var el_grid_data = arguments[2].coords().grid;
            col = el_grid_data.col;
            row = el_grid_data.row;
            callback = arguments[3];
        }
        var matched = [];
        var trow = row;


        var methods = {
            'for_each/above': function() {
                while (trow--) {
                    if (trow > 0 && this.is_widget(col, trow) &&
                        $.inArray(ga[col][trow], matched) === -1
                    ) {
                        cr = callback.call(ga[col][trow], col, trow);
                        matched.push(ga[col][trow]);
                        if (cr) { break; }
                    }
                }
            },
            'for_each/below': function() {
                for (trow = row + 1, max = ga[col].length; trow < max; trow++) {
                    if (this.is_widget(col, trow) &&
                        $.inArray(ga[col][trow], matched) === -1
                    ) {
                        cr = callback.call(ga[col][trow], col, trow);
                        matched.push(ga[col][trow]);
                        if (cr) { break; }
                    }
                }
            }
        };

        if (methods[action]) {
            methods[action].call(this);
        }
    };


    /**
    * Iterate over each widget above the column and row specified.
    *
    * @method for_each_widget_above
    * @param {Number} col The column to start iterating.
    * @param {Number} row The row to start iterating.
    * @param {Function} callback The function to execute on each widget
    *  iteration. The value of `this` inside the function is the jQuery
    *  wrapped HTMLElement.
    * @return {Class} Returns the instance of the Gridster Class.
    */
    fn.for_each_widget_above = function(col, row, callback) {
        this._traversing_widgets('for_each', 'above', col, row, callback);
        return this;
    };


    /**
    * Iterate over each widget below the column and row specified.
    *
    * @method for_each_widget_below
    * @param {Number} col The column to start iterating.
    * @param {Number} row The row to start iterating.
    * @param {Function} callback The function to execute on each widget
    *  iteration. The value of `this` inside the function is the jQuery wrapped
    *  HTMLElement.
    * @return {Class} Returns the instance of the Gridster Class.
    */
    fn.for_each_widget_below = function(col, row, callback) {
        this._traversing_widgets('for_each', 'below', col, row, callback);
        return this;
    };


    /**
    * Returns the highest occupied cell in the grid.
    *
    * @method get_highest_occupied_cell
    * @return {Object} Returns an object with `col` and `row` numbers.
    */
    fn.get_highest_occupied_cell = function() {
        var r;
        var gm = this.gridmap;
        var rl = gm[1].length;
        var rows = [], cols = [];
        var row_in_col = [];
        for (var c = gm.length - 1; c >= 1; c--) {
            for (r = rl - 1; r >= 1; r--) {
                if (this.is_widget(c, r)) {
                    rows.push(r);
                    cols.push(c);
                    break;
                }
            }
        }

        return {
            col: Math.max.apply(Math, cols),
            row: Math.max.apply(Math, rows)
        };
    };


    fn.get_widgets_from = function(col, row) {
        var ga = this.gridmap;
        var $widgets = $();

        if (col) {
            $widgets = $widgets.add(
                this.$widgets.filter(function() {
                    var tcol = $(this).attr('data-col');
                    return (tcol === col || tcol > col);
                })
            );
        }

        if (row) {
            $widgets = $widgets.add(
                this.$widgets.filter(function() {
                    var trow = $(this).attr('data-row');
                    return (trow === row || trow > row);
                })
            );
        }

        return $widgets;
    };


    /**
    * Set the current height of the parent grid.
    *
    * @method set_dom_grid_height
    * @return {Object} Returns the instance of the Gridster class.
    */
    fn.set_dom_grid_height = function(height) {
        if (typeof height === 'undefined') {
            var r = this.get_highest_occupied_cell().row;
            height = r * this.min_widget_height;
        }

        this.container_height = height;
        this.$el.css('height', this.container_height);
        return this;
    };

    /**
    * Set the current width of the parent grid.
    *
    * @method set_dom_grid_width
    * @return {Object} Returns the instance of the Gridster class.
    */
    fn.set_dom_grid_width = function(cols) {
        if (typeof cols === 'undefined') {
            cols = this.get_highest_occupied_cell().col;
        }

        var max_cols = (this.options.autogrow_cols ? this.options.max_cols :
            this.cols);

        cols = Math.min(max_cols, Math.max(cols, this.options.min_cols));
        this.container_width = cols * this.min_widget_width;
        this.$el.css('width', this.container_width);
        return this;
    };


    /**
    * It generates the neccessary styles to position the widgets.
    *
    * @method generate_stylesheet
    * @param {Number} rows Number of columns.
    * @param {Number} cols Number of rows.
    * @return {Object} Returns the instance of the Gridster class.
    */
    fn.generate_stylesheet = function(opts) {
        var styles = '';
        var max_size_x = this.options.max_size_x || this.cols;
        var max_rows = 0;
        var max_cols = 0;
        var i;
        var rules;

        opts || (opts = {});
        opts.cols || (opts.cols = this.cols);
        opts.rows || (opts.rows = this.rows);
        opts.namespace || (opts.namespace = this.options.namespace);
        opts.widget_base_dimensions ||
            (opts.widget_base_dimensions = this.options.widget_base_dimensions);
        opts.widget_margins ||
            (opts.widget_margins = this.options.widget_margins);
        opts.min_widget_width = (opts.widget_margins[0] * 2) +
            opts.widget_base_dimensions[0];
        opts.min_widget_height = (opts.widget_margins[1] * 2) +
            opts.widget_base_dimensions[1];

        // don't duplicate stylesheets for the same configuration
        var serialized_opts = $.param(opts);
        if ($.inArray(serialized_opts, Gridster.generated_stylesheets) >= 0) {
            return false;
        }

        this.generated_stylesheets.push(serialized_opts);
        Gridster.generated_stylesheets.push(serialized_opts);

        /* generate CSS styles for cols */
        for (i = opts.cols; i >= 0; i--) {
            styles += (opts.namespace + ' [data-col="'+ (i + 1) + '"] { left:' +
                ((i * opts.widget_base_dimensions[0]) +
                (i * opts.widget_margins[0]) +
                ((i + 1) * opts.widget_margins[0])) + 'px; }\n');
        }

        /* generate CSS styles for rows */
        for (i = opts.rows; i >= 0; i--) {
            styles += (opts.namespace + ' [data-row="' + (i + 1) + '"] { top:' +
                ((i * opts.widget_base_dimensions[1]) +
                (i * opts.widget_margins[1]) +
                ((i + 1) * opts.widget_margins[1]) ) + 'px; }\n');
        }

        for (var y = 1; y <= opts.rows; y++) {
            styles += (opts.namespace + ' [data-sizey="' + y + '"] { height:' +
                (y * opts.widget_base_dimensions[1] +
                (y - 1) * (opts.widget_margins[1] * 2)) + 'px; }\n');
        }

        for (var x = 1; x <= max_size_x; x++) {
            styles += (opts.namespace + ' [data-sizex="' + x + '"] { width:' +
                (x * opts.widget_base_dimensions[0] +
                (x - 1) * (opts.widget_margins[0] * 2)) + 'px; }\n');
        }

        this.remove_style_tags();

        return this.add_style_tag(styles);
    };


    /**
    * Injects the given CSS as string to the head of the document.
    *
    * @method add_style_tag
    * @param {String} css The styles to apply.
    * @return {Object} Returns the instance of the Gridster class.
    */
    fn.add_style_tag = function(css) {
        var d = document;
        var tag = d.createElement('style');

        d.getElementsByTagName('head')[0].appendChild(tag);
        tag.setAttribute('type', 'text/css');

        if (tag.styleSheet) {
            tag.styleSheet.cssText = css;
        } else {
            tag.appendChild(document.createTextNode(css));
        }

        this.$style_tags = this.$style_tags.add(tag);

        return this;
    };


    /**
    * Remove the style tag with the associated id from the head of the document
    *
    * @method  remove_style_tag
    * @return {Object} Returns the instance of the Gridster class.
    */
    fn.remove_style_tags = function() {
        var all_styles = Gridster.generated_stylesheets;
        var ins_styles = this.generated_stylesheets;

        this.$style_tags.remove();

        Gridster.generated_stylesheets = $.map(all_styles, function(s) {
            if ($.inArray(s, ins_styles) === -1) { return s; }
        });
    };


    /**
    * Generates a faux grid to collide with it when a widget is dragged and
    * detect row or column that we want to go.
    *
    * @method generate_faux_grid
    * @param {Number} rows Number of columns.
    * @param {Number} cols Number of rows.
    * @return {Object} Returns the instance of the Gridster class.
    */
    fn.generate_faux_grid = function(rows, cols) {
        this.faux_grid = [];
        this.gridmap = [];
        var col;
        var row;
        for (col = cols; col > 0; col--) {
            this.gridmap[col] = [];
            for (row = rows; row > 0; row--) {
                this.add_faux_cell(row, col);
            }
        }
        return this;
    };


    /**
    * Add cell to the faux grid.
    *
    * @method add_faux_cell
    * @param {Number} row The row for the new faux cell.
    * @param {Number} col The col for the new faux cell.
    * @return {Object} Returns the instance of the Gridster class.
    */
    fn.add_faux_cell = function(row, col) {
        var coords = $({
                        left: this.baseX + ((col - 1) * this.min_widget_width),
                        top: this.baseY + (row -1) * this.min_widget_height,
                        width: this.min_widget_width,
                        height: this.min_widget_height,
                        col: col,
                        row: row,
                        original_col: col,
                        original_row: row
                    }).coords();

        if (!$.isArray(this.gridmap[col])) {
            this.gridmap[col] = [];
        }

        this.gridmap[col][row] = false;
        this.faux_grid.push(coords);

        return this;
    };


    /**
    * Add rows to the faux grid.
    *
    * @method add_faux_rows
    * @param {Number} rows The number of rows you want to add to the faux grid.
    * @return {Object} Returns the instance of the Gridster class.
    */
    fn.add_faux_rows = function(rows) {
        var actual_rows = this.rows;
        var max_rows = actual_rows + (rows || 1);

        for (var r = max_rows; r > actual_rows; r--) {
            for (var c = this.cols; c >= 1; c--) {
                this.add_faux_cell(r, c);
            }
        }

        this.rows = max_rows;

        if (this.options.autogenerate_stylesheet) {
            this.generate_stylesheet();
        }

        return this;
    };

     /**
    * Add cols to the faux grid.
    *
    * @method add_faux_cols
    * @param {Number} cols The number of cols you want to add to the faux grid.
    * @return {Object} Returns the instance of the Gridster class.
    */
    fn.add_faux_cols = function(cols) {
        var actual_cols = this.cols;
        var max_cols = actual_cols + (cols || 1);
        max_cols = Math.min(max_cols, this.options.max_cols);

        for (var c = actual_cols + 1; c <= max_cols; c++) {
            for (var r = this.rows; r >= 1; r--) {
                this.add_faux_cell(r, c);
            }
        }

        this.cols = max_cols;

        if (this.options.autogenerate_stylesheet) {
            this.generate_stylesheet();
        }

        return this;
    };


    /**
    * Recalculates the offsets for the faux grid. You need to use it when
    * the browser is resized.
    *
    * @method recalculate_faux_grid
    * @return {Object} Returns the instance of the Gridster class.
    */
    fn.recalculate_faux_grid = function() {
        var aw = this.$wrapper.width();
        this.baseX = ($(window).width() - aw) / 2;
        this.baseY = this.$wrapper.offset().top;

        $.each(this.faux_grid, $.proxy(function(i, coords) {
            this.faux_grid[i] = coords.update({
                left: this.baseX + (coords.data.col -1) * this.min_widget_width,
                top: this.baseY + (coords.data.row -1) * this.min_widget_height
            });
        }, this));

        return this;
    };


    /**
    * Get all widgets in the DOM and register them.
    *
    * @method get_widgets_from_DOM
    * @return {Object} Returns the instance of the Gridster class.
    */
    fn.get_widgets_from_DOM = function() {
        var widgets_coords = this.$widgets.map($.proxy(function(i, widget) {
            var $w = $(widget);
            return this.dom_to_coords($w);
        }, this));

        widgets_coords = Gridster.sort_by_row_and_col_asc(widgets_coords);

        var changes = $(widgets_coords).map($.proxy(function(i, wgd) {
            return this.register_widget(wgd) || null;
        }, this));

        if (changes.length) {
            this.$el.trigger('gridster:positionschanged');
        }

        return this;
    };


    /**
    * Calculate columns and rows to be set based on the configuration
    *  parameters, grid dimensions, etc ...
    *
    * @method generate_grid_and_stylesheet
    * @return {Object} Returns the instance of the Gridster class.
    */
    fn.generate_grid_and_stylesheet = function() {
        var aw = this.$wrapper.width();
        var max_cols = this.options.max_cols;

        var cols = Math.floor(aw / this.min_widget_width) +
                   this.options.extra_cols;

        var actual_cols = this.$widgets.map(function() {
            return $(this).attr('data-col');
        }).get();

        //needed to pass tests with phantomjs
        actual_cols.length || (actual_cols = [0]);

        var min_cols = Math.max.apply(Math, actual_cols);

        this.cols = Math.max(min_cols, cols, this.options.min_cols);

        if (max_cols !== Infinity && max_cols >= min_cols && max_cols < this.cols) {
            this.cols = max_cols;
        }

        // get all rows that could be occupied by the current widgets
        var max_rows = this.options.extra_rows;
        this.$widgets.each(function(i, w) {
            max_rows += (+$(w).attr('data-sizey'));
        });

        this.rows = Math.max(max_rows, this.options.min_rows);

        this.baseX = ($(window).width() - aw) / 2;
        this.baseY = this.$wrapper.offset().top;

        if (this.options.autogenerate_stylesheet) {
            this.generate_stylesheet();
        }

        return this.generate_faux_grid(this.rows, this.cols);
    };

    /**
     * Destroy this gridster by removing any sign of its presence, making it easy to avoid memory leaks
     *
     * @method destroy
     * @param {Boolean} remove If true, remove gridster from DOM.
     * @return {Object} Returns the instance of the Gridster class.
     */
    fn.destroy = function(remove) {
        this.$el.removeData('gridster');

        // remove bound callback on window resize
        $(window).unbind('.gridster');

        if (this.drag_api) {
            this.drag_api.destroy();
        }

        this.remove_style_tags();

        remove && this.$el.remove();

        return this;
    };


    //jQuery adapter
    $.fn.gridster = function(options) {
        return this.each(function() {
            if (! $(this).data('gridster')) {
                $(this).data('gridster', new Gridster( this, options ));
            }
        });
    };

    return Gridster;

}));
;
window.UNGM = window.UNGM || {};
window.UNGM.ManageGridster = {
    margin: 5,
    columnCount: null,
    cellWidth: null,
    cellHeight: null,
    isGridsterUsed: null,
    isPrintPage: null,
    gridster: null,
    searchResultsTableMaxHeight: 400,
    setGridParameters: function (columnCount, defaultGridWidth) {
        UNGM.ManageGridster.isGridsterUsed = $(".gridster").length;
        UNGM.ManageGridster.isPrintPage = $(".kc-print-page").length;
        if (UNGM.ManageGridster.isGridsterUsed) {
            UNGM.ManageGridster.columnCount = columnCount;
            var gridWidth = $(".gridster").width();
            if (defaultGridWidth != undefined) {
                gridWidth = defaultGridWidth;
            }

            UNGM.ManageGridster.cellWidth = (gridWidth - 2 * UNGM.ManageGridster.margin * columnCount) / columnCount;
            UNGM.ManageGridster.cellHeight = UNGM.ManageGridster.cellWidth / 2;
        }
    },
    initGridsterForNonKCAdmin: function () {
        UNGM.ManageGridster.gridster = $(".gridster > ul").gridster({
            widget_margins: [UNGM.ManageGridster.margin, UNGM.ManageGridster.margin],
            widget_base_dimensions: [UNGM.ManageGridster.cellWidth, UNGM.ManageGridster.cellHeight],
            resize: {
                enabled: false
            },
            avoid_overlapped_widgets: true,
            min_cols: UNGM.ManageGridster.columnCount,
            min_rows: 12
        }).data("gridster");

        UNGM.ManageGridster.autoResizeWidgets();
        UNGM.ManageGridster.gridster.disable();
    },
    autoResizeWidgets: function () {
        var widgetContents = $(".content-fit-widget");
        for (var i = 0; i < widgetContents.length ; i++) {
            // added +2 because if the widgetHeight - contentHeight < 2, the scrollbar appears, even with border-box
            var contentHeight = $(widgetContents[i]).outerHeight(true) + 2;
            if ($(widgetContents[i]).is(".search-widget") && !UNGM.ManageGridster.isPrintPage) {
                contentHeight += UNGM.ManageGridster.searchResultsTableMaxHeight;
            }

            var widget = $(widgetContents[i]).closest("li.widget");
            var adjustedHeight = Math.ceil((contentHeight + 2 * UNGM.ManageGridster.margin) / (UNGM.ManageGridster.cellHeight + 2 * UNGM.ManageGridster.margin));
            UNGM.ManageGridster.gridster.resize_widget($(widget), $(widget).data("sizex"), adjustedHeight);
        }
    },
    getHighestUnoccupiedRow: function() {
        var highestOccupiedCell = UNGM.ManageGridster.gridster.get_highest_occupied_cell();
        return (highestOccupiedCell.row === -Infinity) ? 1 : highestOccupiedCell.row + 1;
    }
};
window.UNGM.ManagePagePrint = {
    init: function (elementIdToPrint, elementIdsToExcludeFromPrint, gridsterColumnNumber) {
        $("#btnPrintPage").off("click").on("click", function () { UNGM.ManagePagePrint.renderPrintPage(elementIdToPrint, elementIdsToExcludeFromPrint, gridsterColumnNumber) });
    },
    renderPrintPage: function (elementIdToPrint, elementIdsToExcludeFromPrint, gridsterColumnCount) {
        var elementsToPrint = $(elementIdToPrint).clone();
        $.each(elementIdsToExcludeFromPrint, function (index, item) {
            $(elementsToPrint).find(item).remove();
        });
        elementsToPrint = elementsToPrint.html();
        var pageWidth = $(".gridster").width();
        var printPageWidth = 986;
        var popupWin = window.open('', '_blank', 'scrollbars=1, width=' + pageWidth + ', height=' + $(window).height() + ', location=no');
        popupWin.document.open();
        var googleAPIFontStyleSheet = '<link href="/Styles/Googleapis/Fonts/OpenSans.css" rel="stylesheet" type="text/css">';
        var jqueryScript = '<script src="/Scripts/jquery-1.12.0.js"></script>';
        var gridSterScript = '<script src="/Scripts/Gridster/jquery.gridster.js"></script>';
        var manageGridSterScript = '<script src="/Scripts/UNGM.ManageGridster.js"></script>';
        var gridSterStyleSheet = '<link rel="stylesheet" type="text/css" href="/Scripts/Gridster/jquery.gridster.min.css">';
        var ungmStyleSheet = '<link href="/Styles/ungm.ltr.css" rel="stylesheet" type="text/css">';
        var pageTransformStyle = '<style type="text/css"> body { -webkit-transform: scale(' + printPageWidth / pageWidth + ', ' + printPageWidth / pageWidth + ') translateX(-' + (pageWidth - printPageWidth) / 2 + 'px) translateY(-' + (pageWidth - printPageWidth) / 2 + 'px); } </style>';
        var manageGridSterInitScript = '<script>$(window).load(function () { UNGM.ManageGridster.setGridParameters(' + gridsterColumnCount + ', ' + pageWidth + '); if (UNGM.ManageGridster.isGridsterUsed) { UNGM.ManageGridster.initGridsterForNonKCAdmin(); } window.print();});</script>';
        var htmlHead = '<head>' + googleAPIFontStyleSheet + jqueryScript + gridSterScript + manageGridSterScript + manageGridSterInitScript + gridSterStyleSheet + ungmStyleSheet + pageTransformStyle + '</head>';
        var htmlBody = '<body class="kc-print-page">' + elementsToPrint + '</body>';
        popupWin.document.write('<html>' + htmlHead + htmlBody + '</html>');
        popupWin.document.close();
    }
};
(function (namespace, undefined) {

    namespace.ElementHash = ElementHashFactory;

    function ElementHashFactory() {
        return new ElementHash();
    }

    function ElementHash() {
        this._items = [];
    }

    ElementHash.prototype.value = value;
    ElementHash.prototype.item = item;

    function value(element, value) {
        var item = this.item(element);
        return item.value = value || item.value;
    }

    function item(element) {
        var items = $.grep(this._items, function (item) { return $(item.element)[0] === $(element)[0]; });
        if (items.length !== 0) {
            return item = items[0];
        } else {
            var item = { element: $(element)[0], value: undefined };
            this._items.push(item);
            return item;
        }
    }

})(window.UNGM.ViewModel = window.UNGM.ViewModel || {});;
'use strict';

(function (namespace, undefined) {

    namespace.Binder = BinderFactory;

    var binderCount = 0;

    function BinderFactory() {
        var binder = {
            provider: provider,
            factory: factory,
            directive: directive,
            filter: filter,
            bind: bind
        };

        var name = 'binder-' + (++binderCount);
        var module = uvm.module(name, ['uvm']);

        function provider(name, provider) {
            module.provider(name, provider);
            return binder;
        }

        function factory(name, factory) {
            module.factory(name, factory);
            return binder;
        }

        function directive(name, directiveFactory) {
            module.directive(name, directiveFactory);
            return binder;
        }

        function filter(name, filterFunction) {
            module.filter(name, function () { return filterFunction; });
            return binder;
        }

        function bind(selector, options) {
            var $injector = uvm.bootstrap(selector, [name]);
            var $rootScope = $injector.get('$rootScope');

            var bond = {
                data: data,
                watch: watch
            };

            bond.data((options || {}).data || {});

            function data(data) {
                if (data !== undefined) {
                    uvm.Util.extend($rootScope, data);
                    $rootScope.$apply();
                }
                return $rootScope;
            }

            function watch(expression, callback) {
                $rootScope.$watch(expression, callback);
            }

            return bond;
        }

        return binder;
    }

})(window.UNGM.ViewModel = window.UNGM.ViewModel || {});
(function (namespace, undefined) {

    namespace.Repeat = RepeatFactory;

    var hash = namespace.ElementHash();

    function RepeatFactory(element, data) {
        var repeat = hash.value(element) || hash.value(element, new Repeat(element));
        if (data) { repeat.data(data); }
        return repeat;
    }

    function Repeat(element) {
        this._template = $(element)[0].outerHTML;
        this._nodes = [$(element)[0]];
        this._indexKey = null;
        this._data = [];
        this.render();
    }

    Repeat.prototype.setIndex = setIndex;
    Repeat.prototype.data = data;
    Repeat.prototype.render = render;

    function setIndex(key, offset) {
        this._indexKey = key;
        this._indexOffset = offset || 0;
    }

    function data(data) {
        if (data instanceof Array) {
            this._data = data;
            this.render();
            return this._data;
        } else if (data === undefined) {
            return this._data;
        } else {
            throw "Repeat.prototype.data() only accepts array; instead got: " + data;
        }
    }

    function render() {
        switch (this._data.length) {
            case 0:
                var nodes = createCommentNodes.apply(this, [this._template]);
                replaceNodes(this._nodes, nodes);
                this._nodes = nodes;
                break;
            default:
                var nodes = createElementNodes.apply(this, [this._template, this._data]);
                replaceNodes(this._nodes, nodes);
                this._nodes = nodes;
                break;
        }
    }

    function createCommentNodes(template) {
        var nodes = [document.createComment(template)];
        return nodes;
    }

    function createElementNodes(template, data) {
        var $this = this;
        var interpolate = namespace.Interpolate(template);
        var nodes = $.map(data, function (datum, index) {
            if ($this._indexKey !== null) {
                datum = $.extend({}, datum);
                datum[$this._indexKey] = index + $this._indexOffset;
            }
            return $(interpolate(datum))[0];
        });
        return nodes;
    }

    function replaceNodes(oldNodes, newNodes) {
        var parentNode = oldNodes[0].parentNode;
        parentNode.replaceChild(newNodes[0], oldNodes[0]);
        for (var i = 1; i < oldNodes.length; ++i) {
            parentNode.removeChild(oldNodes[i]);
        }
        for (var i = 1; i < newNodes.length; ++i) {
            parentNode.insertBefore(newNodes[i], newNodes[i - 1].nextSibling);
        }
    }

})(window.UNGM.ViewModel = window.UNGM.ViewModel || {});;
(function (namespace, undefined) {

    namespace.Filter = Filter;

    var filters = {};

    function Filter(filter, filterFunction) {
        return filters[filter] = filterFunction || filters[filter];
    }

})(window.UNGM.ViewModel = window.UNGM.ViewModel || {});;
"use strict";

(function (namespace, undefined) {

    namespace.Interpolate = InterpolateFactory;

    var INTERPOLATION_START_SYMBOL = "{{";
    var INTERPOLATION_BODY = "((.|[\n\r])*?)";
    var INTERPOLATION_END_SYMBOL = "}}";
    var INTERPOLATION_PATTERN = INTERPOLATION_START_SYMBOL + INTERPOLATION_BODY + INTERPOLATION_END_SYMBOL;
    var INTERPOLATION_REGEX = new RegExp(INTERPOLATION_PATTERN, "g");
    var INTERPOLATION_ESCAPED_START_SYMBOL = CreateEscapedRegExp(INTERPOLATION_START_SYMBOL.replace(/(.)/g, "\\$1"), "g");
    var INTERPOLATION_ESCAPED_END_SYMBOL = CreateEscapedRegExp(INTERPOLATION_END_SYMBOL.replace(/(.)/g, "\\$1"), "g");

    function InterpolateFactory(text, filters) {
        function Interpolate(object) {
            return text.replace(INTERPOLATION_REGEX, function (match, body) {
                try {
                    var unescapedBody = Unescape(body);
                    var interpolationFunction = ParseInterpolationFunction(unescapedBody);
                    return interpolationFunction(object);
                } catch (e) {
                    console.warn(e);
                    return match;
                }
            });
        }

        var _expressions = null
        Interpolate.expressions = function () {
            if (_expressions !== null) { return _expressions }
            _expressions = []
            for (var match = INTERPOLATION_REGEX.exec(text); match !== null; match = INTERPOLATION_REGEX.exec(text)) {
                var expression = $.trim(match[1].split('|')[0])
                _expressions.push(expression)
            }
            return _expressions
        }

        function ParseInterpolationFunction(body) {
            var tokens = $.trim(body).split(/\s*[|]\s*/);
            var expression = tokens[0];
            var filterTokens = tokens.slice(1);
            var filterFunctions = $.map(filterTokens, function (token) { return ParseInterpolationFilterFunction(token); });
            return function (object) {
                var value = EvaluateExpression(expression, object);
                $.each(filterFunctions, function (index, filterFunction) {
                    value = filterFunction(value);
                });
                return value;
            };
        }

        function ParseInterpolationFilterFunction(body) {
            var tokens = $.trim(body).split(/\s*[:]\s*/);
            var filterName = tokens[0]
            var filter = (filters || {})[filterName] || UNGM.ViewModel.Filter(filterName);
            if (typeof (filter) === 'function') {
                return function (value) {
                    return filter.apply(null, [value].concat(tokens.slice(1)));
                };
            } else {
                console.error('filter not found: ' + filterName);
                return function (value) { return value; };
            }
        }

        function EvaluateExpression(expression, object) {
            if (object.evaluate !== undefined) { return object.evaluate(expression) }

            try {
                expression = expression.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
                expression = expression.replace(/^\./, '');           // strip a leading dot
                var tokens = expression.split('.');
                var node = object;
                $.each(tokens, function (_index, token) {
                    if (token in node) {
                        node = node[token];
                    } else {
                        throw "token not found: " + expression;
                    }
                });
                return node;
            } catch (e) {
                console.warn(e);
                return undefined;
            }
        }

        function Unescape(body) {
            return body.replace(INTERPOLATION_ESCAPED_START_SYMBOL, INTERPOLATION_START_SYMBOL)
                .replace(INTERPOLATION_ESCAPED_END_SYMBOL, INTERPOLATION_END_SYMBOL);
        }

        return Interpolate
    }

    function CreateEscapedRegExp(text, option) {
        return new RegExp(text.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"), option);
    }

})(window.UNGM.ViewModel = window.UNGM.ViewModel || {});;
(function (namespace, undefined) {

    namespace.DelayedFunction = DelayedFunctionFactory;

    function DelayedFunctionFactory(func, timeout) {
        var _timeout = timeout || 300;
        var _timeoutId = null;

        var instance = {
            invoke: invoke,
            cancel: cancel
        }

        function invoke(thisArg, argsArray) {
            cancel();
            _timeoutId = setTimeout(func, _timeout);
        }

        function cancel() {
            clearTimeout(_timeoutId);
        }

        return instance;
    }

})(window.UNGM.ViewModel = window.UNGM.ViewModel || {});
;
(function (namespace, undefined) {

    //
    // Account Registration
    //

    namespace.AccountRegistration = function (parameter) {
        this.FormSelector = parameter.FormSelector;
        this.EnglishNameSelector = parameter.EnglishNameSelector;
        this.CountrySelector = parameter.CountrySelector;
        this.TypeSelector = parameter.TypeSelector;
        this.TypeCommentSelector = parameter.TypeCommentSelector;
        this.TypeCommentHolder = parameter.TypeCommentHolder;
        this.TypeAllowingFreeText = parameter.TypeAllowingFreeText;
        this.PasswordSelector = parameter.PasswordSelector;
        this.ConfirmPasswordSelector = parameter.ConfirmPasswordSelector;
        this.ReferralSourceSelector = parameter.ReferralSourceSelector;
        this.ReferralSourceComent = parameter.ReferralSourceComent;
        this.CheckingAvailabilityHolder = parameter.CheckingAvailabilityHolder;
        this.CheckingAvailabilityHolderSelector = $(this.CheckingAvailabilityHolder);
        this.InstitutionalOrganizationExistsHolder = parameter.InstitutionalOrganizationExistsHolder;
        this.InstitutionalOrganizationExistsHolderSelector = $(this.InstitutionalOrganizationExistsHolder);
        this.LinkIsCombinationNameAndCountryUnique = parameter.LinkIsCombinationNameAndCountryUnique
        this.LinkActivatePending = parameter.LinkActivatePending;
        this.IsNameAndCountryValid = false;

        this.PasswordSelector.keyup(UNGM.ManageAccount.onPasswordKeyUp);
        this.TypeSelector.change(this.OnTypeChange().bind(this));
        this.EnglishNameSelector.focusout(this.IsCombinationOfInstitutionalOrganizationNameAndCountryUnique().bind(this));
        this.CountrySelector.change(this.IsCombinationOfInstitutionalOrganizationNameAndCountryUnique().bind(this));
        this.FormSelector.submit(this.ValidateForm().bind(this));
        UNGM.GoogleRecaptcha.successCallback = this.SubmitForm();
    }

    namespace.AccountRegistration.prototype.OnTypeChange = function () {
        return function (e) {
            var sender = $(e.currentTarget);
            var itemValue = sender.find('option:selected').val();
            if (itemValue == this.TypeAllowingFreeText) {
                this.TypeCommentHolder.show();
            } else {
                this.TypeCommentHolder.hide();
                this.TypeCommentSelector.val("");
            }
        }
    }

    namespace.AccountRegistration.prototype.IsCombinationOfInstitutionalOrganizationNameAndCountryUnique = function () {
        return function (e) {
            $this = this;
            var name = this.EnglishNameSelector.val();
            var countryId = this.CountrySelector.val();
            if (!this.EnglishNameSelector.valid()
                || !this.CountrySelector.valid()
                || name == undefined
                || countryId == undefined
                || name.length <= 0
                || countryId.length <= 0) {
                return false;
            }
            var sender = $(e.currentTarget);

            sender.siblings(this.CheckingAvailabilityHolder).show();

            $.ajax({
                url: UNGM.siteRoot + this.LinkIsCombinationNameAndCountryUnique,
                data: {
                    name: name,
                    countryId: countryId
                },
                type: 'GET',
                contentType: 'application/json',
                success: function (response) {
                    sender.siblings($this.CheckingAvailabilityHolder).hide()
                    if (response == false) {
                        UNGM.Validation.markElementInvalid($this.CountrySelector);
                        UNGM.Validation.markElementInvalid($this.EnglishNameSelector);
                        $this.IsNameAndCountryValid = false;
                        sender.siblings($this.InstitutionalOrganizationExistsHolder).show();
                    } else {
                        UNGM.Validation.markElementValid(sender);
                        $this.IsNameAndCountryValid = true;
                        $this.InstitutionalOrganizationExistsHolderSelector.hide();
                    }
                }
            });
        }
    }

    namespace.AccountRegistration.prototype.ValidateForm = function () {
        return function (e) {
            $this = this;
            e.preventDefault();
            var form = $(e.currentTarget);

            $this.EnglishNameSelector.focusout();
           
            if (!UNGM.EmailValidation.verified
                || !this.IsNameAndCountryValid
                || !form.valid()) {
                return false;
            }

            grecaptcha.execute();
            
            return true;
        }
    }

    namespace.AccountRegistration.prototype.SubmitForm = function () {
        return function (e) {
            $this = this;
            var form = $("form");

            UNGM.throbOver();

            $.ajax({
                url: form.attr("action"),
                type: 'POST',
                data: form.serialize(),
                success: function () {
                    window.location = UNGM.siteRoot + "Account/Registration/ActivatePending";
                }
            });
        }
    }
}(window.UNGM.InstitutionalOrganization = window.UNGM.InstitutionalOrganization || {}));;
window.UNGM.InstitutionalOrganization = window.UNGM.InstitutionalOrganization || {};
window.UNGM.InstitutionalOrganization.Registration = {
    isSubmissionStatusRegistered: null,
    init: function () {
        $(".tabs").off("submit").on("submit", "form", UNGM.InstitutionalOrganization.Registration.onFormSubmitted);
        $("#btnSubmitRegistration").off("click").on("click", UNGM.InstitutionalOrganization.Registration.submitRegistration);
    },
    onFormSubmitted: function (e) {
        e.preventDefault();
        var form = $(e.currentTarget);

        if (!form.valid() || form.find(".institutionalOrganizationExists:visible").length || form.find("#emailExists:visible").length) {
            return false;
        }

        if (!form.hasClass("contactForm") && UNGM.InstitutionalOrganization.Registration.isSubmissionStatusRegistered === true) {
            var sensitiveElements = form.find("#EnglishName, #InstitutionalOrganizationType, #CountryId, #StatuteDocumentId");
            for (i = 0; i < sensitiveElements.length; i++) {
                var element = $(sensitiveElements[i]);
                var oldValue = element.siblings(".oldValue, .OldDocumentId").val();
                var newValue = element.val();
                if (oldValue !== newValue) {
                    $.confirmWithNoCallback(
                        UNGM.InstitutionalOrganization.Registration.savingConfirmationTitle,
                        UNGM.InstitutionalOrganization.Registration.savingConfirmationMessage,
                        UNGM.InstitutionalOrganization.Registration.savingConfirmationBtnConfirm,
                        UNGM.InstitutionalOrganization.Registration.savingConfirmationBtnCancel,
                        function () { UNGM.InstitutionalOrganization.Registration.submitForm(form); },
                        function () { UNGM.InstitutionalOrganization.Registration.reloadTab(element.parents(".tab")); }
                    );
                    return false;
                }
            }
        }

        UNGM.InstitutionalOrganization.Registration.submitForm(form);
    },
    submitForm: function (form) {
        UNGM.Throbber.Push();
        $.ajax({
            url: form.attr("action"),
            type: "POST",
            data: form.serialize(),
            success: function (response) {
                if (form.hasClass("contactForm")) {
                    $("#dialog").dialog('destroy');
                    UNGM.InstitutionalOrganization.Registration.reloadTab("#ContactsContent");
                }
                // Needed due to the uniqueness constraint of the combination of country and english name
                if (form.attr('id') === "frmGeneralInfo") {
                    UNGM.InstitutionalOrganization.Registration.reloadTab("#CountryContent");
                }
                else if (form.attr('id') === "frmCountry") {
                    UNGM.InstitutionalOrganization.Registration.reloadTab("#GeneralInfoContent");
                }

                UNGM.InstitutionalOrganization.Registration.updateCompletion(response);
            },
            complete: UNGM.Throbber.Pop
        });
    },
    updateCompletion: function (response) {
        UNGM.InstitutionalOrganization.Registration.isSubmissionStatusRegistered = response.IsSubmissionStatusRegistered;
        if (response.CanSubmit) {
            $("#divSubmitRegistration").show();
            $.confirm(
                UNGM.InstitutionalOrganization.Registration.submitRegistrationTitle,
                UNGM.InstitutionalOrganization.Registration.submitRegistrationMessage,
                UNGM.InstitutionalOrganization.Registration.submitRegistrationBtnSubmit,
                UNGM.InstitutionalOrganization.Registration.submitRegistrationBtnSubmitLater,
                UNGM.InstitutionalOrganization.Registration.submitRegistration
            );
        }
        else {
            $("#divSubmitRegistration").hide();
        }
        UNGM.markTabComplete("#GeneralInfo", response.IsGeneralInfoComplete);
        UNGM.markTabComplete("#Address", response.IsAddressComplete);
        UNGM.markTabComplete("#Country", response.IsCountryComplete);
        UNGM.markTabComplete("#Contacts", response.IsContactsComplete);
        UNGM.markTabComplete("#SupportingInfo", response.IsSupportingInfoComplete);
    },
    getForm: function (e) {
        var button = $(e.currentTarget);
        UNGM.Throbber.Push();
        $.ajax({
            url: UNGM.siteRoot + button.data('form-url'),
            type: 'POST',
            success: UNGM.InstitutionalOrganization.Registration.onFormReceived,
            complete: UNGM.Throbber.Pop
        });
    },
    onFormReceived: function (data) {
        $("#dialog").html(data);
        $("#dialog").dialog({
            modal: true,
            title: $(data).data("title"),
            width: $(window).width() * 0.5,
            height: $(window).height() * 0.8,
            hide: { effect: 'fade', duration: 100 },
            show: { effect: 'fade', duration: 100 },
            open: function () {
                UNGM.markRequiredFields();
                $("#dialog").off("submit").on("submit", "form", UNGM.InstitutionalOrganization.Registration.onFormSubmitted);
            }
        });
    },
    deactivateContact: function (event) {
        $.confirm(UNGM.InstitutionalOrganization.Registration.deactivateContactTitle,
            UNGM.InstitutionalOrganization.Registration.deactivateContactMessage,
            UNGM.InstitutionalOrganization.Registration.deactivateContactYesButton,
            UNGM.InstitutionalOrganization.Registration.deactivateContactNoButton,
            function () {
                UNGM.Throbber.Push();
                $.post(UNGM.siteRoot + $(event.currentTarget).data("url"))
                    .done(function (result) {
                        if (result.RedirectToHome) {
                            window.location.href = UNGM.siteRoot;
                        } else {
                            UNGM.InstitutionalOrganization.Registration.reloadTab("#ContactsContent");
                        }
                    })
                    .always(function () { UNGM.Throbber.Pop(); });
            });
    },
    cancelInvitation: function (event) {
        $.confirm(UNGM.InstitutionalOrganization.Registration.cancelInvitationTitle,
            UNGM.InstitutionalOrganization.Registration.cancelInvitationMessage,
            UNGM.InstitutionalOrganization.Registration.cancelInvitationYesButton,
            UNGM.InstitutionalOrganization.Registration.cancelInvitationNoButton,
            function () {
                UNGM.Throbber.Push();
                $.post(UNGM.siteRoot + $(event.currentTarget).data("url"))
                    .done(function () { UNGM.InstitutionalOrganization.Registration.reloadTab("#ContactsContent"); })
                    .always(function () { UNGM.Throbber.Pop(); });
            });
    },
    resendInvitation: function (event) {
        $.confirm(UNGM.InstitutionalOrganization.Registration.resendInvitationTitle,
            UNGM.InstitutionalOrganization.Registration.resendInvitationMessage,
            UNGM.InstitutionalOrganization.Registration.resendInvitationYesButton,
            UNGM.InstitutionalOrganization.Registration.resendInvitationNoButton,
            function () {
                UNGM.Throbber.Push();
                $.post(UNGM.siteRoot + $(event.currentTarget).data("url"))
                    .done(function () { UNGM.InstitutionalOrganization.Registration.reloadTab("#ContactsContent"); })
                    .always(function () { UNGM.Throbber.Pop(); });
            });
    },
    reloadTab: function (elementSelector) {
        var tab = $(elementSelector);
        UNGM.Throbber.Push();
        $.ajax({
            url: UNGM.siteRoot + tab.data('url'),
            type: 'GET',
            success: function (data) {
                tab.html(data);
                if (tab.find("form").length) {
                    UNGM.Validation.initForElement(tab.find("form"));
                    UNGM.markRequiredFields();
                }
            },
            complete: UNGM.Throbber.Pop
        });

    },
    submitRegistration: function () {
        UNGM.Throbber.Push();
        $.ajax({
            url: UNGM.siteRoot + "/InstitutionalOrganization/Registration/SubmitRegistration",
            type: 'POST',
            success: function (response) {
                $("#divSubmittedSuccessMessage").show();
                UNGM.InstitutionalOrganization.Registration.updateCompletion(response);
                UNGM.InstitutionalOrganization.Registration.reloadTab("#GeneralInfoContent");                
                UNGM.InstitutionalOrganization.Registration.reloadTab("#CountryContent");
            },
            complete: UNGM.Throbber.Pop
        });
    },
    isCombinationOfEnglishNameAndCountryUnique: function (e) {
        var sender = $(e.currentTarget);
        var name = sender.closest("form").find("#EnglishName").val();
        var countryId = sender.closest("form").find("#CountryId").val();
        var institutionalOrganizationId = sender.closest("form").find("#Id").val();

        if (!sender.valid() || sender.val().length <= 0) {
            return false;
        }
        sender.siblings(".checkingAvailability").show();

        $.ajax({
            url: UNGM.siteRoot + "InstitutionalOrganization/Registration/IsCombinationOfInstitutionalOrganizationNameAndCountryUnique",
            data: {
                name: name,
                countryId: countryId,
                institutionalOrganizationId: institutionalOrganizationId
            },
            type: 'GET',
            contentType: 'application/json',
            success: function (response) {
                sender.siblings(".checkingAvailability").hide();
                if (response == false) {
                    UNGM.Validation.markElementInvalid(sender);
                    sender.siblings(".institutionalOrganizationExists").show();
                } else {
                    UNGM.Validation.markElementValid(sender);
                    $(".institutionalOrganizationExists").hide();
                }
            }
        });
    }
};
"use strict";

(function (namespace, undefined) {

    namespace.MultipleCountryPicker = MultipleCountryPickerFactory;

    var instances = {};

    function MultipleCountryPickerFactory(params) {
        
        if (instances[params.Id] !== undefined) { return instances[params.Id]; }

        var select = $("#" + params.Id).selectToAutocomplete({ "copy-attributes-to-text-field": true });
        var textAutocomplete = select.siblings("input[type='text']");
        var selectedCountries = select.siblings(".selected-countries");
        var allCountriesLinks = select.siblings(".all-countries-links");
        var selectedCountriesInfos = [];

        textAutocomplete.addClass("ignore-on-serialize");
        textAutocomplete.addClass("ignore-on-dom-events");

        textAutocomplete.on("autocompleteselect", function (event, ui) {
            var countryId = ui.item["real-value"];
            if (countryId != "" && !IsCountrySelected(countryId)) { InsertSelectedCountry(countryId); }
        });

        textAutocomplete.on("autocompleteclose", function (event, ui) {
            textAutocomplete.val("");
        });

        selectedCountries.on("click", ".selected-country-remove", function (event) {
            var countryId = $(event.currentTarget).parent(".selected-country").data("country-id");
            RemoveSelectedCountry(countryId);
        });

        if (params.IsWithSelectAllAndRemoveAllLinks) {
            allCountriesLinks.on("click", ".select-all-countries", SelectAllCountries);
            allCountriesLinks.on("click", ".remove-all-countries", RemoveAllCountries);
        }

        function IsCountrySelected(countryId) {
            return $.grep(selectedCountriesInfos, function (info) { return info.countryId == countryId; }).length !== 0;
        }

        function InsertSelectedCountry(countryId) {
            var countryName = select.children("option[value='" + countryId + "']").text();
            selectedCountriesInfos.push({ countryId: countryId, countryName: countryName });
            selectedCountriesInfos.sort(function (item1, item2) { return item1.countryName.localeCompare(item2.countryName); });
            RefreshSelectedCountries();
            select.triggerHandler("change");
        }

        function RemoveSelectedCountry(countryId) {
            selectedCountriesInfos = $.grep(selectedCountriesInfos, function (info) { return info.countryId != countryId; });
            selectedCountriesInfos.sort(function (item1, item2) { return item1.countryName.localeCompare(item2.countryName); });
            RefreshSelectedCountries();
            select.trigger("change");
        }

        function RemoveAllCountries() {
            selectedCountriesInfos = [];
            RefreshSelectedCountries();
            select.trigger("change");
        }

        function SelectAllCountries() {
            selectedCountriesInfos = [];
            select.children("option:not([value=''])").each(function () {
                selectedCountriesInfos.push({ countryId: $(this).val(), countryName: $(this).text() });
            });
            RefreshSelectedCountries();
            select.trigger("change");
        }

        function RefreshSelectedCountries() {
            selectedCountries.empty();
            $.each(selectedCountriesInfos, function (_, info) { selectedCountries.append(CreateSelectedCountry(info.countryId, info.countryName)); });
        }

        function CreateSelectedCountry(countryId, countryName) {
            var removeText = params.RemoveText || "remove";
            return $("<div class='selected-country' data-country-id='" + countryId + "'> \
                          <input type='hidden' name='" + params.Name + "' value='" + countryId + "'>\
                          <span>" + countryName + "</span> \
                          <a class='selected-country-remove' href='javascript:void(0);' style='display: inline;'>(" + removeText  + " " + countryName + ")</a> \
                      </div>");
        }

        var instance = {
            InsertSelectedCountries: InsertSelectedCountries,
            ClearSelectedCountries: ClearSelectedCountries,
            GetSelectedCountryIds: GetSelectedCountryIds,
            Remove: Remove
        };

        function InsertSelectedCountries(countryIds) {
            $.each(countryIds, function (_, countryId) {
                InsertSelectedCountry(countryId);
            });
        }

        function ClearSelectedCountries() {
            textAutocomplete.val("");
            selectedCountriesInfos = [];
            RefreshSelectedCountries();
        }

        function GetSelectedCountryIds() {
            var selectedCountryIds = [];
            $.each(selectedCountriesInfos, function (_, info) { selectedCountryIds.push(info.countryId); });
            return selectedCountryIds;
        }

        function Remove() {
            delete instances[params.Id];
        }

        return instances[params.Id] = instance;
    }
})(window.UNGM.EditorTemplates = window.UNGM.EditorTemplates || {});
;
"use strict";

(function (namespace, undefined) {

    namespace.MultipleAgencyPicker = MultipleAgencyPickerFactory;

    var instances = {};

    function MultipleAgencyPickerFactory(params) {

        if (instances[params.Id] !== undefined) { return instances[params.Id]; }

        var select = $("#" + params.Id).selectToAutocomplete({ "copy-attributes-to-text-field": true });
        var textAutocomplete = select.siblings("input[type='text']");
        var selectedAgencies = select.siblings(".selected-agencies");
        var allAgenciesLinks = select.siblings(".all-agencies-links");
        var selectedAgenciesInfos = [];

        textAutocomplete.addClass("ignore-on-serialize");
        textAutocomplete.addClass("ignore-on-dom-events");

        textAutocomplete.on("autocompleteselect", function (event, ui) {
            var agencyId = ui.item["real-value"];
            if (agencyId != "" && !IsAgencySelected(agencyId)) { InsertSelectedAgency(agencyId , "true"); }
        });

        textAutocomplete.on("autocompleteclose", function (event, ui) {
            textAutocomplete.val("");
        });

        selectedAgencies.on("click", ".selected-agency-remove", function (event) {
            var agencyId = $(event.currentTarget).parent(".selected-agency").data("agency-id");
            RemoveSelectedAgency(agencyId);
        });

        if (params.IsWithSelectAllAndRemoveAllLinks) {
            allAgenciesLinks.on("click", ".select-all-agencies", SelectAllAgencies);
            allAgenciesLinks.on("click", ".remove-all-agencies", RemoveAllAgencies);
        }

        function IsAgencySelected(agencyId) {
            return $.grep(selectedAgenciesInfos, function (info) { return info.agencyId == agencyId; }).length !== 0;
        }

        function InsertSelectedAgency(agencyId, removable) {
            var agencyAbbreviation = select.children("option[value='" + agencyId + "']").text();
            selectedAgenciesInfos.push({ agencyId: agencyId, agencyAbbreviation: agencyAbbreviation, removable: removable });
            selectedAgenciesInfos.sort(function (item1, item2) { return item1.agencyAbbreviation.localeCompare(item2.agencyAbbreviation); });
            RefreshSelectedAgencies();
            select.triggerHandler("change");
        }

        function RemoveSelectedAgency(agencyId) {
            selectedAgenciesInfos = $.grep(selectedAgenciesInfos, function (info) { return info.agencyId != agencyId; });
            selectedAgenciesInfos.sort(function (item1, item2) { return item1.agencyAbbreviation.localeCompare(item2.agencyAbbreviation); });
            RefreshSelectedAgencies();
            select.trigger("change");
        }

        function RemoveAllAgencies() {
            selectedAgenciesInfos = [];
            RefreshSelectedAgencies();
            select.trigger("change");
        }

        function SelectAllAgencies() {
            selectedAgenciesInfos = [];
            select.children("option:not([value=''])").each(function () {
                selectedAgenciesInfos.push({ agencyId: $(this).val(), agencyAbbreviation: $(this).text() });
            });
            RefreshSelectedAgencies();
            select.trigger("change");
        }

        function RefreshSelectedAgencies() {
            selectedAgencies.empty();
            $.each(selectedAgenciesInfos, function (_, info) { selectedAgencies.append(CreateSelectedAgency(info.agencyId, info.agencyAbbreviation, info.removable)); });
        }

        function CreateSelectedAgency(agencyId, agencyAbbreviation, removable) {
            var removeText = params.RemoveText || "remove";
            if (removable == "true") {
                return $("<div class='selected-agency' data-agency-id='" + agencyId + "'> \
                              <input type='hidden' name='" + params.Name + "' value='" + agencyId + "'>\
                              <span>" + agencyAbbreviation + "</span> \
                              <a class='selected-agency-remove' href='javascript:void(0);' style='display: inline;'>(" + removeText + ")</a> \
                          </div>");
            } else {
                return $("<div class='selected-agency' data-agency-id='" + agencyId + "'> \
                              <input type='hidden' name='" + params.Name + "' value='" + agencyId + "'>\
                              <span>" + agencyAbbreviation + "</span> \
                          </div>");
            }
        }

        var instance = {
            InsertSelectedAgencies: InsertSelectedAgencies,
            ClearSelectedAgencies: ClearSelectedAgencies,
            GetSelectedAgencyIds: GetSelectedAgencyIds
        };

        function InsertSelectedAgencies(agencyIds) {
            $.each(agencyIds, function (_, agencyId) {
                InsertSelectedAgency(agencyId, params.Removable);
            });
        }

        function ClearSelectedAgencies() {
            textAutocomplete.val("");
            selectedAgenciesInfos = [];
            RefreshSelectedAgencies();
        }

        function GetSelectedAgencyIds() {
            var selectedAgencyIds = [];
            $.each(selectedAgenciesInfos, function (_, info) { selectedAgencyIds.push(info.agencyId); });
            return selectedAgencyIds;
        }

        return instances[params.Id] = instance;
    }
})(window.UNGM.EditorTemplates = window.UNGM.EditorTemplates || {});
;
"use strict";

(function (namespace, undefined) {

    namespace.MultipleGeographicRegionPicker = MultipleGeographicRegionPickerFactory;

    var instances = {};

    function MultipleGeographicRegionPickerFactory(params) {
        
        if (instances[params.Id] !== undefined) { return instances[params.Id]; }

        var select = $("#" + params.Id).selectToAutocomplete({ "copy-attributes-to-text-field": true });
        var textAutocomplete = select.siblings("input[type='text']");
        var selectedRegions = select.siblings(".selected-regions");
        var allRegionsLinks = select.siblings(".all-regions-links");
        var selectedRegionsInfos = [];

        textAutocomplete.addClass("ignore-on-serialize");
        textAutocomplete.addClass("ignore-on-dom-events");

        textAutocomplete.on("autocompleteselect", function (event, ui) {
            var regionId = ui.item["real-value"];
            if (regionId != "" && !IsRegionSelected(regionId)) { InsertSelectedRegion(regionId); }
        });

        textAutocomplete.on("autocompleteclose", function (event, ui) {
            textAutocomplete.val("");
        });

        selectedRegions.on("click", ".selected-region-remove", function (event) {
            var regionId = $(event.currentTarget).parent(".selected-region").data("region-id");
            RemoveSelectedRegion(regionId);
        });

        if (params.IsWithSelectAllAndRemoveAllLinks) {
            allRegionsLinks.on("click", ".select-all-regions", SelectAllRegions);
            allRegionsLinks.on("click", ".remove-all-regions", RemoveAllRegions);
        }

        function IsRegionSelected(regionId) {
            return $.grep(selectedRegionsInfos, function (info) { return info.regionId == regionId; }).length !== 0;
        }

        function InsertSelectedRegion(regionId) {
            var regionName = select.children("option[value='" + regionId + "']").text();
            selectedRegionsInfos.push({ regionId: regionId, regionName: regionName });
            selectedRegionsInfos.sort(function (item1, item2) { return item1.regionName.localeCompare(item2.regionName); });
            RefreshSelectedRegions();
            select.triggerHandler("change");
        }

        function RemoveSelectedRegion(regionId) {
            selectedRegionsInfos = $.grep(selectedRegionsInfos, function (info) { return info.regionId != regionId; });
            selectedRegionsInfos.sort(function (item1, item2) { return item1.regionName.localeCompare(item2.regionName); });
            RefreshSelectedRegions();
            select.trigger("change");
        }

        function RemoveAllRegions() {
            selectedRegionsInfos = [];
            RefreshSelectedRegions();
            select.trigger("change");
        }

        function SelectAllRegions() {
            selectedRegionsInfos = [];
            select.children("option:not([value=''])").each(function () {
                selectedRegionsInfos.push({ regionId: $(this).val(), regionName: $(this).text() });
            });
            RefreshSelectedRegions();
            select.trigger("change");
        }

        function RefreshSelectedRegions() {
            selectedRegions.empty();
            $.each(selectedRegionsInfos, function (_, info) { selectedRegions.append(CreateSelectedRegion(info.regionId, info.regionName)); });
        }

        function CreateSelectedRegion(regionId, regionName) {
            var removeText = params.RemoveText || "remove";
            return $("<div class='selected-region' data-region-id='" + regionId + "'> \
                          <input type='hidden' name='" + params.Name + "' value='" + regionId + "'>\
                          <span>" + regionName + "</span> \
                          <a class='selected-region-remove' href='javascript:void(0);' style='display: inline;'>(" + removeText  + " " + regionName + ")</a> \
                      </div>");
        }

        var instance = {
            InsertSelectedRegions: InsertSelectedRegions,
            ClearSelectedRegions: ClearSelectedRegions,
            GetSelectedRegionIds: GetSelectedRegionIds,
            Remove: Remove
        };

        function InsertSelectedRegions(regionIds) {
            $.each(regionIds, function (_, regionId) {
                InsertSelectedRegion(regionId);
            });
        }

        function ClearSelectedRegions() {
            textAutocomplete.val("");
            selectedRegionsInfos = [];
            RefreshSelectedRegions();
        }

        function GetSelectedRegionIds() {
            var selectedRegionIds = [];
            $.each(selectedRegionsInfos, function (_, info) { selectedRegionIds.push(info.regionId); });
            return selectedRegionIds;
        }

        function Remove() {
            delete instances[params.Id];
        }

        return instances[params.Id] = instance;
    }
})(window.UNGM.EditorTemplates = window.UNGM.EditorTemplates || {});
;
"use strict";

(function (namespace, undefined) {

    namespace.Wizard = WizardFactory;

    var hash = UNGM.ViewModel.ElementHash();

    function WizardFactory(selector, area, type, options) {
        var root = $(selector);

        if (hash.value(root)) { return hash.value(root); }

        UNGM.initTabsIn(root);

        root.on("click", ".user-email-template-create", OnUserEmailTemplateCreate);
        root.on("click", ".user-email-template-select", OnUserEmailTemplateSelect);
        root.on("click", ".dynamicField", InsertDynamicFieldIntoActiveTabEmailBodyText);
        root.on("click", ".user-email-template-preview-contact", OnPreviewSelect);
        root.on("click", ".user-email-template-confirm", Confirm);
        UNGM.tabContentReceivedCallback = OnTabContentLoaded;
        UNGM.DocumentPickerCallbacks = { documentPicked: AttachDocument, documentRemoved: DetachDocument };
        
        function OnUserEmailTemplateCreate(event) {
            root = $(event.currentTarget).closest(selector);
            SelectTemplate(null);
        }

        function OnUserEmailTemplateSelect(event) {
            root = $(event.currentTarget).closest(selector);
            var templateId = $(event.currentTarget).closest(".user-email-template").data("template-id");
            SelectTemplate(templateId);
        }

        function InsertDynamicFieldIntoActiveTabEmailBodyText(event) {
            root = $(event.currentTarget).closest(selector);
            var field = $(event.currentTarget).text();
            var richTextArea = root.find(".tab-user-email-template-form .tab:visible .rich-text-area");
            var id = richTextArea.attr("id");
            var editor = CKEDITOR.instances[id];
            editor.insertText(field);
        }

        function OnUserEmailTemplateSubmit(event) {
            event.preventDefault();
            root = $(event.currentTarget).closest(selector);
            var form = $(event.currentTarget);
            UpdateRichTextAreaDataFromCkeditor(form);
            if (IsUserEmailTemplateFormValid(form)) {
                $("#myUserEmailTemplatesInvalid").hide();
                UNGM.Throbber.Push();
                var url = form.attr("action");
                var data = form.serialize();
                $.post(url, data)
                    .done(function(templateId) {
                        var tabIndex = root.find(".tab-user-email-template-index");
                        tabIndex.data("reload", true);
                        SelectTemplate(templateId);
                    })
                    .always(function() { UNGM.Throbber.Pop(); });
            } 
            else {
                $("#myUserEmailTemplatesInvalid").show();
            }
        }

        function OnPreviewSelect(event) {
            var index = $(event.currentTarget).index();
            root = $(event.currentTarget).closest(selector);
            SelectPreview(index);
        }

        var callbacksOnConfirmed = [];
        function Confirm() {
            $.each(callbacksOnConfirmed, function (_, callback) { callback(selectedTemplateId, attachedDocumentIds); });
        }
        function AttachOnConfirmed(callback) {
            callbacksOnConfirmed.push(callback);
        }

        var selectedTemplateId = null;
        function SelectTemplate(templateId) {
            if (templateId === null) {
                selectedTemplateId = templateId;
                LoadCreateForm()
                DisableAttachments();
                DisablePreview();
            } else {
                if (selectedTemplateId !== templateId) {
                    selectedTemplateId = templateId;
                    LoadUpdateForm();
                    EnableAttachments();
                }
                EnablePreview();
            }
            UpdateSelectButton();
        }
        function LoadCreateForm() { return LoadForm("Shared/UserEmailTemplate/CreateForm?UserEmailTemplateArea=" + area + "&UserEmailTemplateType=" + type); }
        function LoadUpdateForm() { return LoadForm("Shared/UserEmailTemplate/UpdateForm?id=" + selectedTemplateId +"&UserEmailTemplateArea=" + area + "&UserEmailTemplateType=" + type); }
        function LoadForm(url) {
            var head = root.find(".tab-header-user-email-template-form");
            var body = root.find(".tab-user-email-template-form");
            body.data("url", url);
            body.data("reload", true);
            head.removeClass("tabDisabled");
            head.click();
        }

        var attachedDocumentIds = [];
        function EnableAttachments() {
            var head = root.find(".tab-header-user-email-template-attachments");
            UNGM.DocumentPickerCallbacks.documentPicked = AttachDocument;
            UNGM.DocumentPickerCallbacks.documentRemoved = DetachDocument;
            head.removeClass("tabDisabled");
        }
        function DisableAttachments() {
            var head = root.find(".tab-header-user-email-template-attachments");
            head.addClass("tabDisabled");
        }
        function AttachDocument(document) {
            attachedDocumentIds.push(document.Id);
        }
        function DetachDocument(documentId) {
            var index = $.inArray(documentId, attachedDocumentIds);
            attachedDocumentIds.splice(index, 1);
        }

        function EnablePreview() {
            var head = root.find(".tab-header-user-email-template-preview");
            var body = root.find(".tab-user-email-template-preview");
            var url = "Shared/UserEmailTemplate/Preview/" + selectedTemplateId;

            if (options.InstitutionalOrganizationId) { url += "?InstitutionalOrganizationId=" + options.InstitutionalOrganizationId; }
            if (options.BusinessSeminarId && options.VendorId) { url += "?BusinessSeminarId=" + options.BusinessSeminarId + "&VendorId=" + options.VendorId; }
            body.data("url", url);
            body.data("reload", true);
            head.removeClass("tabDisabled");
        }
        function DisablePreview() {
            var head = root.find(".tab-header-user-email-template-preview");
            head.addClass("tabDisabled");
        }

        function OnTabContentLoaded(tab) {
            UpdateSelectButton();
            ReplaceRichTextAreaWithCkeditor(tab);
            SelectFirstPreview(tab);
            root.find(".user-email-template-form").bind("submit", OnUserEmailTemplateSubmit);
        }

        function UpdateSelectButton() {
            root.find(".user-email-template-select").show();
            root.find("[data-template-id='" + selectedTemplateId + "'] .user-email-template-select").hide();
        }

        function ReplaceRichTextAreaWithCkeditor(tab) {
            tab.find(".rich-text-area").each(function (_, element) {
                var richTextArea = $(element);
                var id = richTextArea.attr("id");
                var editor = CKEDITOR.instances[id];
                CKEDITOR.replace(id, { toolbar: UNGM.standardToolbarWithLinks });
            });
        }

        function UpdateRichTextAreaDataFromCkeditor(form) {
            form.find(".rich-text-area").each(function (_, element) {
                var richTextArea = $(element);
                var id = richTextArea.attr("id");
                var editor = CKEDITOR.instances[id];
                richTextArea.val(editor.getData());
            });
        }

        function SelectFirstPreview(tab) {
            $(tab).find(".user-email-template-preview-contact").first().click();
        }

        function IsUserEmailTemplateFormValid(form) {
            var texts = ["TextEn", "TextFr", "TextEs", "TextPt", "TextZh"];
            for (var i = 0; i < texts.length; ++i) {
                var text = texts[i];
                var hasSubject = form.find("[name='" + text + ".SubjectText']").val().trim() !== "";
                var hasBody = form.find("[name='" + text + ".BodyText']").val().trim() !== "";
                if (hasSubject && hasBody) { return true; }
            }
            return false;
        }

        function SelectPreview(index) {
            root.find(".user-email-template-preview-contact").removeClass("successnormalpadding").eq(index).addClass("successnormalpadding");
            root.find(".user-email-template-preview-content").hide().eq(index).show();
        }

        var instance = {
            AttachOnConfirmed: AttachOnConfirmed
        };

        return hash.value(root, instance);
    }
})(window.UNGM.UserEmailTemplate = window.UNGM.UserEmailTemplate || {});
;
'use strict';

(function(namespace, undefined) {

    namespace.Dialog = DialogFactory;

    function DialogFactory() {
        var dialog = {
            open: open
        }

        var _element = $('<div></div>');

        function open(url, options) {
            UNGM.Throbber.Push();
            options = options || {}
            $.get(url, options.data)
                .done(function(res) {
                    _element.html(res);
                    _element.dialog({
                            title: options.title,
                            modal: true,
                            width: options.width,
                            height: options.height,
                            hide: { effect: 'fade', duration: 100 },
                            show: { effect: 'fade', duration: 100 },
                            close: function(event, ui) { $(this).dialog('destroy').remove() }
                        })
                        .css("maxHeight", $(window).height() * 0.8);
                })
                .error(function (error) {
                    console.error(error);
                })
                .always(UNGM.Throbber.Pop);
        }

        return dialog;
    }

})((window.UNGM.Util = window.UNGM.Util || {}))
;
'use strict';

(function (namespace, undefined) {

    namespace.PdfDialog = PdfDialogFactory

    function PdfDialogFactory() {
        var pdfDialog = {
            open: open,
            errorMessage: errorMessage
        }

        var _element = $('<div></div>')
        var _errorMessage = "This document is not available."

        function open(pdfUrl, options) {
            if ((options || {}).skipCheck === true) {
                renderPdf(pdfUrl);
                openDialog();
            } else {
                UNGM.Throbber.Push();
                $.ajax({
                    url: pdfUrl,
                    type: 'HEAD',   // Gets only size of the header, not the actual file
                    global: false   // Disable global events, as UNGM.ajaxErrorHandler
                })
                .error(renderError)
                .done(function () { renderPdf(pdfUrl); })
                .always(function () { openDialog((options || {}).title); })
                .always(UNGM.Throbber.Pop)
            }
        }

        function errorMessage(message) {
            _errorMessage = message || _errorMessage
        }

        function renderError() {
            _element.empty()
            _element.html('<div class="info">' + _errorMessage + '</div>')
        }

        function renderPdf(pdfUrl) {
            _element.empty()
            var pdfViewer = UNGM.siteRoot + "Scripts/PDF/web/viewer.html?file="
            var iframeSrc = 'src="' + pdfViewer + pdfUrl + '"'
            var iframeStyle = 'style="width: ' + 0.6 * $(window).width() + 'px; height: ' + 0.7 * $(window).height() + 'px;"'
            var iframe = '<iframe ' + iframeSrc + ' ' + iframeStyle + '></iframe>'
            _element.html(iframe)
        }

        function openDialog(title) {
            _element.dialog({
                modal: true,
                title: title,
                width: 'auto',
                height: 'auto',
                hide: { effect: 'fade', duration: 100 },
                show: { effect: 'fade', duration: 100 }
            })
        }


        return pdfDialog
    }

})((window.UNGM.Util = window.UNGM.Util || {}))
;
//
// DocumentPickerDialog
//

(function (namespace, undefined) {

    namespace.DocumentPickerDialog = function (selector, area) {
        if (namespace.DocumentPickerDialog.prototype._singletonInstance) {
            return namespace.DocumentPickerDialog.prototype._singletonInstance;
        }
        namespace.DocumentPickerDialog.prototype._singletonInstance = this;

        var $this = this;
        this.element = $(selector);
        this.area = area;
        this.pickers = [];

        this.element.load(UNGM.siteRoot + this.area + "/Documents/List?isPicker=true", function () {
            UNGM.DocumentPicker = UNGM.DocumentPicker || {};
            UNGM.DocumentPicker.cofi = 0;
            UNGM.initCollapsables();
            $(".btnClose").click(function () { $this.element.dialog("close") });
            $.each($this.pickers, function (index, picker) { if (!picker.isMultipleDocumentPicker) { picker.Refresh(); } });
        });
    }

    namespace.DocumentPickerDialog.prototype.AttachDocumentPicker = function (picker) {
        this.pickers.push(picker);
    }

    namespace.DocumentPickerDialog.prototype.Open = function (picker) {
        var $this = this;
        UNGM.DocumentPicker.pickDocumentClicked = function (event) {
            var documentId = $(event.currentTarget).data("documentid");

            if (picker.isMultipleDocumentPicker) {
                var document = {
                    Id: documentId,
                    Filename: $(event.currentTarget).data("documentfilename"),
                    Description: $(event.currentTarget).data("description")
                }
                picker.AddDocument(document);
                $this.DisableUnavailableDocuments(picker.filesUsed);
            }
            else {
                $this.element.dialog("close");
                picker.ValidateAndSetValue(documentId);
            }
        };

        $this.element.dialog({
            modal: true,
            title: "Select file",
            width: $(window).width() * 0.8,
            height: $(window).height(),
            position: { my: 'top', at: 'top+' + ($(".top-bar") + 5), of: window },
            hide: { effect: 'fade', duration: 100 },
            show: { effect: 'fade', duration: 100 },
            open: function () {
                UNGM.initDatePickersIn($this.element);
                if (UNGM.Documents.initPagination) {
                    UNGM.Documents.initPagination();
                    UNGM.Documents.init();
                    $this.DisableUnavailableDocuments(picker.filesUsed);
                }
            }
        });
    }

    namespace.DocumentPickerDialog.prototype.GetFileName = function (id) {
        var element = this.element.find("[data-documentid='" + id + "']");
        return element.data('documentfilename');
    }

    namespace.DocumentPickerDialog.prototype.GetFilePath = function (id) {
        return UNGM.siteRoot + this.area + "/Documents/Download?docId=" + id;
    }

    namespace.DocumentPickerDialog.prototype.DisableUnavailableDocuments = function (filesUsed) {
        $(this.element).find(".btn.use").prop("disabled", false);
        if (filesUsed) {
            for (i = 0; i < filesUsed.length; i++) {
                var btnRow = $(this.element).find(".btn.use[data-documentid='" + filesUsed[i].Id + "']").parents(".tableRow");
                btnRow.find(".btn.use").prop("disabled", true);
                btnRow.find(":checkbox").prop("checked", false);
            }
        }
    }

}(window.UNGM.SharedScripts = window.UNGM.SharedScripts || {}));
;
//
// DocumentPicker
//

(function (namespace, undefined) {

    namespace.DocumentPicker = function (selector, errorMessage, dialog, resource) {
        this.element = $(selector);
        this.dialog = dialog;
        this.hidden = $("<input type='hidden'></input>");
        this.select = $("<div><a class='lnkShowDocumentSearch' href='javascript:;'>" + resource.select + "</a></div>");
        this.selected = $("<div style='display:none;'></div>");
        this.filename = $("<a class='lnkShowDocument' href='javascript:;'></a>");
        this.remove = $("<a class='lnkRemoveDocument' href='javascript:;'>" + resource.remove + "</a>");
        this.ErrorMessage = new UNGM.SharedScripts.ErrorMessage(errorMessage);

        this.element.append(this.hidden);
        this.element.append(this.select);
        this.element.append(this.selected);
        this.selected.append(this.filename);
        this.selected.append(this.remove);
        this.dialog.AttachDocumentPicker(this);

        this.select.click(this.Select(this));
        this.remove.click(this.Clear(this));
    }

    namespace.DocumentPicker.prototype.val = function (id, filename, callbackUrl) {
        if (callbackUrl) {
            this.CallbackUrl = callbackUrl;
        }

        if (typeof (id) !== 'undefined' && id != 0) {
            this.hidden.val(id);
            this.ErrorMessage.Hide();
            if (id) {
                this.filename.html(filename || this.dialog.GetFileName(id));
                this.filename.attr('href', this.dialog.GetFilePath(id));
                this.selected.fadeIn();
            } else {
                this.selected.fadeOut();
            }
            // hide the select link if file is selected
            this.ToggleSelectLink(!this.IsNotComplete());
        }

        return this.hidden.val();
    }

    namespace.DocumentPicker.prototype.Select = function ($this) {
        return function (event) {
            $this.dialog.Open($this);
        };
    }

    namespace.DocumentPicker.prototype.Clear = function ($this) {
        return function (event) {
            var removedDocumentId = $this.val();
            if ($this.CallbackUrl && ($this.CallbackUrl.OnRemovedUrl || $this.CallbackUrl.OnPreChangeConfirmationCallback || $this.CallbackUrl.OnChangeCallback)) {
                if ($this.CallbackUrl.OnRemovedUrl) {
                    UNGM.Throbber.Push();
                    $.ajax({
                        url: UNGM.siteRoot + $this.CallbackUrl.OnRemovedUrl,
                        type: 'POST',
                        success: function () {
                            $this.val(null);
                        },
                        error: function (xhr, err) {
                            alert("readyState: " + xhr.readyState + "\nstatus: " + xhr.status + "\nresponseText: " + xhr.responseText);
                        },
                        complete: function () {
                            UNGM.Throbber.Pop();
                        }
                    });
                }

                if ($this.CallbackUrl.OnPreChangeConfirmationCallback) {
                    $this.CallbackUrl.OnPreChangeConfirmationCallback(function () {
                        $this.val(null);
                        $this.CallbackUrl.OnChangeCallback.call();
                    });
                }
                else if ($this.CallbackUrl.OnChangeCallback) {
                    $this.val(null);
                    $this.CallbackUrl.OnChangeCallback.call();
                }
            }
            else {
                $this.val(null);
            }
        };
    }

    namespace.DocumentPicker.prototype.IsNotComplete = function () {
        return !this.hidden.val() || this.hidden.val() == "0";
    }

    namespace.DocumentPicker.prototype.ValidateAndSetValue = function (documentId) {
        var $this = this;
        if ($this.CallbackUrl) {
            if ($this.CallbackUrl.ValidationUrl) {
                UNGM.Throbber.Push();
                $this.ErrorMessage.Hide();
                $.ajax({
                    url: UNGM.siteRoot + $this.CallbackUrl.ValidationUrl.replace("{documentId}", documentId),
                    type: 'GET',
                    success: function (data) {
                        var response = JSON.parse(data);
                        if (response.IsDocumentValid) {
                            $this.val(documentId);
                            $this.ErrorMessage.Hide();
                        }
                        else {
                            $this.val(null);
                            $this.ErrorMessage.SetMessage(response.ErrorMessage);
                            $this.ErrorMessage.Show();
                        }
                    },
                    error: function (xhr, err) {
                        alert("readyState: " + xhr.readyState + "\nstatus: " + xhr.status + "\nresponseText: " + xhr.responseText);
                    },
                    complete: function () {
                        UNGM.Throbber.Pop();
                    }
                });
            }

            if ($this.CallbackUrl.OnSelectedUrl) {
                $.ajax({
                    url: UNGM.siteRoot + $this.CallbackUrl.OnSelectedUrl.replace("{documentId}", documentId),
                    type: 'POST',
                    success: function () {
                        $this.val(documentId);
                    },
                    error: function (xhr, err) {
                        alert("readyState: " + xhr.readyState + "\nstatus: " + xhr.status + "\nresponseText: " + xhr.responseText);
                    }
                });
            }

            if ($this.CallbackUrl.OnPreChangeConfirmationCallback) {
                $this.CallbackUrl.OnPreChangeConfirmationCallback(function () {
                    $this.val(documentId);
                    $this.CallbackUrl.OnChangeCallback.call();
                });
            }
            else if ($this.CallbackUrl.OnChangeCallback) {
                $this.val(documentId);
                $this.CallbackUrl.OnChangeCallback.call();
            }
        }
        else {
            $this.val(documentId);
        }
    }

    namespace.DocumentPicker.prototype.Refresh = function () {
        this.val(this.val());
    }

    namespace.DocumentPicker.prototype.ToggleReadonly = function (readonly) {
        this.ToggleSelectLink(readonly);
        this.ToggleRemoveLink(readonly);
    }

    namespace.DocumentPicker.prototype.ToggleSelectLink = function (readonly) {
        if (readonly || this.val() != 0) {
            this.select.hide();
        }
        else {
            this.select.show();
        }
    }

    namespace.DocumentPicker.prototype.ToggleRemoveLink = function (readonly) {
        if (readonly) {
            this.remove.hide();
        }
        else {
            this.remove.show();
        }
    }
}(window.UNGM.SharedScripts = window.UNGM.SharedScripts || {}));
;

//
// Multiple DocumentPicker
//

(function (namespace, undefined) {

    namespace.MultipleDocumentPicker = function (selector, errorMessage, dialog, resource) {
        this.element = $(selector);
        this.dialog = dialog;
        this.select = $("<div><a class='lnkShowDocumentSearch' href='javascript:;'>" + resource.select + "</a></div>");
        this.documentsList = $("<div class='docslist'></div>");
        this.isMultipleDocumentPicker = true;
        this.filesUsed = [];
        this.ErrorMessage = new UNGM.SharedScripts.ErrorMessage(errorMessage);

        this.element.append(this.select);
        this.element.append(this.documentsList);
        this.dialog.AttachDocumentPicker(this);

        this.select.click(this.Select(this));
    }

    namespace.MultipleDocumentPicker.prototype.AddDocument = function (doc) {
        if (doc) {
            this.filesUsed.push(doc);

            this.documentsList.append(this.RenderDocument(doc));
        }
    }

    namespace.MultipleDocumentPicker.prototype.RenderDocument = function (doc) {
        var elem = $("<div></div>").addClass("filterDiv").attr("data-documentid", doc.Id);
        var name = $("<span></span>").addClass("selectedDocumentFilename");
        var link = $("<a></a>").addClass("lnkShowDocument").attr("href", this.dialog.GetFilePath(doc.Id)).html(doc.Filename);
        var remove = $("<a></a>").addClass("lnkRemoveDocument").attr("data-documentid", doc.Id).attr("href", "javascript:;").html("(remove)");
        remove.on("click", this.Clear(this));

        elem.append(name).append(link).append(remove);
        return elem;
    }

    namespace.MultipleDocumentPicker.prototype.Select = function ($this) {
        return function (event) {
            $this.dialog.Open($this);
        };
    }

    namespace.MultipleDocumentPicker.prototype.Clear = function ($this) {
        return function (event) {
            var documentId = $(event.currentTarget).data("documentid");
            $(event.currentTarget).parent("div[data-documentid='" + documentId + "']").remove();
            $this.filesUsed = $.grep($this.filesUsed, function (item) { return item.Id != documentId; });
        };
    }

    namespace.MultipleDocumentPicker.prototype.IsNotComplete = function () {
        return this.filesUsed.length == 0;
    }

    namespace.MultipleDocumentPicker.prototype.GetSelectedFileIds = function () {
        return this.filesUsed.map(function (item) { return item.Id });
    }
}(window.UNGM.SharedScripts = window.UNGM.SharedScripts || {}));
;
//
// Validation Error Message
//

(function (namespace, undefined) {

    namespace.ErrorMessage = function (selector) {
        this.element = $(selector);
    }

    namespace.ErrorMessage.prototype.Toggle = function (show) {
        if (show) {
            this.Show();
        } else {
            this.Hide();
        }
    }

    namespace.ErrorMessage.prototype.Hide = function (show) {
        this.element.fadeOut();
    }

    namespace.ErrorMessage.prototype.Show = function (show) {
        this.element.fadeIn();
    }

    namespace.ErrorMessage.prototype.SetMessage = function (message) {
        this.element.html(message);
    }
}(window.UNGM.SharedScripts = window.UNGM.SharedScripts || {}));
;
'use strict';

uvm.module('UNGM.BusinessSeminar.Search', ['uvm'])
    .filter('entity_invitation_tag',
        function() {
            return function(value) {
                switch (value) {
                    case 1:
                        return "black";
                    case 2:
                        return "yellow";
                    case 4:
                        return "red";
                    case 8:
                        return "green";
                    default:
                        return "black";
                }
            }
        });;
'use strict';

uvm.module('UNGM.BusinessSeminar.Search')
    .controller('SearchController', SearchController);

SearchController.$inject = ['$http', '$delay', '$element', '$scope', '$confirm', '$stringResource'];

function SearchController($http, $delay, $element, $scope, $confirm, $stringResource) {
    var uvm = {
        config: {},
        businessSeminars: [],
        newSearch: newSearch,
        runSearch: $delay(runSearch, { preInvoke: function () { uvm.waypoint = false; } }),
        resetSearchFilters: resetSearchFilters,
        openBusinessSeminar: openBusinessSeminar,
        editBusinessSeminar: editBusinessSeminar,
        submitBusinessSeminar: submitBusinessSeminar,
        inviteVendors: inviteVendors,
        vendorAttendance: vendorAttendance,
        filter: {
            Page: 0,
            SortField: 'Id',
            SortAscending: false,
            CountryIds: [],
            StartDateFrom: '',
            StartDateTo: '',
            EndDateFrom: '',
            EndDateTo: '',
            Status: 0,
            VendorInvitationStatuses: 0,
            LocationTypes: []
        },
        total: 0,
        waypoint: false
    };

    uvm.newSearch();

    function newSearch() {
        uvm.filter.Page = 0;
        uvm.runSearch();
    }

    function runSearch() {
        uvm.filter.CountryIds = UNGM.EditorTemplates.MultipleCountryPicker({ Id: 'CountryIds' }).GetSelectedCountryIds();
        $http.get(uvm.config.searchUrl, { data: uvm.filter })
            .done(function (result) {
                if (typeof (result) === 'string') { result = JSON.parse(result); }
                var isFirstPage = uvm.filter.Page === 0;
                uvm.filter.Page = uvm.filter.Page +1;
                uvm.businessSeminars = isFirstPage ? result.Items : uvm.businessSeminars.concat(result.Items);
                uvm.shown = uvm.businessSeminars.length;
                uvm.total = result.TotalCount;
                uvm.waypoint = uvm.businessSeminars.length < result.TotalCount;
            });
    }

    function resetSearchFilters() {
        UNGM.EditorTemplates.MultipleCountryPicker({ Id: 'CountryIds' }).ClearSelectedCountries();
        uvm.filter.SortField = 'Id';
        uvm.filter.SortAscending = false;
        uvm.filter.CountryIds = [];
        uvm.filter.StartDateFrom = '';
        uvm.filter.StartDateTo = '';
        uvm.filter.EndDateFrom = '';
        uvm.filter.EndDateTo = '';
        uvm.filter.Status = 0;
        uvm.filter.VendorInvitationStatuses = 0;
        uvm.newSearch();
    }

    function openBusinessSeminar(businessSeminarId) {
        var businessSeminar = $.grep(uvm.businessSeminars, function (businessSeminar) { return businessSeminar.Id === businessSeminarId; })[0];
        if (businessSeminar.KnowledgeCenterRelativeUrl) {
            window.open(UNGM.siteRoot + businessSeminar.KnowledgeCenterRelativeUrl, '_blank');
        } else {
            window.open(UNGM.siteRoot + 'Shared/BusinessSeminar/Detail/' + businessSeminarId, '_blank');
        }
    }

    function editBusinessSeminar($event, businessSeminarId) {
        $event.stopPropagation();
        UNGM.Throbber.Push();
        window.location.href = UNGM.siteRoot + 'InstitutionalOrganization/BusinessSeminar/Edit/' + businessSeminarId;
    }

    function submitBusinessSeminar($event, businessSeminarId) {
        $event.stopPropagation();
        $confirm({
            title: $stringResource.get('InstitutionalOrganization.BusinessSeminar.Index.SaveAndSubmitDialogTitle'),
            description: $stringResource.get('InstitutionalOrganization.BusinessSeminar.Index.SaveAndSubmitDialogMessage'),
            confirm: $stringResource.get('InstitutionalOrganization.BusinessSeminar.Index.SaveAndSubmitDialogSubmit'),
            cancel: $stringResource.get('InstitutionalOrganization.BusinessSeminar.Index.SaveAndSubmitDialogCancel')
        })
        .done(function () {
            var submitUrl = UNGM.siteRoot + 'InstitutionalOrganization/BusinessSeminar/Submit/' + businessSeminarId;
            $http.post(submitUrl, {})
                .done(function () {
                    $.each(uvm.businessSeminars, function (_index, item) {
                        if (item.Id === businessSeminarId) {
                            item.Status = 2; // Submitted
                        }
                    });
                });
        });
    }

    function inviteVendors($event, businessSeminarId) {
        $event.stopPropagation();
        UNGM.Throbber.Push();
        window.location.href = UNGM.siteRoot + 'Shared/BusinessSeminar/VendorsForInstitutionalOrganization/' + businessSeminarId;
    }

    function vendorAttendance($event, businessSeminarId) {
        $event.stopPropagation();
        UNGM.Throbber.Push();
        window.location.href = UNGM.siteRoot + 'Shared/BusinessSeminar/VendorsForInstitutionalOrganization/' + businessSeminarId;
    }

    return uvm;
};
'use strict';

uvm.module('UNGM.BusinessSeminar.Search')
    .controller('DetailController', DetailController);

DetailController.$inject = ['$element', '$http', '$scope', '$dialog', '$confirm', '$stringResource'];

function DetailController($element, $http, $scope, $dialog, $confirm, $stringResource) {

    var BUSINESS_SEMINAR_ONE_TO_ONE_MEETING_INVITER__ENTITY = 1;
    var BUSINESS_SEMINAR_ONE_TO_ONE_MEETING_INVITER__VENDOR = 2;

    var BUSINESS_SEMINAR_ONE_TO_ONE_MEETING_STATUS__PENDING = 1;
    var BUSINESS_SEMINAR_ONE_TO_ONE_MEETING_STATUS__ACCEPTED = 2;
    var BUSINESS_SEMINAR_ONE_TO_ONE_MEETING_STATUS__NATA = 4;

    var uvm = {
        evaluation: evaluationFactory(),
        entityInvitationResponse: {
            resourceUrl:
                UNGM.siteRoot +
                'Shared/BusinessSeminar/EntityInvitationResponse/' +
                '?id=' +
                $element.attr('data-uvm-business-seminar-id') +
                '&entityId=' +
                $element.attr('data-uvm-business-seminar-entity-id'),
            data: {
                entityId: parseInt($element.attr('data-uvm-business-seminar-entity-id')),
                status: parseInt($element.attr('data-uvm-business-seminar-entity-invitation-status')),
                historyLogs: []
            },
            form: {
                status: 8, // !== BusinessSeminarStatus.Approved as default value
                comment: ''
            },
            commentLimit: parseInt($element.attr('data-uvm-business-seminar-entity-invitation-comment-limit')),
            isExpanded: false,
            init: initEntityInvitationResponse,
            get: getEntityInvitationResponse,
            save: saveEntityInvitationResponse,
            commentMissing: entityInvitationResponseCommentMissing,
            commentExceedingLimit: entityInvitationResponseCommentExceedingLimit
        },
        entityContactsResponse: {
            resourceUrl:
                UNGM.siteRoot +
                'Shared/BusinessSeminar/EntityContacts/' +
                '?id=' +
                $element.attr('data-uvm-business-seminar-id') +
                '&entityId=' +
                $element.attr('data-uvm-business-seminar-entity-id'),
            data: {
                entityId: parseInt($element.attr('data-uvm-business-seminar-entity-id')),
                contacts: []
            },
            isExpanded: false,
            init: initEntityContactsResponse,
            get: getEntityContacts
        },
        oneToOneMeetingEntity: oneToOneMeetingEntityFactory(),
        expressionOfInterest: {
            isSuccessful: false,
            businessSeminarUrl: '',
            expressInterest: expressInterest,
            redirectToLogin: redirectToLogin
        }
    };

    function expressInterest() {
        $http.post(UNGM.siteRoot + "Shared/BusinessSeminar/VendorExpressionOfInterest/" + $element.attr('data-uvm-business-seminar-id'))
            .done(function () {
                uvm.expressionOfInterest.isSuccessful = true;
            });
    }

    function redirectToLogin() {
        window.location.href = UNGM.siteRoot + "Account/Account/Login?returnUrl=" + uvm.expressionOfInterest.businessSeminarUrl;
    }

    function evaluationFactory() {
        var evaluation = {
            resourceUrl: UNGM.siteRoot + 'Shared/BusinessSeminar/Evaluation/' + $element.attr('data-uvm-business-seminar-id'),
            data: {
                id: parseInt($element.attr('data-uvm-business-seminar-id')),
                status: 0,
                historyLogs: []
            },
            form: {
                status: 0,
                comment: ''
            },
            init: init,
            get: get,
            save: save,
            commentMissing: commentMissing
        };

        var initialized = false;
        function init() {
            if (!initialized) {
                evaluation.get();
                initialized = true;
            }
        }

        function get() {
            $http.get(evaluation.resourceUrl)
                .done(function (res) {
                    evaluation.data.status = res.Status;
                    evaluation.data.historyLogs = res.HistoryLogs;
                });
        }

        function save() {
            if (evaluation.commentMissing()) { return; }
            $confirm({
                title: $stringResource.get('Shared.BusinessSeminar.Evaluation.ConfirmDialogTitle'),
                description: $stringResource.get('Shared.BusinessSeminar.Evaluation.ConfirmDialogDescription'),
                confirm: $stringResource.get('Shared.BusinessSeminar.Evaluation.ConfirmDialogConfirm'),
                cancel: $stringResource.get('Shared.BusinessSeminar.Evaluation.ConfirmDialogCancel')
            }).done(function () {
                $http.post(evaluation.resourceUrl, evaluation.form)
                    .done(evaluation.get);
            });
        }

        function commentMissing() {
            return evaluation.form.status !== 4 // !== BusinessSeminarStatus.Approved
                && evaluation.form.comment.length === 0;
        }

        return evaluation;
    }

    var entityInvitationResponseInitalized = false;
    function initEntityInvitationResponse() {
        uvm.entityInvitationResponse.isExpanded = !uvm.entityInvitationResponse.isExpanded;
        uvm.entityContactsResponse.isExpanded = false;
        if (!entityInvitationResponseInitalized) {
            uvm.entityInvitationResponse.get();
            entityInvitationResponseInitalized = true;
        }
    }

    function getEntityInvitationResponse() {
        $http.get(uvm.entityInvitationResponse.resourceUrl)
            .done(function (res) {
                uvm.entityInvitationResponse.data.status = res.Status;
                uvm.entityInvitationResponse.data.historyLogs = res.HistoryLogs;
                uvm.entityInvitationResponse.form.status = 8; // !== BusinessSeminarStatus.Approved as default value
                uvm.entityInvitationResponse.form.comment = '';
            });
    }

    var entityContactsResponseInitalized = false;
    function initEntityContactsResponse() {
        uvm.entityContactsResponse.isExpanded = !uvm.entityContactsResponse.isExpanded;
        uvm.entityInvitationResponse.isExpanded = false;
        if (!entityContactsResponseInitalized) {
            uvm.entityContactsResponse.get();
            entityContactsResponseInitalized = true;
        }
    }

    function getEntityContacts() {
        $http.get(uvm.entityContactsResponse.resourceUrl)
            .done(function (res) {
                uvm.entityContactsResponse.data.contacts = res;
            });
    }

    function saveEntityInvitationResponse() {
        if (uvm.entityInvitationResponse.commentMissing() || uvm.entityInvitationResponse.commentExceedingLimit()) { return; }
        $confirm({
            title: $stringResource.get('Shared.BusinessSeminar.EntityInvitationResponse.ConfirmDialogTitle'),
            description: $stringResource.get('Shared.BusinessSeminar.EntityInvitationResponse.ConfirmDialogDescription'),
            confirm: $stringResource.get('Shared.BusinessSeminar.EntityInvitationResponse.ConfirmDialogConfirm'),
            cancel: $stringResource.get('Shared.BusinessSeminar.EntityInvitationResponse.ConfirmDialogCancel')
        }).done(function () {
            $http.post(uvm.entityInvitationResponse.resourceUrl, uvm.entityInvitationResponse.form)
                .done(uvm.entityInvitationResponse.get);
        });
    }

    function entityInvitationResponseCommentMissing() {
        return uvm.entityInvitationResponse.form.status === 4 // === BusinessSeminarEntityInvitationStatus.Declined
            && uvm.entityInvitationResponse.form.comment.length === 0;
    }

    function entityInvitationResponseCommentExceedingLimit() {
        return uvm.entityInvitationResponse.form.comment.length > uvm.entityInvitationResponse.commentLimit;
    }

    function oneToOneMeetingEntityFactory() {
        var oneToOneMeetingEntity = {
            config: {
                status: 0,
                inviter: 0
            },

            requestOneToOneMeeting: requestOneToOneMeeting,
            respondToOneToOneMeeting: respondToOneToOneMeeting,
            save: save,

            response: {
                url: UNGM.siteRoot + 'Shared/BusinessSeminar/OneToOneMeetingResponseFromVendorToBusinessSeminarEntity/' + $element.attr('data-uvm-business-seminar-id'),
                data: {
                    entityId: 0,
                    status: '',
                    comment: ''
                },

                submit: submitResponse,
                noDecisionSelectedMessageShown: false,
                setStatus: setStatus,
                commentMissing: commentMissingResponse
            },
        };

        function requestOneToOneMeeting(businessSeminarId, businessSeminarEntityId) {
            $confirm({
                title: $stringResource.get('Shared.BusinessSeminar.OneToOneMeetingEntity.ConfirmDialogTitle'),
                description: $stringResource.get('Shared.BusinessSeminar.OneToOneMeetingEntity.ConfirmDialogDescription'),
                confirm: $stringResource.get('Shared.BusinessSeminar.OneToOneMeetingEntity.ConfirmDialogConfirm'),
                cancel: $stringResource.get('Shared.BusinessSeminar.OneToOneMeetingEntity.ConfirmDialogCancel')
            }).done(function () {
                $http.post(UNGM.siteRoot + 'Shared/BusinessSeminar/OneToOneMeetingRequestFromVendorToBusinessSeminarEntity?id=' + businessSeminarId + '&entityId=' + businessSeminarEntityId)
                    .done(function () {
                        oneToOneMeetingEntity.config.inviter = BUSINESS_SEMINAR_ONE_TO_ONE_MEETING_INVITER__VENDOR;
                        oneToOneMeetingEntity.config.status = BUSINESS_SEMINAR_ONE_TO_ONE_MEETING_STATUS__PENDING;
                    });
            });
        }

        var dialogHolder = null;
        function respondToOneToOneMeeting(businessSeminarId, businessSeminarEntityId) {
            var url = UNGM.siteRoot + '/Shared/BusinessSeminar/OneToOneMeetingResponseFromVendorToBusinessSeminarEntity/' + businessSeminarId + '?entityId=' + businessSeminarEntityId;
            $dialog(url, {
                title: $stringResource.get("Shared.BusinessSeminar.OneToOneMeetingVendor.ConfirmDialogTitle"),
                width: "70%",
                scope: $scope
            }).done(function (dialog) { dialogHolder = dialog; });
        }
        
        function save() {
            $confirm({
                title: $stringResource.get('Shared.BusinessSeminar.OneToOneMeetingEntity.ConfirmDialogTitle'),
                description: $stringResource.get('Shared.BusinessSeminar.OneToOneMeetingEntity.ConfirmDialogDescription'),
                confirm: $stringResource.get('Shared.BusinessSeminar.OneToOneMeetingEntity.ConfirmDialogConfirm'),
                cancel: $stringResource.get('Shared.BusinessSeminar.OneToOneMeetingEntity.ConfirmDialogCancel')
            }).done(function () {
                $http.post(oneToOneMeetingEntity.requestUrl)
                    .done(function () {
                        oneToOneMeetingEntity.config.inviter = BUSINESS_SEMINAR_ONE_TO_ONE_MEETING_INVITER__VENDOR;
                        oneToOneMeetingEntity.config.status = BUSINESS_SEMINAR_ONE_TO_ONE_MEETING_STATUS__PENDING;
                    });
            });
        }

        function setStatus(status) {
            oneToOneMeetingEntity.response.data.status = parseInt(status);
            decisionSelectionMissing();
        }

        function decisionSelectionMissing() {
            oneToOneMeetingEntity.response.noDecisionSelectedMessageShown =
                oneToOneMeetingEntity.response.data.status !== BUSINESS_SEMINAR_ONE_TO_ONE_MEETING_STATUS__NATA &&
                oneToOneMeetingEntity.response.data.status !== BUSINESS_SEMINAR_ONE_TO_ONE_MEETING_STATUS__ACCEPTED;
        }


        function submitResponse() {
            decisionSelectionMissing();
            if (oneToOneMeetingEntity.response.noDecisionSelectedMessageShown || oneToOneMeetingEntity.response.commentMissing()) { return; }
            $http.post(oneToOneMeetingEntity.response.url, oneToOneMeetingEntity.response.data)
                .done(function () {
                    oneToOneMeetingEntity.config.status = oneToOneMeetingEntity.response.data.status;
                    dialogHolder.close();
                });
        }

        function commentMissingResponse() {
            return oneToOneMeetingEntity.response.data.status === BUSINESS_SEMINAR_ONE_TO_ONE_MEETING_STATUS__NATA
                && $.trim(oneToOneMeetingEntity.response.data.comment).length === 0;
        }

        return oneToOneMeetingEntity;
    }

    return uvm;
};
'use strict';

(function (undefined) {
    uvm.module('UNGM.BusinessSeminar.Search')
        .controller('VendorInvitationController', VendorInvitationController);

    VendorInvitationController.$inject = ['$http', '$scope', '$confirm'];

    function VendorInvitationController($http, $scope, $confirm) {
        var uvm = {
            data: {
                businessSeminarId: 0,
                isVendorInvitationAccepted: false,
                isCurrentUserVendorACompany: true,
                isBusinessSeminarOpenForAcceptingVendorInvitation: false,
                isOpenForModifyingCompanyDescription: false,
                CompanyDescription: '',
                participatingContacts: [],
            },

            addParticipatingContactForm: {
                FirstName: '',
                LastName: '',
                Email: '',
                CompanyPosition: '',
            },

            $init: $init,

            isParticipatingContactEmailTaken: isParticipatingContactEmailTaken,
            addParticipatingContactFromVendorContact: addParticipatingContactFromVendorContact,
            submitAddParticipatingContactForm: submitAddParticipatingContactForm,
            removeParticipatingContact: removeParticipatingContact,
            submitAcceptVendorInvitationForm: submitAcceptVendorInvitationForm,
            updateCompanyDescription: updateCompanyDescription,
            scrollToParticipatingEntities: scrollToParticipatingEntities
        };

        function $init() {
            getVendorContacts();
            getParticipatingContacts();
            getVendorType();
        }

        function isParticipatingContactEmailTaken(participatingContactEmail) {
            var matchingParticipatingContacts = $.grep(uvm.data.participatingContacts, function (participatingContact) {
                return participatingContact.Email === participatingContactEmail;
            });
            return matchingParticipatingContacts.length !== 0;
        }

        function addParticipatingContactFromVendorContact(vendorContactEmail) {
            if (isParticipatingContactEmailTaken(vendorContactEmail)) { return; }

            var participatingVendorContact = $.grep(uvm.data.vendorContacts, function (vendorContact) {
                return vendorContact.Email === vendorContactEmail;
            })[0];
            addParticipatingContact(participatingVendorContact);
        }

        function submitAddParticipatingContactForm($event) {
            var form = $($event.currentTarget).closest('form');
            if (!form.valid()) { return; }
            if (isParticipatingContactEmailTaken(uvm.addParticipatingContactForm.Email)) { return; }

            addParticipatingContact(uvm.addParticipatingContactForm);
        }

        function getVendorContacts() {
            var url = '/Shared/BusinessSeminar/VendorContacts';
            $http.get(url)
                .done(function (res) {
                    uvm.data.vendorContacts = res;
                });
        }

        function getParticipatingContacts() {
            var url = '/Shared/BusinessSeminar/VendorParticipatingContacts?businessSeminarId=' + uvm.data.businessSeminarId;
            $http.get(url)
                .done(function (res) {
                    uvm.data.participatingContacts = res;
                });
        }

        function getVendorType() {
            var url = '/Shared/BusinessSeminar/IsCurrentUserVendorACompany';
            $http.get(url)
                .done(function (res) {
                    uvm.data.isCurrentUserVendorACompany = res;
                });
        }

        function addParticipatingContact(participatingContact) {
            var url = '/Shared/BusinessSeminar/AddVendorParticipatingContact?businessSeminarId=' + uvm.data.businessSeminarId;
            $http.post(url, participatingContact)
                .always(function () {
                    uvm.addParticipatingContactForm = {
                        FirstName: '',
                        LastName: '',
                        Email: '',
                        CompanyPosition: '',
                    };
                    $scope.$emit('close');
                    getParticipatingContacts();
                });
        }

        function removeParticipatingContact(participatingContactEmail) {
            if (uvm.data.participatingContacts.length <= 1) { return; }
            $confirm('Shared.BusinessSeminar.VendorContact.RemoveParticipatingContactDialog')
                .done(function () {
                    var url = '/Shared/BusinessSeminar/RemoveVendorParticipatingContact?businessSeminarId=' + uvm.data.businessSeminarId;
                    $http.post(url, { participatingContactEmail: participatingContactEmail })
                        .always(function () {
                            getParticipatingContacts();
                        });
                })
        }

        function submitAcceptVendorInvitationForm($event) {
            var form = $($event.currentTarget).closest('form');
            if (!form.valid()) { return; }
            if (uvm.data.participatingContacts.length === 0) { return; }

            var url = '/Shared/BusinessSeminar/AcceptVendorInvitation?businessSeminarId=' + uvm.data.businessSeminarId;
            $http.post(url, { CompanyDescription: uvm.data.CompanyDescription })
                .done(function () {
                    uvm.data.isVendorInvitationAccepted = true;
                    location.reload();
                });
        }

        function updateCompanyDescription($event) {
            var form = $($event.currentTarget).closest('form');
            if (!form.valid()) { return; }
            if (uvm.data.isVendorInvitationAccepted === false || uvm.data.isOpenForModifyingCompanyDescription === false) { return; }

            var url = '/Shared/BusinessSeminar/UpdateVendorDescription?businessSeminarId=' + uvm.data.businessSeminarId;
            $http.post(url, { CompanyDescription: uvm.data.CompanyDescription });
        }

        function scrollToParticipatingEntities() {
            window.scrollTo({
                top: $("#participating-entities").offset().top - $(".top-bar").height() - 10,
                left: 0,
                behavior: 'smooth'
            });
        }

        return uvm;
    }
})();
;
'use strict';

uvm.module('UNGM.KnowledgeCenterWorkingGroup.Membership', ['uvm']);
    ;
'use strict';

uvm.module('UNGM.KnowledgeCenterWorkingGroup.Membership')
    .controller('MembershipController', MembershipController);

MembershipController.$inject = ['$http', '$delay', '$element', '$scope', '$confirm', '$stringResource'];

function MembershipController($http, $delay, $element, $scope, $confirm, $stringResource) {
    var uvm = {        
        users: [],
        userIds: [],
        resetSearch: resetSearch,
        search: $delay(search, { preInvoke: function () { uvm.waypoint = false; } }),
        resetSearchFilters: resetSearchFilters,
        filter: {            
            SortField: 'Id',
            SortAscending: false,
            Id: $element.data('id'),
            Username: '',
            FirstName: '',
            Surname: '',
            Organization: '',            
            IsGroupAdmin: false,
            IsGroupEditor: false,
            IsGroupViewer: false,
            Roles: [],
            WorkingGroupNames: [],
            Skip: 0
        },
        knowledgeCenterWorkingGroupPermissions: {
            admin: '',
            editor: '',
            viewer: ''
        },
        isSelectAllGroupAdminChecked: false,
        isSelectAllGroupEditorChecked: false,
        isSelectAllGroupViewerChecked: false,
        total: 0,
        shown: false,
        waypoint: false,
        savePermission: savePermission,
        saveAllPermissions: saveAllPermissions,        
        url: UNGM.siteRoot + $element.data('uvm-user-search-url')
    };

    uvm.resetSearch();

    function resetSearch() {
        uvm.filter.Skip = 0;        
        uvm.search();
    }

    function search() {        
        $http.get(uvm.url, { data: uvm.filter })
            .done(function (result) {
                result = JSON.parse(result);

                var isFirstPage = uvm.filter.Skip == 0;
                uvm.users = isFirstPage ? result.users : uvm.users.concat(result.users);
                uvm.filter.Skip = uvm.users.length;
                uvm.shown = uvm.users.length;
                uvm.total = result.totalCount;
                uvm.waypoint = uvm.users.length < result.totalCount;
                updateSelectAllPermissionCheckboxes();
            });
    }

    function updateSelectAllPermissionCheckboxes() {
        var usersNotHavingGroupAdminPermission = $.grep(uvm.users, function (user, index) {
            return user.IsGroupAdmin == false;
        });

        var usersNotHavingGroupEditorPermission = $.grep(uvm.users, function (user, index) {
            return user.IsGroupEditor == false;
        });

        var usersNotHavingGroupViewerPermission = $.grep(uvm.users, function (user, index) {
            return user.IsGroupViewer == false;
        });
        
        uvm.isSelectAllGroupAdminChecked = usersNotHavingGroupAdminPermission.length > 0 ? false : true;
        uvm.isSelectAllGroupEditorChecked = usersNotHavingGroupEditorPermission.length > 0 ? false : true;
        uvm.isSelectAllGroupViewerChecked = usersNotHavingGroupViewerPermission.length > 0 ? false : true;
    }

    function resetSearchFilters() {
        uvm.filter.Username = '';
        uvm.filter.FirstName = '';
        uvm.filter.Surname = '';
        uvm.filter.Organization = '';        
        uvm.filter.IsGroupAdmin = false;
        uvm.filter.IsGroupEditor = false;
        uvm.filter.IsGroupViewer = false;
        uvm.filter.Roles = [];
        uvm.filter.WorkingGroupNames = [];
        uvm.filter.SortField = 'Id';
        uvm.filter.SortAscending = false;
        uvm.resetSearch();
    }

    function savePermission($event) {        
        var jsonString = JSON.stringify({
            id: uvm.filter.Id,
            isAssigned: $event.currentTarget.checked,
            userId: $($event.currentTarget).data("id"),            
            permission: $($event.currentTarget).data("permission")
        });
        var url = UNGM.siteRoot + 'UNUser/KnowledgeCenterWorkingGroup/SavePermission';
        $http.post(url, jsonString, { contentType: 'application/json' });
    }  

    function saveAllPermissions($event, permission) {
        var isChecked = $event.currentTarget.checked;
        $confirm({
            title: $stringResource.get('UNUser.KnowledgeCenterWorkingGroup.MembershipConfirmDialogTitle'),
            description: $stringResource.get('UNUser.KnowledgeCenterWorkingGroup.Membership.ConfirmDialogDescription') + uvm.users.length
                + $stringResource.get('UNUser.KnowledgeCenterWorkingGroup.Membership.ConfirmDialogSelectedUsers'),
            confirm: $stringResource.get('UNUser.KnowledgeCenterWorkingGroup.Membership.ConfirmDialogConfirm'),
            cancel: $stringResource.get('UNUser.KnowledgeCenterWorkingGroup.Membership.ConfirmDialogCancel')
        }).done(function () {
            var userIds = [];            
            $.each(uvm.users, function (key, user) {
                userIds.push(user.Id);
            });

            var jsonString = JSON.stringify({
                id: uvm.filter.Id,
                isAssigned: isChecked,
                permission: permission,
                userIds: userIds
            });

            var url = UNGM.siteRoot + "UNUser/KnowledgeCenterWorkingGroup/SaveAllPermissions";
            $http.post(url, jsonString, { contentType: 'application/json' });

            $.each(uvm.users, function (key, user) {
                if (permission == uvm.knowledgeCenterWorkingGroupPermissions.admin) {
                    user.IsGroupAdmin = isChecked;
                }
                else if (permission == uvm.knowledgeCenterWorkingGroupPermissions.editor) {
                    user.IsGroupEditor = isChecked;
                }
                else if (permission == uvm.knowledgeCenterWorkingGroupPermissions.viewer) {
                    user.IsGroupViewer = isChecked;
                }
            });
        }).fail(function () {
            $event.currentTarget.checked = !isChecked;
        });
    }
    return uvm;
};
'use strict';

uvm.module('UNGM.KnowledgeCenterWorkingGroup.Membership')
    .controller('MembershipForUnOrganizationsController', MembershipForUnOrganizationsController);

MembershipForUnOrganizationsController.$inject = ['$http', '$element'];

function MembershipForUnOrganizationsController($http, $element) {
    var uvm = {
        Id: $element.data('id'),
        unOrganizations: [],
        savePermission: savePermission,
        loadUnOrganizations: loadUnOrganizations
    };

    uvm.loadUnOrganizations();

    function savePermission($event) {        
        var jsonString = JSON.stringify({
            id: uvm.Id,
            isAssigned: $event.currentTarget.checked,
            unOrganizationId: $($event.currentTarget).data("id")
        });
        var url = UNGM.siteRoot + 'UNUser/KnowledgeCenterWorkingGroup/SavePermissionForUnOrganization';
        $http.post(url, jsonString, { contentType: 'application/json' });
    }  
    
    function loadUnOrganizations() {
        $http.get(UNGM.siteRoot + "UNUser/KnowledgeCenterWorkingGroup/UnOrganizations?id=" + uvm.Id)
            .done(function (result) {
                result = JSON.parse(result);
                uvm.unOrganizations = result.unOrganizations;
            });
    }
    return uvm;
};
UNGM.TenderAlertService = UNGM.TenderAlertService || {};
UNGM.TenderAlertService.RemindMeLater = {
    init: function () {
        $("input[name=Reason]").bind("change", UNGM.TenderAlertService.RemindMeLater.reasonChanged);
    },
    reasonChanged: function () {
        var item = $('input[name=Reason]:checked');
        if (item.val().toLowerCase() === "other") {
            $("#otherReason").show();
            UNGM.markRequiredFields(); 
        } else {
            $("#otherReason").hide();
        }
    },
    submit: function () {
        var form = $("#CreateReminderForm");
        if (form.valid()) {
            UNGM.throbOver(form);
            $.ajax({
                url: form.attr('action'),
                type: 'POST',
                data: form.serialize(),
                success:
                    function () {
                        UNGM.hideThrobber();
                        $.confirm(
                            UNGM.TenderAlertService.RemindMeLater.NotifyTitle,
                            UNGM.TenderAlertService.RemindMeLater.NotifyMessage,
                            UNGM.TenderAlertService.RemindMeLater.NotifyOK,
                            "",
                            function () {
                                UNGM.throbOver(form);
                                window.location.href = "/Public/UNGMPro";
                            }
                        );
                    }
            });
        }
    }
}
;
'use strict';

(function () {
    uvm.module('UNGM.AccountRegistration', ['uvm']);
})();;
'use strict';

(function () {
    uvm.module('UNGM.AccountRegistration')
        .controller('VendorActivatePendingController', VendorActivatePendingController);

    VendorActivatePendingController.$inject = ['$element', '$http'];

    function VendorActivatePendingController($element, $http) {
        var uvm = {
            isEmailSent: false,
            account: {
                Email: "",
                RegistrationProgress: null
            },
            $init: $init,
            resendActivationEmail: resendActivationEmail
        };

        function $init() {
            $http.get(UNGM.siteRoot + 'Account/Registration/GetVendorAccountActivationStatus')
                .done(function (account) {
                    uvm.account = account;
                });
        }

        function resendActivationEmail() {
            $http.post(UNGM.siteRoot + 'Account/Registration/ResendVendorActivationEmail');
            uvm.isEmailSent = true;
        }

        return uvm;
    }
})();;
(function (undefined) {
    uvm.module('UNGM.ProcurementsByCategoriesWidget', ['uvm']);

    uvm.module('UNGM.ProcurementsByCategoriesWidget')
        .filter('in_USD', inUsdFilterFactory);

    function inUsdFilterFactory() {
        return function (value) {
            var number = parseFloat(value);
            if (isNaN(number)) { return ""; }
            if (number < 0) { return "-$" + Math.abs(number).toLocaleString("en", { minimumFractionDigits: 2, maximumFractionDigits: 2, useGrouping: true }); }
            return "$" + number.toLocaleString("en", { minimumFractionDigits: 2, maximumFractionDigits: 2, useGrouping: true });
        };
    }

    uvm.module('UNGM.ProcurementsByCategoriesWidget')
        .filter('in_percentage', inPercentageFilterFactory);

    function inPercentageFilterFactory() {
        return function (value) {
            var number = parseFloat(value);
            if (isNaN(number)) { return ""; }
            var string = number.toLocaleString("en", { minimumFractionDigits: 2, maximumFractionDigits: 2, useGrouping: true }) + "%";
            return (string == "0.00%") ? "< 0.01%" : string;
        };
    }
})();
;
(function (undefined) {
    uvm.module('UNGM.ProcurementsByCategoriesWidget')
        .controller('SearchController', SearchController);

    SearchController.$inject = ['$http', '$delay'];

    function SearchController($http, $delay) {
        var uvm = {
            config: {
                UngmUnspscIds: ''
            },
            filter: {
                UngmUnspscIds: [],
                Year: null,
                ASRUNSPSCLevelName: null,
            },

            result: {
                items: [],
            },

            $init: $init,
            search: $delay(search),
        };

        function $init() {
            uvm.filter.UngmUnspscIds = uvm.config.UngmUnspscIds.split(',');
            uvm.search();
        }

        function search() {
            $http.post('/Public/ASRDataArchive/ProcurementsByCategoriesWidgetResult', uvm.filter)
                .done(function (response) {
                    uvm.result.items = response;
                });
        }

        return uvm;
    }
})();
;
$.widget("ui.dialog", $.ui.dialog, {
    /*! jQuery UI - v1.10.2 - 2013-12-12
     *  http://bugs.jqueryui.com/ticket/9087#comment:27 - bugfix
     *  http://bugs.jqueryui.com/ticket/4727#comment:23 - bugfix
     *  allowInteraction fix to accommodate windowed editors
     */
    _allowInteraction: function (event) {
        if (this._super(event)) {
            return true;
        }

        // address interaction issues with general iframes with the dialog
        if (event.target.ownerDocument != this.document[0]) {
            return true;
        }

        // address interaction issues with dialog window
        if ($(event.target).closest(".cke_dialog").length) {
            return true;
        }

        // address interaction issues with iframe based drop downs in IE
        if ($(event.target).closest(".cke").length) {
            return true;
        }
    },
    /*! jQuery UI - v1.10.2 - 2013-10-28
     *  http://dev.ckeditor.com/ticket/10269 - bugfix
     *  moveToTop fix to accommodate windowed editors
     */
    _moveToTop: function (event, silent) {
        if (!event || !this.options.modal) {
            this._super(event, silent);
        }
    }
});
;
(function (namespace, undefined) {

    namespace.FlyoutMenu = FlyoutMenuFactory;

    function FlyoutMenuFactory() {
        var menuItems = document.querySelectorAll('.flyout-menu');
        Array.prototype.forEach.call(menuItems, function (el, i) {
            el.querySelector('button').addEventListener("click", function (event) {
                if (this.parentNode.classList.contains("open")) {
                    this.parentNode.classList.remove("open");
                    this.setAttribute('aria-expanded', "false");
                } else {
                    this.parentNode.classList.add("open");
                    this.setAttribute('aria-expanded', "true");
                }
                event.preventDefault();
                return false;
            });

            el.addEventListener("focusout", function (event) {
                if (el.contains(event.relatedTarget)) return;

                if (document.querySelector(".flyout-menu.open")) {
                    document.querySelector(".flyout-menu.open").classList.remove("open");
                }
            });
        });
    }

    
})(window.UNGM.Component = window.UNGM.Component || {});;
/*
*   This content is licensed according to the W3C Software License at
*   https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
*/
UNGM.Tab = {
    tablist: null,
    tabs: null,
    panels: null,
    delay:0,
    // For easy reference
    keys : {
        end: 35,
        home: 36,
        left: 37,
        up: 38,
        right: 39,
        down: 40,
        delete: 46
    },

    // Add or substract depending on key pressed
    direction : {
        37: -1,
        38: -1,
        39: 1,
        40: 1
    },

    init: function () {
        UNGM.Tab.tablist = document.querySelectorAll('[role="tablist"]')[0];
        //UNGM.Tab.tablist = $('[role="tablist"]')[0];
        
        UNGM.Tab.delay = UNGM.Tab.determineDelay();
        UNGM.Tab.generateArrays();
        
        // Bind listeners
        for (i = 0; i < UNGM.Tab.tabs.length; ++i) {
            UNGM.Tab.addListeners(i);
        };
        $('div').attr('data-text', '© ' + new Date().getFullYear() +' W3C® (MIT, ERCIM, Keio, Beihang). This page includes material derived from [Example of Tabs with Automatic Activation https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document].');
    },
    

    generateArrays: function () {
        UNGM.Tab.tabs = $('[role="tab"]');
        UNGM.Tab.panels = $('[role="tabpanel"]');
    },

    addListeners: function (index) {
        UNGM.Tab.tabs[index].addEventListener('click', UNGM.Tab.clickEventListener);
        UNGM.Tab.tabs[index].addEventListener('keydown', UNGM.Tab.keydownEventListener);
        UNGM.Tab.tabs[index].addEventListener('keyup', UNGM.Tab.keyupEventListener);

        // Build an array with all tabs (<button>s) in it
        UNGM.Tab.tabs[index].index = index;
    },

    // When a tab is clicked, activateTab is fired to activate it
    clickEventListener: function (event) {
        var tab = event.target;
        UNGM.Tab.activateTab(tab, false);
    },

    // Handle keydown on tabs
    keydownEventListener: function (event) {
        var key = event.keyCode;

        switch (key) {
            case UNGM.Tab.keys.end:
                event.preventDefault();
                // Activate last tab
                UNGM.Tab.activateTab(tabs[tabs.length - 1]);
                break;
            case UNGM.Tab.keys.home:
                event.preventDefault();
                // Activate first tab
                UNGM.Tab.activateTab(tabs[0]);
                break;

            // Up and down are in keydown
            // because we need to prevent page scroll >:)
            case UNGM.Tab.keys.up:
            case UNGM.Tab.keys.down:
                UNGM.Tab.determineOrientation(event);
                break;
        };
    },

    // Handle keyup on tabs
    keyupEventListener: function (event) {
        var key = event.keyCode;

        switch (key) {
            case UNGM.Tab.keys.left:
            case UNGM.Tab.keys.right:
                UNGM.Tab.determineOrientation(event);
                break;
        };
    },

    // When a tablistâ€™s aria-orientation is set to vertical,
    // only up and down arrow should function.
    // In all other cases only left and right arrow function.
    determineOrientation: function (event) {
        var key = event.keyCode;
        var vertical = UNGM.Tab.tablist.getAttribute('aria-orientation') == 'vertical';
        var proceed = false;

        if (vertical) {
            if (key === UNGM.Tab.keys.up || key === UNGM.Tab.keys.down) {
                event.preventDefault();
                proceed = true;
            };
        }
        else {
            if (key === UNGM.Tab.keys.left || key === UNGM.Tab.keys.right) {
                proceed = true;
            };
        };

        if (proceed) {
            UNGM.Tab.switchTabOnArrowPress(event);
        };
    },

    // Either focus the next, previous, first, or last tab
    // depening on key pressed
    switchTabOnArrowPress: function (event) {
        var pressed = event.keyCode;

        for (x = 0; x < UNGM.Tab.tabs.length; ++x) {
            UNGM.Tab.tabs[x].addEventListener('focus', UNGM.Tab.focusEventHandler);
        };

        if (UNGM.Tab.direction[pressed]) {
            var target = event.target;
            if (target.index !== undefined) {
                if (UNGM.Tab.tabs[target.index + UNGM.Tab.direction[pressed]]) {
                    UNGM.Tab.tabs[target.index + UNGM.Tab.direction[pressed]].focus();
                }
                else if (pressed === UNGM.Tab.keys.left || pressed === UNGM.Tab.keys.up) {
                    UNGM.Tab.focusLastTab();
                }
                else if (pressed === UNGM.Tab.keys.right || pressed === UNGM.Tab.keys.down) {
                    UNGM.Tab.focusFirstTab();
                };
            };
        };
    },

    // Activates any given tab panel
    activateTab: function (tab, setFocus) {
        setFocus = setFocus || true;
        // Deactivate all other tabs
        UNGM.Tab.deactivateTabs();

        // Remove tabindex attribute
        tab.removeAttribute('tabindex');

        // Set the tab as selected
        tab.setAttribute('aria-selected', 'true');

        // Get the value of aria-controls (which is an ID)
        var controls = tab.getAttribute('aria-controls');

        // Remove hidden attribute from tab panel to make it visible
        document.getElementById(controls).removeAttribute('hidden');

        // Set focus when required
        if (setFocus) {
            tab.focus();
        };
    },

    // Deactivate all tabs and tab panels
    deactivateTabs: function () {
        for (t = 0; t < UNGM.Tab.tabs.length; ++t) {
            UNGM.Tab.tabs[t].setAttribute('tabindex', '-1');
            UNGM.Tab.tabs[t].setAttribute('aria-selected', 'false');
            UNGM.Tab.tabs[t].removeEventListener('focus', UNGM.Tab.focusEventHandler);
        };

        for (p = 0; p < UNGM.Tab.panels.length; ++p) {
            UNGM.Tab.panels[p].setAttribute('hidden', 'hidden');
        };
    },

    // Make a guess
    focusFirstTab: function () {
        UNGM.Tab.tabs[0].focus();
    },

    // Make a guess
    focusLastTab: function () {
        UNGM.Tab.tabs[UNGM.Tab.tabs.length - 1].focus();
    },

    // Determine whether there should be a delay
    // when user navigates with the arrow keys
    determineDelay: function () {
        var hasDelay = UNGM.Tab.tablist.hasAttribute('data-delay');
        var delay = 0;

        if (hasDelay) {
            var delayValue = UNGM.Tab.tablist.getAttribute('data-delay');
            if (delayValue) {
                delay = delayValue;
            }
            else {
                // If no value is specified, default to 300ms
                delay = 300;
            };
        };

        return delay;
    },

    //
    focusEventHandler: function (event) {
        var target = event.target;

        setTimeout(UNGM.Tab.checkTabFocus, delay, target);
    },

    // Only activate tab on focus if it still has focus after the delay
    checkTabFocus: function (target) {
        focused = document.activeElement;

        if (target === focused) {
            UNGM.Tab.activateTab(target, false);
        };
    }
}
;
'use strict';

(function () {

    var pages = [
        "/",
        "/Login",
        "/Public/Notice",
        "/Public/ContractAward",
        "/Public/UNGMPro",
        "/Public/UNSPSC",
        "/Vendor/Registration"
    ];

    var title = "We are building a more accessible UNGM!";
    var message = "<p style='line-height: 1.5;'>We are transforming UNGM to make it more accessible for people with disabilities. We are making enhancements to the website so that it can be read by screen readers, operable by keyboards, and compliant with the WCAG 2.0. We would appreciate if you could please share your feedback with us by completing a short survey. Thank you very much in advance!</p>";
    var yesButton = "Yes, I will give my feedback";
    var noButton = "Sorry, it is not relevant to me";
    var isWithinSpecifiedTime = new Date() < new Date(2021, 11, 15);
    var delayInMilliseconds = 30 * 1000; 

    if (pages.includes(window.location.pathname) && localStorage.getItem('accessibilityFeedback') != 'shown' && isWithinSpecifiedTime) {
        setTimeout(function () {
            $.confirm(title, message, yesButton, noButton, function () {
                window.open('https://docs.google.com/forms/d/e/1FAIpQLScZDP7wbiC6dsMUile_FRXrlAjwtE-sIb81aoH5koS_oBzIbw/viewform', "_blank");
            }, 700);
            localStorage.setItem('accessibilityFeedback', 'shown');
        }, delayInMilliseconds);
    }

})();;
'use strict';

(function (undefined) {
    uvm.module('UNGM.SustainabilityWeightedProcurementPortfolioModel', ['uvm'])
        .filter('group_class',
            function () {
                return function (value) {
                    switch (value) {
                        case 1: return "sppm-group__icon--critical";
                        case 2: return "sppm-group__icon--marginal";
                        case 3: return "sppm-group__icon--strategic";
                        case 4: return "sppm-group__icon--leverage";
                        default: return "";
                    }
                }
            });
})();;
'use strict';

(function () {
    uvm.module('UNGM.SustainabilityWeightedProcurementPortfolioModel')
        .controller('SimpleController', SimpleController);

    SimpleController.$inject = ['$http', '$scope'];

    function SimpleController($http, $scope) {
        var uvm = {
            categories: [],
            filteredCategories: [],
            selectedCategoriesCount: 0,
            isErrorMessageForCategorySelectionShown: false,
            isAddingCategories: false,
            isAnalysisDone: false,
            showSelectedCategoriesOnly: showSelectedCategoriesOnly,
            toggleCategorySelection: toggleCategorySelection,
            changeSpendingAmount: changeSpendingAmount,
            form: {},
            submit: submit,
            filters:
            {
                keyword: ""
            },
            filter: filter,
            clear: clear,
            search: search,
            result: {},
            editInput: editInput,
            exportDetailedAnalysisResultToExcel: exportDetailedAnalysisResultToExcel
        };

        resetSearch();

        function resetSearch() {
            uvm.search();
            $scope.$apply();
        }

        function clearFilters() {
            uvm.filters.keyword = "";
        }

        function editInput() {
            uvm.isAnalysisDone = false;
        }

        function toggleCategorySelection() {
            uvm.isAddingCategories = !uvm.isAddingCategories;
        }


        function search() {
            $http.get("/UNUser/SustainabilityWeightedProcurementPortfolioModel/GetAll")
                .done(function (result) {
                    uvm.categories = uvm.filteredCategories = result;
                });
        }

        function filter($event) {
            UNGM.Throbber.Push();
            $event.preventDefault();
            uvm.filteredCategories = uvm.categories.filter(category =>
                category.A !== null && category.A.toLowerCase().includes(uvm.filters.keyword.toLowerCase()) ||
                category.B !== null && category.B.toLowerCase().includes(uvm.filters.keyword.toLowerCase())
            );
            UNGM.Throbber.Pop();
        }

        function changeSpendingAmount(Id) {
            validateSpendingAmount(Id);
            refreshSelectedCategoriesCount();
            $scope.$apply();
        }

        function validateSpendingAmount(Id) {
            var category = uvm.categories.find(category => category.Id === Id);
            category.IsSpendingAmountValid = !isNaN(category.SpendingAmount);
        }

        function refreshSelectedCategoriesCount() {
            uvm.selectedCategoriesCount = uvm.categories.filter(category => category.SpendingAmount > 0).length;
            if (uvm.isErrorMessageForCategorySelectionShown) {
                uvm.isErrorMessageForCategorySelectionShown = uvm.selectedCategoriesCount === 0;
            }
        }

        function clear() {
            UNGM.Throbber.Push();
            clearFilters()
            uvm.filteredCategories = uvm.categories;
            UNGM.Throbber.Pop();
        }

        function showSelectedCategoriesOnly() {
            UNGM.Throbber.Push();
            clearFilters();
            uvm.filteredCategories = uvm.categories.filter(category => category.SpendingAmount > 0);
            UNGM.Throbber.Pop();
        }

        function submit($event) {
            $event.preventDefault();
            var $form = $($event.currentTarget);
            if (!$form.valid()) { return; }
            if (uvm.selectedCategoriesCount === 0) {
                uvm.isErrorMessageForCategorySelectionShown = true;
                return;
            }

            uvm.form.selectedCategories = uvm.categories
                .filter(category => category.SpendingAmount > 0)
                .map(category => ({ Id: category.Id, SpendingAmount: parseFloat(category.SpendingAmount) }));

            $http.post("/UNUser/SustainabilityWeightedProcurementPortfolioModel/Simple", JSON.stringify(uvm.form), { contentType : 'application/json' })
                .done(function (data) {
                    uvm.isAnalysisDone = true;
                    loadChart(data);
                    uvm.result = data;
                    $scope.$apply();
                });
        }

        function exportDetailedAnalysisResultToExcel() {
            var riskRatings = encodeURIComponent(JSON.stringify(uvm.result));
            var form = $(`<form action="/UNUser/SustainabilityWeightedProcurementPortfolioModel/ExportDetailedAnalysisResultToExcel" method="POST"><input type="hidden" name="json" value="${riskRatings}"></form>`);
            $(document.body).append(form);
            form.submit();
        }

        return uvm;
    }
})();;
'use strict';

(function () {
    uvm.module('UNGM.SustainabilityWeightedProcurementPortfolioModel')
        .controller('AdvancedController', AdvancedController);

    AdvancedController.$inject = ['$scope'];

    function AdvancedController($scope) {
        var uvm = {
            isAnalysisDone: false,
            submit: submit,
            editInput: editInput,
            exportDetailedAnalysisResultToExcel: exportDetailedAnalysisResultToExcel,
            errorMessage: null,
            result: {}
        };

        function editInput() {
            uvm.isAnalysisDone = false;
        }

        function submit($event) {
            $event.preventDefault();
            $(".error").fadeOut("fast");
            if ($("#sppm-advanced-form").valid() && $("#sppm-advanced-form [name=File]")[0].files[0] !== undefined) {
                UNGM.Throbber.Push();


                $.ajax({
                    type: "POST",
                    enctype: 'multipart/form-data',
                    url: $(this).attr('action'),
                    data: new FormData($("#sppm-advanced-form")[0]),
                    processData: false,
                    contentType: false,
                    cache: false
                })
                .done(function (data) {
                    if (data.errorMessage !== null) {
                        $(".error").html(data.errorMessage);
                        $(".error").show();
                        UNGM.Throbber.Pop();
                        return;
                    }

                    $(".advanced-input").hide();

                    loadChart(data.model);
                    uvm.result = data.model;
                    uvm.isAnalysisDone = true;
                    $scope.$apply();
                    UNGM.Throbber.Pop();
                });
            }
        }

        function exportDetailedAnalysisResultToExcel() {
            var riskRatings = encodeURIComponent(JSON.stringify(uvm.result));
            var form = $(`<form action="/UNUser/SustainabilityWeightedProcurementPortfolioModel/ExportDetailedAnalysisResultToExcel" method="POST"><input type="hidden" name="json" value="${riskRatings}"></form>`);
            $(document.body).append(form);
            form.submit();
        }

        return uvm;
    }
})();;
'use strict';

(function () {
    uvm.module('UNGM.ImplementingPartner', ['uvm'])
})();;
'use strict';

(function () {
    uvm.module('UNGM.ImplementingPartner')
        .controller('AccountRegistrationController', AccountRegistrationController);

    AccountRegistrationController.$inject = ['$scope', '$http', '$element', '$stringResource'];
    
    function AccountRegistrationController($scope, $http, $element, $stringResource) {
        
        var uvm = {
            data: {
                CodeOfConduct: false
            },
            $init: $init,
            validateForm: validateForm,
            submitForm: submitForm,
            onCodeOfConductChanged: onCodeOfConductChanged
        };
        
        function $init() {
            UNGM.GoogleRecaptcha.successCallback = uvm.submitForm;
        }

        function validateForm($event) {
            $event.preventDefault();
            UNGM.removeError();

            if (!uvm.data.CodeOfConduct) {
                $("#CodeOfConduct-error").parent().css("display", "block");
            }

            if ($element.valid() && UNGM.EmailValidation.verified && uvm.data.CodeOfConduct) {
                if (uvm.isGrecaptchaEnabled === "true") {
                    grecaptcha.execute();
                } else {
                    uvm.submitForm();
                }
                return true;
            }
            else {
                return false;
            }
        }

        function submitForm() {
            var $form = $("#ImplementingPartnerForm");
            var url = $form.attr('action');
            var data = $form.serialize();
            var dateAdClicked = localStorage.getItem('dateAdClicked');
            if (dateAdClicked) {
                data += `&DateAdClicked=${encodeURIComponent(dateAdClicked)}`;
            }

            $http.post(url, data)
                .fail(function (response) {
                    UNGM.appendErrorTo($form, response.responseJSON);
                })
                .done(function () {
                    window.location = UNGM.siteRoot + "Account/Registration/ActivatePending";
                });

        }

        function onCodeOfConductChanged() {
            if (!uvm.data.CodeOfConduct) {
                $("#CodeOfConduct-error").parent().css("display", "none");
            }
        }

        return uvm;
    }
})();;
'use strict';

(function () {
    uvm.module('UNGM.ImplementingPartner')
        .controller('ActivatePendingController', ActivatePendingController);

    ActivatePendingController.$inject = ['$scope', '$http'];
    
    function ActivatePendingController($scope, $http) {
        
        var uvm = {
            isEmailSent: false,
            account: {
                Email: "",
                RegistrationProgress: null
            },
            $init: $init,
            resendActivationEmail: resendActivationEmail
        };

        function $init() {
            $http.get(UNGM.siteRoot + 'Account/Registration/GetImplementingPartnerAccountActivationStatus')
                .done(function (account) {
                    uvm.account = account;
                });
        }

        function resendActivationEmail() {
            $http.post(UNGM.siteRoot + 'Account/Registration/ResendImplementingPartnerActivationEmail');
            uvm.isEmailSent = true;
        }

        return uvm;
    }
})();;
