﻿(function ($) {

    $.KEY = {
        UP: 38,
        DOWN: 40,
        DEL: 46,
        TAB: 9,
        RETURN: 13,
        ESC: 27,
        COMMA: 188,
        PAGEUP: 33,
        PAGEDOWN: 34,
        BACKSPACE: 8
    };

    /* 
    ======================================================
    Download a file from the server using an iframe 
    ======================================================
    Example:
    
    $(myButton).bind("click", function(){
    $.downloadFile('/ext/downloadfile.aspx', {'accountID': 123} );
    });
    ====================================================== */
    $.downloadFile = function (url, paramaters) {
        // see if an iframe already exists
        var $iframe = $("iframe[id=FILEDOWNLOAD]");
        if ($iframe.size() == 0) {
            // if iframe does not exist, create it on the fly and add it to the body
            $iframe = $("<iframe>").attr("id", "FILEDOWNLOAD").hide();
            $("body").append($iframe);
        }
        var sep = "?";
        // Build Url by concatenating url and parameters
        for (var name in paramaters) {
            url += sep + name + "=" + encodeURI(paramaters[name])
            sep = "&";
        }
        // Assign file to the iframe
        $iframe.attr("src", url);
    }

    // Currently used by autocomplete only
    $.highlight = function (text, pattern) {
        return text.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + pattern.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>")

    };

    //http://updatepanel.wordpress.com/2009/02/20/getting-the-page-and-viewport-dimensions-using-jquery/
    $.viewport = {
        width: function () {
            return $(window).width();
        },
        height: function () {
            return window.innerHeight ? window.innerHeight : $(window).height();
        }
    };

    // Set Timer
    $.timer = function (interval, callback) {
        var myTimer = setInterval(callback, interval * 1000);
        return myTimer;
    };

    // Clear Timer
    $.clearTimer = function (timerObject) {
        window.clearInterval(timerObject);
    };

    $.getRandomNumber = function (min, max) {
        var adjustedHigh = (parseFloat(max) - parseFloat(min)) + 1;
        return (Math.floor(Math.random() * adjustedHigh) + parseFloat(min));
    };

    $.unitsLeft = function (selector, cookieName, currentValue, timeInterval, minPerInterval, maxPerInterval, minUnitsLeft) {

        var unitsLeft = {
            $selector: $(selector),
            $timer: null,
            change: null
        };

        unitsLeft.change = function () {
            var randomValue = $.getRandomNumber(minPerInterval, maxPerInterval);
            if (randomValue > 0) {
                currentValue -= randomValue;
                $.cookie(cookieName, currentValue, { expires: 10, path: '/' });
                if (currentValue < minUnitsLeft) {
                    $.clearTimer(unitsLeft.$timer);
                }
                else {
                    unitsLeft.$selector.animate({
                        fontSize: "1.2em"
                    }, 500, function () {
                        $(this).html(currentValue).animate({
                            fontSize: "1.0em"
                        }, 500);
                    });
                };
            };

        };


        $.timer(timeInterval, unitsLeft.change);

    };

    $.productDisplay = function (skuList, priceList, shippingData, shippingDefinition, txtSkuIdSelector, txtShippingOptionIdSelector, dropShippingSelector, spnShippingSelector, spnSubTotalSelector, spnTotalSelector, submitButtonSelector, options) {

        var imageBaseUrl = Anmida.AppFolder + "/images/";
        var o = $.extend({
            bgOff: "#fff",
            bgHover: "#dceec6",
            bgSelected: "#f7f1d8"

        }, options || {});

        o.selectedIndex = -1;
        o.shippingAmount = 0;
        o.totalAmount = 0;

        var $spnShippingSelector = $(spnShippingSelector);
        var $spnTotalSelector = $(spnTotalSelector);
        var $spnSubTotalSelector = $(spnSubTotalSelector);
        var $txtSkuIdSelector = $(txtSkuIdSelector);
        var $txtShippingOptionIdSelector = $(txtShippingOptionIdSelector);
        var $selectImages = $("img[class=SELECT_IMAGE]").attr("src", imageBaseUrl + "select-off.png");
        var $submitButtonSelector = $(submitButtonSelector).attr("src", imageBaseUrl + "placeyourorder-disabled.png")
            .bind("click", function (e) {
                if (o.selectedIndex === -1) {
                    alert("Please select a package first before placing your order.");
                    return false;
                }
            });


        var calculateShipping = function () {
            var selectedSku = skuList[o.selectedIndex];

            var skuShippingData = shippingData[selectedSku];
            for (var i = 0; i < skuShippingData.length; i++) {
                $dropShippingSelector.get(0).options[i].text = shippingDefinition[i].Name + " $" + $.formatNumber(skuShippingData[i].Amount, 2, true) + " ";

                if ($dropShippingSelector.val() === skuShippingData[i].ShippingOptionId) {
                    o.shippingAmount = skuShippingData[i].Amount;
                };
            };
            reDisplayTotals();
        };

        var reDisplayTotals = function () {
            o.totalAmount = priceList[o.selectedIndex] + o.shippingAmount;
            $spnSubTotalSelector.html($.formatNumber(priceList[o.selectedIndex], 2, true));
            $spnShippingSelector.html($.formatNumber(o.shippingAmount, 2, true));
            $spnTotalSelector.html($.formatNumber(o.totalAmount, 2, true));
            $txtShippingOptionIdSelector.val($dropShippingSelector.val());
            $txtSkuIdSelector.val(skuList[o.selectedIndex]);
        };


        var $dropShippingSelector = $(dropShippingSelector).bind("change", function (e) {
            calculateShipping();
        });


        var $allItems = $("tr[class=DISPLAY_ITEM]").each(function (n) {

            $(this).bind("click", { index: n }, function (e) {

                if (e.data.index == o.selectedIndex) {
                    return;
                };

                o.selectedIndex = e.data.index;
                calculateShipping();
                $submitButtonSelector.attr("src", imageBaseUrl + "placeyourorder.png");
                $allItems.css("backgroundColor", o.bgOff);
                $selectImages.attr("src", imageBaseUrl + "select-off.png");
                $(this).css("backgroundColor", o.bgSelected);
                $selectImages.slice(e.data.index, e.data.index + 1).attr("src", imageBaseUrl + "select-selected.png");
            }).bind("mouseover", { index: n }, function (e) {
                if (o.selectedIndex != e.data.index) {
                    $(this).css({ "backgroundColor": o.bgHover, "cursor": "pointer" });
                    $selectImages.slice(e.data.index, e.data.index + 1).attr("src", imageBaseUrl + "select-on.png");
                };

            }).bind("mouseout", { index: n }, function (e) {
                if (o.selectedIndex != e.data.index) {
                    $(this).css({ "backgroundColor": o.bgOff });
                    $selectImages.slice(e.data.index, e.data.index + 1).attr("src", imageBaseUrl + "select-off.png");
                };

            });

        });

        if ($txtShippingOptionIdSelector.val() !== "") {
            $dropShippingSelector.val($txtShippingOptionIdSelector.val());
        };

        if ($txtSkuIdSelector.val() !== "") {
            for (var i = 0; i < skuList.length; i++) {
                if ($txtSkuIdSelector.val() === skuList[i]) {
                    $allItems.slice(i, i + 1).trigger("click");
                };
            };
        };


    };

    $.crudGridServer = function (qsCode, qsInitializer, dropNumberOfItemsSelector, txtCurrentPageSelector, currentPage, totalPages, filterSelector, parameterSelectors) {

        var getUrl = function () {

            var currentUrl = window.location.href;
            if (qsInitializer !== "") {
                if (currentUrl.indexOf("?") > -1) {
                    currentUrl += "&" + qsCode + "=" + qsInitializer;
                }
                else {
                    currentUrl += "?" + qsCode + "=" + qsInitializer;
                }
            }
            return currentUrl;
        };

        // Filter
        if (filterSelector != "") {
            $(filterSelector).bind("click", function () {

                var params = "";
                var sep = ""
                for (var i = 0; i < parameterSelectors.length; i++) {
                    params += sep + $(parameterSelectors[i]).val();
                    sep = "/";
                };
                var matchStr = /(g1=[0-9]*?_[0-9]*?_)([\-A-Za-z0-9\/]*)/g;
                window.location.href = getUrl().replace(matchStr, "$1" + params);
                return false;
            });
        }

        // Number of units
        $(dropNumberOfItemsSelector).bind("change", function () {
            var matchStr = /(g1=[0-9]*?_)([0-9]*?)(_)/g;

            window.location.href = getUrl().replace(matchStr, "$1" + $(this).val() + "$3");
        });

        // Current Page
        var $txtCurrentPage = $(txtCurrentPageSelector).bind("keypress", function (e) {
            if (e.keyCode == $.KEY.RETURN) {
                $txtCurrentPage.trigger("blur");
                return false;
            }
        }).bind("blur", function () {
            var c = parseInt($txtCurrentPage.val());
            if (isNaN(c) || c < 1 || c > (totalPages)) {
                $txtCurrentPage.val(currentPage + 1);
            }
            else {
                var matchStr = /(g1=)([0-9]*?)(_)/g;
                window.location.href = getUrl().replace(matchStr, "$1" + (c - 1) + "$3");
            }
        });

    }

    $.crudGrid = function (gridWrapper, pagingPrefix, currentPage, pageSize, totalRecords, hp) {

        var o = {};
        o.hp = hp;
        o.op = 0;
        o.idx = null;
        o.currentPage = currentPage;
        o.pageSize = pageSize;
        o.totalRecords = totalRecords;
        o.orderByColumn = 0;
        o.descending = false;
        o.getTotalPages = function () {
            return Math.ceil(o.totalRecords / o.pageSize);
        };

        o.popupID = "crudGrid_getTableBody";

        var getTableBody = function () {

            var success = function (result) {

                $tbody.html(result.body);
                o.totalRecords = result.totalRecords;
                o.hp = result.hp;
                makeDisplayChanges();
                o.op = 0; // reset to default
                o.idx = null; // reset to default
                bindEvents();
                $.hideModal(o.popupID);

            }
            var failure = function (err) {
                $.hideModal(o.popupID);
                alert(err.Message);
            };

            $.showModal(o.popupID, 2, { elementToOverlay: "#" + gridWrapper });
            $.myAjax("/Admin/WS/Crud.asmx", "GetDynamicGrid", success, failure, { data: "{ 'pageSize': '" + o.pageSize + "','currentPage': '" + o.currentPage + "','orderByColumn': '" + o.orderByColumn + "','descending': '" + o.descending + "','hp': '" + o.hp + "','op': " + o.op + ",'idx': " + o.idx + "}" });

        };

        var $gridWrapper = $("#" + gridWrapper);

        var $ths = $gridWrapper.find("th.sort").each(function (i) {

            var $a = $(this).find("a");
            $a.attr("href", "#").bind("click", function () {
                if (i == o.orderByColumn) {
                    o.descending = !o.descending;
                }
                else {
                    o.orderByColumn = i;
                    o.descending = false;
                }
                o.currentPage = 0;
                o.op = 4; //Sort
                getTableBody();
                return false;
            });
        });

        var $tbody = $gridWrapper.find("tbody[rel=tableBody]");
        var $first = $gridWrapper.find("#" + pagingPrefix + "_First").bind("click", function () {
            o.currentPage = 0;
            getTableBody();
            return false;
        });
        var $previous = $gridWrapper.find("#" + pagingPrefix + "_Previous").bind("click", function () {
            o.currentPage -= 1;
            getTableBody();
            return false;
        });
        var $next = $gridWrapper.find("#" + pagingPrefix + "_Next").bind("click", function () {
            o.currentPage += 1;
            getTableBody();
            return false;
        });
        var $last = $gridWrapper.find("#" + pagingPrefix + "_Last").bind("click", function () {
            o.currentPage = o.getTotalPages() - 1;
            getTableBody();
            return false;
        });
        var $totalPages = $gridWrapper.find("#" + pagingPrefix + "_totalPages");
        var $currentPage = $gridWrapper.find("#" + pagingPrefix + "_txtCurrentPage").bind("keypress", function (e) {
            if (e.keyCode == $.KEY.RETURN) {
                $currentPage.trigger("blur");
                return false;
            }
        }).bind("blur", function () {

            var c = parseInt($currentPage.val());
            if (isNaN(c)) {
                $currentPage.val(o.currentPage + 1);
                c = o.currentPage + 1;
            }
            else {
                if (c > o.getTotalPages()) { c = o.getTotalPages(); }
                else if (c < 1) { c = 1; };

                $currentPage.val(c);
            }
            if (o.currentPage != c - 1) {
                o.currentPage = c - 1;

                getTableBody();
            };

        });


        var $displayInfo = $gridWrapper.find("span#" + pagingPrefix + "_displayInfo").html(totalRecords);
        var $numberOfResults = $gridWrapper.find("select[id$=dropNumberOfResults]").bind("change", function () {
            o.pageSize = $numberOfResults.val();
            o.currentPage = 0;
            getTableBody();
        });


        var bindEvents = function () {

            var $btnDelete = $gridWrapper.find("input[type=button]").each(function (n) {

                $(this).bind("click", { idx: n }, function (e) {
                    if (confirm("Are you sure you want to delete this record?")) {
                        o.op = 3; // Delete
                        o.idx = e.data.idx;
                        getTableBody();
                    };
                });
            });
        };

        var makeDisplayChanges = function () {

            var startRow = o.pageSize * o.currentPage;
            var endRow = startRow + parseInt(o.pageSize);
            if (endRow > o.totalRecords) { endRow = o.totalRecords; };
            $totalPages.html(o.getTotalPages());
            $currentPage.val(o.currentPage + 1);
            startRow++;
            $displayInfo.html("Displaying " + startRow + " to " + endRow + " of " + o.totalRecords + " items");

            if (o.currentPage == 0) {
                $first.hide().next().show();
                $previous.hide().next().show();

            }
            else {
                $first.show().next().hide();
                $previous.show().next().hide();

            };


            if (o.currentPage < (o.getTotalPages() - 1)) {

                $next.show().next().hide();
                $last.show().next().hide();
            }
            else {
                $last.hide().next().show();
                $next.hide().next().show();

            };
        };

        makeDisplayChanges();
        bindEvents();

    }




    // =============================================================================
    // Connecting to ASP.NET Web Services through Jquery
    // =============================================================================
    // http://encosia.com/2008/06/05/3-mistakes-to-avoid-when-using-jquery-with-aspnet-ajax/#more-78
    // http://encosia.com/2009/07/21/simplify-calling-asp-net-ajax-services-from-jquery/#more-888
    // http://www.west-wind.com/weblog/posts/324917.aspx
    // =============================================================================

    // =============================================================================
    // jquery Ajax Options
    // =============================================================================
    // http://docs.jquery.com/Ajax/jQuery.ajax
    // =============================================================================

    // =============================================================================
    // JSON Parser and Stringifier
    // =============================================================================
    // JavaScript json parser (safer than eval)
    // can also stringify javascript objects
    // http://www.json.org/json2.js
    // =============================================================================

    // =============================================================================
    // Ajax Queue Manager:
    // =============================================================================
    // http://www.protofunc.com/scripts/jquery/ajaxManager/
    // =============================================================================

    $.myAjax = function (serviceName, methodName, successMethod, errorMethod, options) {

        var o = $.extend({
            type: "POST",
            data: "{}", // IE 6 issue
            contentType: "application/json; charset=utf-8",
            // dataType: "json", removed, because we are parsing ourselves in dataFilter
            timeout: 0, // jquery default "timeout"
            dataFilter: function (data) {
                //take advantage of browser-native JSON parsing in Firefox 3.5 and IE8
                var msg;
                if (typeof (JSON) !== 'undefined' && typeof (JSON.parse) === 'function') {
                    msg = JSON.parse(data);
                }
                else { msg = eval('(' + data + ')'); };
                if (msg.hasOwnProperty('d')) {
                    return msg.d;
                }
                else {
                    return msg;
                };
            }
        }, options || {});

        $.ajax({
            type: o.type,
            url: serviceName + "/" + methodName,
            data: o.data,
            contentType: o.contentType,
            dataType: o.dataType,
            dataFilter: o.dataFilter,
            timeout: o.timeout,
            success: successMethod,
            error: function (XMLHttpRequest, textStatus, errorThrown) {
                // errorThrown not used with ASP.NET?!?
                var err = null;
                switch (textStatus) {
                    case "error":
                        var res = XMLHttpRequest.responseText;
                        if (res && res.charAt(0) == '{')
                        { err = eval('(' + res + ')'); };
                        if (err == null && XMLHttpRequest.status != 200)
                            err = { Message: "Http Error: " + XMLHttpRequest.statusText };
                        else if (err == null)
                            err = { Message: "Unknown Error Response" };
                        break;
                    case "timeout":
                        err = { Message: "Timeout" };
                        break;
                    default: // "notmodified", "parsererror", or null
                        err = { Message: "Unkown error.", StackTrace: 'TextStatus: ' + textStatus + "\n" + XMLHttpRequest.responseText };
                }
                if (this.url != "/WS/ApplicationLog.asmx/LogException") { // prevent infinite loops
                    $.myAjax("/WS/ApplicationLog.asmx", "LogException", null, null, { data: "{ 'message': '" + escape(err.Message) + "','stackTrace': '" + escape(err.StackTrace) + "','source': '" + escape(this.url) + "','exceptionType': '" + escape(err.ExceptionType) + "','additionalInfo' : '" + escape(JSON.stringify(o.data)) + "'}" });
                };
                if (errorMethod) { errorMethod(err); }; // if error callback was specified, call it

            }
        });
    };


    //http://www.queness.com/post/152/simple-jquery-image-slide-show-with-semi-transparent-caption
    //http://www.leigeber.com/2008/05/ajax-image-gallery-slideshow/
    //http://www.pirolab.it/pirobox/

    // needed CSS
    //    <style type="text/css">
    //        .slideShow
    //        {
    //            position: relative;
    //        }
    //        .slideShow div
    //        {
    //            position: absolute;
    //            top: 0;
    //            left: 0;
    //        }
    //        .slideShow div.active
    //        {
    //            z-index: 500;
    //        }
    //        .slideShow img
    //        {
    //            border: none;
    //        }
    //    </style>

    // HTML markup
    //  <div id="mySlideShow" class="slideShow">
    //    <div>
    //      <img src="img/grass-blades.jpg" alt="Grass Blades" />
    //    </div>
    //  <div>
    //  </div>
    //  </div>

    // init:     
    //$(function() {
    //            $.slideShow("mySlideShow",
    //                    [{ imageUrl: "img/grass-blades.jpg", navigateUrl: "" }
    //                 , { imageUrl: "img/lotus.jpg", navigateUrl: "default.aspx" }
    //   , { imageUrl: "img/lightning.jpg", navigateUrl: "default2.aspx" }
    //                ]
    //            );
    //        });

    $.slideShow = function (slideShowID, images, options) {

        var settings = $.extend({
            currentIndex: -1,
            width: 580,
            height: 360,
            delay: 5000,
            transitionSpeed: 2000
        }, options || {});

        var $slideShow = $("#" + slideShowID).css({ height: settings.height + 'px', width: settings.width + 'px' });

        var isPreloaded = false;

        var preloadNextImage = function () {
            isPreloaded = false;
            if (settings.currentIndex >= (images.length - 1)) {
                settings.currentIndex = 0;
            }
            else {
                settings.currentIndex += 1;
            };

            $('<img />').load(function () {
                isPreloaded = true;
            }).attr('src', images[settings.currentIndex].imageUrl);
        };

        // The first time we load an image the loading spinner is visible, the timeout delay should be really short so we check often if the first image was loaded
        var firstLoadDelay = 200;
        // During subsequent loads we can check less because the user can still look at the previous picture
        var subsequentLoadDelay = 1000;
        var isFirstLoad = true;

        var showNextImage = function () {
            if (isPreloaded) {
                var $active = $slideShow.find("> div.active");
                var $inactive = $slideShow.find("> div:not(div.active)");

                var img = images[settings.currentIndex];

                var $img = $('<img />').attr({ "src": img.imageUrl, "alt": "" });

                $inactive.addClass("active")
    .css({ opacity: 0.0 })
    .html($img).animate({ opacity: 1 }, settings.transitionSpeed);

                if (img.navigateUrl && img.navigateUrl != "") {
                    $img = $img.wrap('<a href="' + img.navigateUrl + '"></a>');
                };

                $active.removeClass("active");
                if (isFirstLoad) {
                    $slideShow.find("div[id=divAjaxLoad]").hide();
                    isFirstLoad = false;
                };
                preloadNextImage();
                setTimeout(showNextImage, settings.delay);
            }
            else {
                setTimeout(showNextImage, isFirstLoad ? firstLoadDelay : subsequentLoadDelay); // Shorter time out because image should be loaded by now
            };
        };

        // If no active class was found
        if ($slideShow.find("div.active").size() === 0) {
            $slideShow.find("div:first").addClass("active");
        };
        preloadNextImage();
        setTimeout(showNextImage, firstLoadDelay); //make the first delay really short so we can check early if the first image has been loaded
    }


    $.initExternalPopup = function (elementId, options) {

        var settings = $.extend({
            width: 720,
            height: 350,
            left: 50,
            top: 50
        }, options || {});


        $("#" + elementId).bind("click", function () {

            // IE7: Make sure that window name contains no Non-Word Characters
            var w = window.open(this.href, this.id.replace(/\W/g, ""), 'height=' + settings.height + ', width=' + settings.width + ', scrollbars=1, resizable=1, left=' + settings.left + ', top=' + settings.top);
            w.focus();
            return false;

        });
    };

    /*
    
    $(function() {
    $.limitTextEntry("TextBox1", 10, {
    emptyMessage: "Please enter text here.",
    charLeftPhraseSingular: "{0} char left.",
    charLeftPhrasePlural: "{0} chars left.",
    charLeftElementId: "charsleft"
    });
    });

    Requires a span with an id specified in <charLeftElementId>
    Supports the following placeholders:
    {0} = chars left
    {1} = max chars

    */

    $.limitTextEntry = function (elementId, maxLength, options) {

        var settings = $.extend({
            emptyMessage: "",
            charLeftPhraseSingular: "{0} char left.",
            charLeftPhrasePlural: "{0} chars left.",
            charLeftElementId: "charsleft"
        }, options || {});

        $Textbox = $("#" + elementId).bind("focus", function () {

            if ($(this).val() == settings.emptyMessage) {
                $(this).val("");
                modifyPhrase();
            }

        }).bind("blur", function () {

            if ($.trim($(this).val()) == "") {
                $(this).val(settings.emptyMessage)
                modifyPhrase();
            };

        }).bind("keyup keydown", function () {
            var str = $(this).val();
            if (str.length > maxLength) {
                $(this).val(str.substring(0, maxLength));
            };
            modifyPhrase();

        });

        var modifyPhrase = function () {

            var charsLeft = ($Textbox.val() == settings.emptyMessage) ? maxLength : (maxLength - $Textbox.val().length);
            var str = (charsLeft == 1) ? settings.charLeftPhraseSingular : settings.charLeftPhrasePlural;
            str = str.replace("{0}", charsLeft);
            str = str.replace("{1}", maxLength);
            $("#" + settings.charLeftElementId).html(str);
        };



        //init
        if ($.trim($Textbox.val()) == "") {
            $Textbox.val(settings.emptyMessage);
        };
        modifyPhrase();
    }


    // Type 1: Dynamic Html stored in html
    // Type 2: Wait (message stored in htmlWait)
    // Type 3: Confirm (message stored in htmlConfirm
    // Type 4: Html retrieved by selector
    $.showModal = function (popupID, type, options) {

        var settings = $.extend({
            anchorSelector: null,
            popupHAlign: 2, //"center"
            popupVAlign: 2, //"middle"
            popupPosition: "absolute",
            popupOffsetLeft: 0,
            popupOffsetTop: 0,
            width: null,
            elementToOverlay: null,
            showOverlay: true,
            overlayColor: "#000",
            overlayOpacity: 0.5,
            locked: false,
            fadeInSpeed: 0,
            zIndexBase: 100, // Minimum number of characters to be entered for autocomplete to trigger
            // allowClose: false,
            html: '',
            htmlWait: '<div class="ajaxload"><span>Please Wait &hellip;</span></div>',
            htmlConfirm: '<h1>Confirm <a href="" onclick="$.hideModal(\'' + popupID + '\');return false;" >Cancel</a></h1>'
        }, options || {});

        var z = settings.zIndexBase;
        var $body = $("body");

        // ======================================================================================================
        // Begin Curtain Overlay
        // ======================================================================================================
        if (settings.showOverlay) {
            var overlayStyle = "";
            if (settings.elementToOverlay == null) {
                overlayStyle = 'position: fixed;top: 0px;left: 0px;height: 100%;width: 100%;background: ' + settings.overlayColor + ';display:none';
            }
            else {
                var $elementToOverlay = $(settings.elementToOverlay);
                var pos = $elementToOverlay.position();

                overlayStyle = 'position: absolute;top:' + (pos.top - 20) + 'px;left:' + pos.left + 'px;height:' + $elementToOverlay.height() + 'px;width:' + $elementToOverlay.width() + 'px;background: ' + settings.overlayColor + ';display:none';
            };

            // IE issues: 'about:blank' fails on HTTPS and javascript:false is s-l-o-w
            // (hat tip to Jorge H. N. de Vasconcelos)
            var iframeSrc = /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank';
            //($.browser.msie
            var $iframe = $('<iframe id="modal-overlay-iframe" style="' + overlayStyle + ';z-index:' + (z++) + ';border:none;margin:0;padding:0;" src="' + iframeSrc + '"></iframe>');

            var $overlay = $('<div id="modal-overlay" style="' + overlayStyle + ';z-index:' + (z++) + ';"></div>');

            $body.append($iframe).append($overlay);
            $iframe.css("opacity", 0.0).show();
            $overlay.css("opacity", settings.overlayOpacity).fadeIn(settings.fadeInSpeed);
        }

        // ======================================================================================================
        // Begin Popup Handling
        // ======================================================================================================
        var $popup = $("#" + popupID);
        if ($popup.size() == 0) {
            $popup = $("<div></div>").attr("id", popupID);
            $body.append($popup);
        }

        var $anchor = null;
        if (settings.anchorSelector == null) {
            settings.popupPosition = "fixed";
            // alert("noanchor");
        }
        else {
            $anchor = $(settings.anchorSelector).css("position", "relative").append($popup);
        };
        //Init or ReInit popup
        $popup.css({ 'margin': 0, 'position': settings.popupPosition });

        if (settings.width) {
            $popup.css('width', settings.width + 'px');
        }

        switch (type) {
            case 1: //Dynamic Html
                $popup.html(settings.html);
                // if (settings.allowClose) {
                //  $popup.prepend('<div style="text-align:right"><a href="" onclick="$.hideModal(\'' + popupID + '\');return false;" >Close</a></div>');
                // };
                break;
            case 2: //Wait
                $popup.html(settings.htmlWait);
                settings.locked = true; //Force lock
                break;
            case 3: //Confirm
                $popup.html(settings.htmlConfirm);
                settings.locked = true; //Force lock
                break;
            case 4: //Html from Selector
                $popup.find("a.CLOSE").bind("click", function (e) {
                    $.hideModal(popupID);
                    return false;
                });
                break;

        };

        var left = 0;
        switch (settings.popupHAlign) {
            case 1: //"left"
                left = ($anchor == null) ? 0 : -parseInt($popup.outerWidth());
                break;
            case 2: //"center"
                left = parseInt(($.viewport.width() - $popup.outerWidth()) / 2);
                break;
            case 3: //"right"
                left = ($anchor == null) ? (parseInt($.viewport.width()) - $popup.outerWidth()) : parseInt($anchor.outerWidth());
                break;
        };

        var top = 0;
        switch (settings.popupVAlign) {
            case 1: //"top"
                top = ($anchor == null) ? 0 : -parseInt($popup.outerHeight());
                break;
            case 2: //"middle"
                if ($anchor == null) {
                    top = parseInt(($.viewport.height() - $popup.outerHeight()) / 2);
                }
                else {
                    top = parseInt(($anchor.outerHeight() - $popup.outerHeight()) / 2);
                };
                break;
            case 3: //"bottom"
                top = ($anchor == null) ? (parseInt($.viewport.height()) - $popup.outerHeight()) : parseInt($anchor.outerHeight());
                break;
        }


        $popup.css({ "z-index": (z++), "left": left + "px", "top": (top < 20 ? 20 : top) + "px" }).show();
        if (!settings.locked) {
            $("#modal-overlay").bind("click.modalPopup", function () {
                $.hideModal(popupID);
            });
        };
    };

    $.hideModal = function (popupID) {
        $("#modal-overlay").unbind("click.modal").remove();
        $("#modal-overlay-iframe").remove();
        $("#" + popupID).hide();
    };


    //===========================================================================================
    //Credit Card Type
    //===========================================================================================
    $.initCreditCardType = function (selector) {

        var $creditCardIcons = $("#creditCardIcons img");
        $(selector).bind("keyup", function (e) {
            $creditCardIcons.each(function (i) {
                this.src = this.src.replace("-on", "-off");
            });
            var creditCardType = $.getCreditCardType($(this));
            switch (creditCardType) {
                case 1: $("#visa").attr("src", "/Images/visa-on.gif"); break;
                case 2: $("#mastercard").attr("src", "/Images/mastercard-on.gif"); break;
                case 3: $("#amex").attr("src", "/Images/amex-on.gif"); break;
                case 4: $("#discover").attr("src", "/Images/discover-on.gif"); break;
            };
        }).trigger("keyup");
    };

    $.getCreditCardType = function (jTextbox) {
        var textboxValue = jTextbox.val();
        if (textboxValue.match(/^4[0-9]{12}(?:[0-9]{3})?$/)) {
            return 1; //Visa
        } else if (textboxValue.match(/^5[1-5][0-9]{14}$/)) {
            return 2;  //MasterCard
        } else if (textboxValue.match(/^3[47][0-9]{13}$/)) {
            return 3;  //Amex
        } else if (textboxValue.match(/^6(?:011|5[0-9]{2})[0-9]{12}$/)) {
            return 4;  //Discover
        };
        return 0;
    };

    //===========================================================================================

    $.showHide = function (contentSelector, valuesSelector, options) {

        var execute = function (preventSlideIn) {

            if ($(valuesSelector + ":checked").val() == 0) {
                if (settings.slideIn && !preventSlideIn) {
                    $(contentSelector).slideDown(settings.slideInSpeed);
                }
                else {
                    $(contentSelector).show();
                };
            }
            else {
                $(contentSelector).hide();
            };
        };
        var settings = $.extend({
            slideIn: true,
            slideInSpeed: 200
        }, options || {});

        execute(true);
        $(valuesSelector).bind("click", function (e) {
            execute(false);
        });
    };


    $.maxLengthIndicator = function (textboxSelector, currentCountSelector, maxLength) {

        $(textboxSelector).bind("keyup", function (e) {
            var length = $(this).val().length;
            if (maxLength < length) {
                return false;
            };
            $(currentCountSelector).html(length);
        }).trigger("keyup");
    };



    //===========================================================================================
    // Input Validation
    //===========================================================================================



    $.highlightOnFocus = function (selector) {
        $(selector).find("input[type=text],select,textarea").bind("focus", function () {
            $(this).addClass("hasFocus");
        }).bind("blur", function () {
            $(this).removeClass("hasFocus");
        });
    };

    $.displayMessage = function (selectorArray, message) {

        for (var i = 0; i < selectorArray.length; i++) {
            var selector = selectorArray[i];
            if (selector.substring(0, 1) !== "#") { selector = "#" + selector; }
            var $message = $(selector);
            if ($message.size() > 0) {
                if (message.length > 0) {
                    $message.html(message).show();
                }
                else {
                    $message.hide();
                }
                break;
            };
        };
    };

    $.formValidation = function (group, buttonSelector, elementsToValidate, displaySettings, options) {

        var me = $.extend({
            cssInvalid: "isInvalid",
            isPostBack: false,
            errorHeader: "Oops&hellip; we found issues with your information.",
            // Server Side error wrapper can be found in Core.Validation.ErrorList.GetJoinedErrorsWithWrapper
            errorWrapper: '<div class="MessageError"><div><img src="/images/error-icon.png" width="48" height="48" /></div><h3>{ErrorHeader}</h3><ul>{ListItems}</ul></div>'
        }, options || {});

        me.groupToValidate = "";
        me.submitted = false;
        me.errorWrapper = me.errorWrapper.replace(/{ErrorHeader}/, me.errorHeader);

        // ----------------------------------------------------------------------------------------------------------
        // Validation methods
        // ----------------------------------------------------------------------------------------------------------
        var methods = {
            required: function (jElement, args) {
                if ($.trim(jElement.val()) == args.defaultValue) {
                    return false;
                };
                return true;
            },
            email: function (jElement) {
                if (!($.trim(jElement.val()).match(/\w+([\-+.']\w+)*@\w+([\-.]\w+)*\.\w+([\-.]\w+)*/))) {
                    return false;
                };
                return true;
            }
        };

        // ----------------------------------------------------------------------------------------------------------
        // Displays the error collection based on the chosen display method
        // ----------------------------------------------------------------------------------------------------------
        var displayErrors = function (messageList) {
            switch (displaySettings.DisplayMethod) {
                case 1: //"JavaScriptAlert"
                    if (messageList.length > 0) {
                        alert(messageList.join("\n"));
                    }
                    break;
                case 2: //"DivPanel"
                    var message = "";
                    if (messageList.length > 0) { message = me.errorWrapper.replace(/{ListItems}/, "<li>" + messageList.join("</li><li>") + "</li>"); };
                    $.displayMessage(displaySettings.CommaSeparatedSelectors, message);
                    break;
                case 3: //"AjaxPopup"
                    var ajaxPopupError = "";
                    if (messageList.length > 0) {
                        ajaxPopupError = me.errorWrapper.replace(/{ListItems}/, "<li>" + messageList.join("</li><li>") + "</li>");
                    };
                    $.showModal('group' + group, 1, { 'html': ajaxPopupError, 'anchorSelector': displaySettings.AnchorSelector, 'width': displaySettings.Width, 'popupHAlign': displaySettings.HAlign, 'popupVAlign': displaySettings.VAlign, 'popupOffsetLeft': displaySettings.OffsetLeft, 'popupOffsetTop': displaySettings.OffsetTop, 'showOverlay': false });
                    break;
            };
        };

        var validateAll = function (allElements) {

            var err = [];
            var hasError = false;
            for (var i = 0; i < allElements.length; i++) {
                var element = allElements[i];
                var $input = $("#" + element.id);
                if ($input.is(":visible")) {
                    for (var j = 0; j < element.rules.length; j++) {
                        var rule = element.rules[j];
                        var isValid = methods[rule.name].call(this, $input, rule);
                        if (!isValid) {
                            err[err.length] = rule.errorMessage;
                            hasError = true;
                            $input.addClass(me.cssInvalid);
                            break; // make sure not to have more than 1 invalid item per control
                        };
                    };
                };
            };
            return err;
        };

        // hook up form submit event for buttons
        $(buttonSelector).click(function (e) {
            me.groupToValidate = group;
        });

        // Handle form submit when user presses the "ENTER" Key
        $("div." + group + " :text,:checkbox,:file,:password,:radio,select").bind('keypress', function (e) {
            var code = (e.keyCode ? e.keyCode : e.which);
            if (code == 13) { //Enter keycode
                //use legacy code to prevent jquery permission error
                $(buttonSelector)[0].click();
                return false;
            };
        });


        if (me.isPostBack) {
            var err = validateAll(elementsToValidate);
            if (err.length > 0) {
                //  if ($.trim($message.html()) != '') { //TODO
                //     $message.append(me.carriageReturn);
                //  };
                //  $message.append(err).show();
                displayErrors(err);
            };
        };


        // Hook up BLUR event for all elments that need to be validated
        for (i = 0; i < elementsToValidate.length; i++) {
            var element = elementsToValidate[i];
            $("#" + element.id).bind("blur", { rules: element.rules }, function (e) {
                $this = $(this).removeClass(me.cssInvalid);  // assume everything is ok
                for (j = 0; j < e.data.rules.length; j++) {
                    var isValid = methods[e.data.rules[j].name].call(this, $this, e.data.rules[j]);
                    if (!isValid) {
                        $this.addClass(me.cssInvalid);
                    };
                };
                // Auto Revalidate on blue
                // Do this only if
                //   - display method is NOT alert, because otherwise the javascript alert would be constantly prompted
                //   - the user has at least tried to submit the form once
                if (!me.isPostBack && displaySettings.DisplayMethod != 1 && me.submitted) {
                    var err = validateAll(elementsToValidate);
                    displayErrors(err);
                };
            });
        };

        $("form").bind("submit", { allElements: elementsToValidate }, function (e) {

            // TODO ???
            if (group != me.groupToValidate) {
                for (i = 0; i < e.data.allElements.length; i++) {
                    $("#" + e.data.allElements[i].id).removeClass(me.cssInvalid);
                };
                return true;
            };

            //indicated that the user has at least tried to submit the form once
            me.submitted = true;

            var err = validateAll(e.data.allElements);
            if (err.length > 0) {
                displayErrors(err);
                return false;
            }
            else {
                $.showModal("submit", 2);
                return true;
            };

        });
    };

    //===========================================================================================
    // Font Size Controller
    //===========================================================================================
    // TODO: Define default resizable tags
    $.fontSizeController = function (controlAreaSelector, controlSelector, options) {

        var cookieName = "jFontSizeController";

        var settings = $.extend({
            currentIndex: 3,
            minIndex: 1,
            maxIndex: 5,
            resizableTags: "p,h2,h3,h4,h5,li"
        }, options || {});

        var $allElements = $(controlAreaSelector).find(settings.resizableTags);

        var changeFontSize = function (adder) {
            settings.currentIndex += adder;
            $allElements.each(function () {
                var $this = $(this);
                var newFontSize = parseInt($(this).css("font-size")) + (adder * 2);
                if (newFontSize < 1) { newFontSize = 1; };
                $this.css("font-size", newFontSize + "px");
                //#if(num==4 || num==5)
                //parags[i].style.lineHeight = (fontsizes[num] + 3) + "px";
            });
            $.cookie(cookieName, settings.currentIndex, { expires: 30 });
        };


        if ($.cookie(cookieName) && ($.cookie(cookieName) >= settings.minIndex && $.cookie(cookieName) <= settings.maxIndex)) {
            changeFontSize(parseInt($.cookie(cookieName)) - settings.currentIndex);
        };

        var $controlSelector = $(controlSelector);

        var $increaseSelector = $controlSelector.find("a.increase").click(function (e) {
            if (settings.currentIndex < settings.maxIndex) {
                changeFontSize(1);
            };
            return false;
        });

        var $decreaseSelector = $controlSelector.find("a.decrease").click(function (e) {
            if (settings.currentIndex > settings.minIndex) {
                changeFontSize(-1);
            };
            return false;
        });

    };

    $.stateLoader = function (countryDropDownSelector, stateDropDownSelector, options) {

        var me = $.extend({
            hasPleaseSelect: true,
            selectedValue: 0
        }, options || {});

        me.popupID = "stateLoader";
        var initialLoad = true;

        var $stateDropDown = $(stateDropDownSelector);


        var success = function (result) {
            $stateDropDown.empty();
            for (var i = 0; i < result.length; i++) {
                $stateDropDown.append($('<option></option>').val(result[i].StateID).html(result[i].Name));
            };
            $stateDropDown.val(me.selectedValue);
            if (initialLoad == true) {
                initialLoad = false;
            }
            else {
                $.hideModal(me.popupID);
            };
        };
        var failure = function (err) {
            if (initialLoad == true) {
                initialLoad = false;
            }
            else {
                $.hideModal(me.popupID);
            };
            alert(err.Message);
        };

        var $countryDropDown = $(countryDropDownSelector).bind("change", function (e) {
            loadStates();
        });

        var loadStates = function () {
            if (!initialLoad) {
                $.showModal(me.popupID, 2);
            };

            $.myAjax("/WS/Country.asmx", "GetStatesByCountryID", success, failure, { data: "{ 'countryID': '" + $countryDropDown.val() + "', 'hasPleaseSelect': " + me.hasPleaseSelect + " }" });


        };
        loadStates();

    };


    $.keepSessionAlive = function (interval, options) {
        var settings = $.extend({
            numberOfTries: 0
        }, options || {});

        var i = 0;
        var timer = $.timer(interval, function () {
            if (settings.numberOfTries === 0 || i < settings.numberOfTries) {
                $.myAjax('/WS/KeepSessionAlive.asmx', 'Request');
                i += 1;
            }
            else {
                $.clearTimer(timer);
            };
        });
    };

    //===========================================================================================
    // END Input Validation
    //===========================================================================================

    //===========================================================================================
    // Cookies
    //===========================================================================================
    // http://plugins.jquery.com/project/cookie
    // Examples
    // http://www.electrictoolbox.com/jquery-cookies/

    // Alternative with JSON parsing
    // http://joncom.be/code/jquery-jookie/
    //===========================================================================================

    /**
    * Cookie plugin
    *
    * Copyright (c) 2006 Klaus Hartl (stilbuero.de)
    * Dual licensed under the MIT and GPL licenses:
    * http://www.opensource.org/licenses/mit-license.php
    * http://www.gnu.org/licenses/gpl.html
    *
    */

    /**
    * Create a cookie with the given name and value and other optional parameters.
    *
    * @example $.cookie('the_cookie', 'the_value');
    * @desc Set the value of a cookie.
    * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
    * @desc Create a cookie with all available options.
    * @example $.cookie('the_cookie', 'the_value');
    * @desc Create a session cookie.
    * @example $.cookie('the_cookie', null);
    * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
    *       used when the cookie was set.
    *
    * @param String name The name of the cookie.
    * @param String value The value of the cookie.
    * @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
    * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
    *                             If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
    *                             If set to null or omitted, the cookie will be a session cookie and will not be retained
    *                             when the the browser exits.
    * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
    * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
    * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
    *                        require a secure protocol (like HTTPS).
    * @type undefined
    *
    * @name $.cookie
    * @cat Plugins/Cookie
    * @author Klaus Hartl/klaus.hartl@stilbuero.de
    */

    /**
    * Get the value of a cookie with the given name.
    *
    * @example $.cookie('the_cookie');
    * @desc Get the value of a cookie.
    *
    * @param String name The name of the cookie.
    * @return The value of the cookie.
    * @type String
    *
    * @name $.cookie
    * @cat Plugins/Cookie
    * @author Klaus Hartl/klaus.hartl@stilbuero.de
    */
    $.cookie = function (name, value, options) {

        var setCookie = function (val, expires) {
            if (val === null) {
                val = '';
            }
            if (expires && (typeof expires == 'number' || expires.toUTCString)) {
                var date;
                if (typeof expires == 'number') {
                    date = new Date();
                    date.setTime(date.getTime() + (expires * 24 * 60 * 60 * 1000));
                } else {
                    date = expires;
                }
                expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
            }
            // CAUTION: Needed to parenthesize options.path and options.domain
            // in the following expressions, otherwise they evaluate to undefined
            // in the packed version for some reason...
            var path = options.path ? '; path=' + (options.path) : '';
            var domain = options.domain ? '; domain=' + (options.domain) : '';
            var secure = options.secure ? '; secure' : '';
            document.cookie = [name, '=', encodeURIComponent(val), expires, path, domain, secure].join('');
        };

        if (typeof value != 'undefined') { // name and value given, set cookie
            options = options || {};

            if (value !== null) {
                // clear cookie and recreate
                setCookie(null, -1);
                setCookie(value, options.expires);
            }
            else {
                // clear cookie
                setCookie(null, -1);
            };

        } else { // only name given, get cookie
            var cookieValue = null;
            if (document.cookie && document.cookie != '') {
                var cookies = document.cookie.split(';');
                for (var i = 0; i < cookies.length; i++) {
                    var cookie = jQuery.trim(cookies[i]);
                    // Does this cookie string begin with the name we want?
                    if (cookie.substring(0, name.length + 1) == (name + '=')) {
                        cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                        break;
                    };
                };
            };
            return cookieValue;
        };
    };


    $.setTimeZoneOffsetCookie = function (cookieName) {
        var offSet = new Date().getTimezoneOffset();
        $.cookie(cookieName, offSet, { expires: 30, path: '/' });
    };

    $.fn.createToolTips = function (xOffset, yOffset) {
        if (typeof (xOffset) == 'undefined') xOffset = 15;
        if (typeof (yOffset) == 'undefined') xOffset = 15;
        return this.each(function () {
            $("#C" + this.id).hide();
            $(this).bind("mousemove", function (e) {
                $("#C" + this.id).css("left", (e.pageX + xOffset) + 'px').css("top", (e.pageY + yOffset) + 'px').show();
            });
            $(this).bind("mouseout", { _this: this }, function (e) {
                $("#C" + e.data._this.id).hide();
            });
        }).css("cursor", "default");
    };

    // http://www.mredkj.com/javascript/nfbasic.html
    $.formatNumber = function (number, decimalPlaces, show1000Separator) {
        if (isNaN(number)) { return NaN; };
        if (decimalPlaces == undefined) { decimalPlaces = 0 };
        number = parseFloat(number).toFixed(decimalPlaces);
        if (show1000Separator) {
            number += '';
            var x = number.split('.');
            var x1 = x[0];
            var x2 = x.length > 1 ? '.' + x[1] : '';
            var rgx = /(\d+)(\d{3})/;
            while (rgx.test(x1)) {
                x1 = x1.replace(rgx, '$1' + ',' + '$2');
            };
            number = x1 + x2;
        };
        return number;
    };

    $.fn.htmlEncode = function () {
        return this.each(function () {
            this.value = escape(this.value);
        });
    };

    $.fn.htmlDecode = function () {
        return this.each(function () {
            this.value = unescape(this.value);
        });
    };

    // Admin menu
    $.createMenu = function (elementID, options) {

        var settings = $.extend({
            timeout: 500
        }, options || {});

        settings.timer = null;
        settings.currentSubItem = null;

        settings.close = function () {
            if (settings.currentSubItem) settings.currentSubItem.css('visibility', 'hidden');
        };

        $('#' + elementID + ' > ul > li').bind('mouseover', function () {

            if (settings.timer) {
                window.clearTimeout(settings.timer);
                settings.timer = null;
            };
            settings.close();
            settings.currentSubItem = $(this).find('ul').css('visibility', 'visible');
        }).bind('mouseout', function () {
            settings.timer = window.setTimeout(settings.close, settings.timeout);
        });
    };

    $.gallery = function (popupID, $wrapper, initIndex, galleryItems, options) {
        var settings = $.extend({
            showIndex: true
        }, options || {});

        settings.currentIndex = initIndex;
        settings.$Title = $wrapper.find("#" + popupID + "_title");
        settings.$Image = $wrapper.find("#" + popupID + "_img");
        settings.$Caption = $wrapper.find("#" + popupID + "_caption");
        settings.$Index = $wrapper.find("#" + popupID + "_index");
        settings.$CurrentPicture = $wrapper.find("#" + popupID + "_currentPicture");
        $wrapper.find("#" + popupID + "_totalPictures").html(galleryItems.length);
        settings.$NextImg = $wrapper.find("#" + popupID + "_nextImg");
        settings.$PreviousImg = $wrapper.find("#" + popupID + "_previousImg");
        settings.$SpanPreviousImg = $wrapper.find("#" + popupID + "_spanPreviousImg");
        settings.$SpanNextImg = $wrapper.find("#" + popupID + "_spanNextImg");

        var changeImage = function (idx) {

            settings.currentIndex += idx;
            settings.$Title.html(galleryItems[settings.currentIndex].Title);
            settings.$Image.attr({ "src": galleryItems[settings.currentIndex].ImageUrl });
            settings.$Caption.html(galleryItems[settings.currentIndex].Caption);

            if (!settings.showIndex) {
                settings.$Index.css("display", "none");
            }
            else {
                settings.$CurrentPicture.html(settings.currentIndex + 1);
            }

            if (settings.currentIndex >= (galleryItems.length - 1)) {
                settings.$NextImg.hide().removeAttr("href").unbind();
                settings.$SpanNextImg.show();
            }
            else {
                settings.$SpanNextImg.hide();
                settings.$NextImg.show().unbind().bind("click", function (e) {
                    changeImage(1);
                    return false;
                }).attr("href", "#");
            }

            if (settings.currentIndex == 0) {
                settings.$PreviousImg.hide().removeAttr("href").unbind();
                settings.$SpanPreviousImg.show();
            }
            else {
                settings.$SpanPreviousImg.hide();
                settings.$PreviousImg.show().unbind().bind("click", function (e) {
                    changeImage(-1);
                    return false;
                }).attr("href", "#"); ;
            }

        }

        changeImage(0);

    };

    $.galleryPopup = function (popupID, popupTriggers, galleryItems, options) {

        var settings = $.extend({
            width: 600
        }, options || {});

        settings.galleryWrapper = $("#" + popupID);

        // make the click binding a separate function so we can reuse it in case we have more than one anchor tag that opens the popup
        var on_click = function (_this, i) {
            $(_this).bind("click", { index: i }, function (e) {
                $.gallery(popupID, settings.galleryWrapper, e.data.index, galleryItems);
                $.showModal(popupID, 4, { width: settings.width, 'showOverlay': true });
                return false;
            });
        };

        for (var i = 0; i < popupTriggers.length; i++) {
            $(popupTriggers[i]).each(function (i) {
                on_click(this, i);
            });
        }

    };



})(jQuery);