(function($) {
    $.fn.gallery = function(opts) {
        $.fn.gallery.defaults = {
            sourceSelector: 'h1:first,div.gallery:first',
            galleryClass: 'gallery-dynamic',
            buildingClass: 'gallery-building',
            loadingClass: 'gallery-loading-icon',
            target: 'body',
            useMask: true,
            maskClass: 'gallery-mask',
            maskTarget: true,
            maskOpacity: '0.8',
            indexMaskOpacity: '0.7',
            useShadows: true,
            galleryZ: 50000,
            maskZ: 49999,
            currentZ: 45000,
            revealZ: 44999,
            slideSpeed: 250,
            fullImageSelector: 'img.full',
            thumbnailSelector: 'img.thumbnail',
            picsPerPage: 5
        };
        var opts = $.extend({}, $.fn.gallery.defaults, opts);

        var target = $(opts.target);
        if (!target) return this;

        return this.each(function(idx) {
            var link = this;
            var url = $(this).attr("href") + " " + opts.sourceSelector;
            $('<div />').load(url, null, function(responseText, textStatus, XMLHttpRequest) {
                if (textStatus != "success") return false;
                var gallery = null;
                var galleryTitle = null;
                var galleryID = GenerateRandomID("gallery");

                if ($(this).children().length == 2) { //Looks like a gallery title was included
                    galleryTitle = $(this).children("h1").remove();
                    gallery = $(this).children("div.gallery").remove();
                } else gallery = $(this).children().remove();
                if (!gallery.length) return false;
                gallery.css("z-index", opts.galleryZ).removeAttr("class").addClass(opts.galleryClass).addClass(opts.buildingClass).attr("id", galleryID);
                $(link).data("gallery", gallery.attr("id"));
                target.append(gallery);
                gallery = $("#" + galleryID);
                var index = gallery.children("ul").remove().addClass("gallery-index");
                var pics = index.children("li");

                var numPics = pics.length;
                var indexWrapper = $('<div class="gallery-index-wrapper" />').append(index);

                indexWrapper.data("numPics", numPics).data("numPages", Math.ceil(numPics / opts.picsPerPage)).data("currentPage", 1);
                gallery.append('<a class="gallery-close" /><div class="gallery-current-item" /><div class="gallery-reveal-item" /><a class="gallery-previous-item" /><a class="gallery-next-item" />').append(indexWrapper).append('<div class="gallery-item-content" />');
                if (galleryTitle) gallery.prepend("<h1>" + galleryTitle.html() + "</h1>");
                var offset = 0;
                pics.each(function(idx) {
                    $(this).css({ top: 0, left: offset });
                    offset += $(this).outerWidth(true);
                    $(this)
                        .click(function() {
                            $(this).children(".gallery-thumb-mask").remove();
                            var gallery = $(this).closest(".gallery-dynamic");
                            Select(gallery, idx);
                        })
                       .hover(
                            function() {
                                if ($(this).hasClass("gallery-item-current")) return;
                                $('<div class="gallery-thumb-mask" />').css({ position: 'absolute', opacity: 0.5, top: 0, left: 0, height: $(this).height(), width: $(this).width() }).mouseleave(function() { $(this).remove(); }).appendTo($(this));
                            },
                            function() {
                                $(this).children(".gallery-thumb-mask").remove();
                            }
                       );
                }).children().not("img.thumb").hide();

                gallery
                    .children("a.gallery-close")
                        .click(function() {
                            Close(gallery);
                        }).hover(
                            function() {
                                $(this).addClass("gallery-close-hover")
                            },
                            function() {
                                $(this).removeClass("gallery-close-hover");
                            }
                        );
                gallery.children("a.gallery-previous-item").click(function() {
                    if ($(this).hasClass("gallery-previous-item-disabled")) return;
                    Slide(gallery, 1);
                }).hover(
                    function() {
                        if (!$(this).hasClass("gallery-previous-item-disabled")) $(this).addClass("gallery-previous-item-hover");
                    },
                    function() {
                        $(this).removeClass("gallery-previous-item-hover");
                    }
                );
                gallery.children("a.gallery-next-item").click(function() {
                    if ($(this).hasClass("gallery-next-item-disabled")) return;
                    Slide(gallery, -1);
                }).hover(
                    function() {
                        if (!$(this).hasClass("gallery-next-item-disabled")) $(this).addClass("gallery-next-item-hover");
                    },
                    function() {
                        $(this).removeClass("gallery-next-item-hover");
                    }
                );
                gallery.children(".gallery-current-item").css("z-index", opts.currentZ);
                gallery.children(".gallery-reveal-item").css("z-index", opts.revealZ);

                if (numPics < opts.picsPerPage) gallery.children("a.gallery-next-item").addClass("gallery-next-item-disabled");
                gallery.children("a.gallery-previous-item").addClass("gallery-previous-item-disabled");
                gallery.hide().removeClass(opts.buildingClass);
            });
            $(this).click(function() {
                var galleryID = "#" + $(this).data("gallery");
                var gallery = $(galleryID);
                if (!gallery) return true;
                Select(gallery, 0, true);
                Slide(gallery, 1, true);

                var windowHeight = $(window).height();
                var windowWidth = $(window).width();
                var scrollTop = $(document).scrollTop();
                var galleryHeight = gallery.outerHeight();
                var galleryWidth = gallery.outerWidth();

                if (opts.useMask) {
                    var mask = $('<div />').addClass(opts.maskClass);
                    var maskContainer = opts.maskTarget ? $(opts.target) : $("body");
                    mask.css({
                        position: "absolute",
                        top: maskContainer.css("padding-top"),
                        left: maskContainer.css("padding-left"),
                        opacity: "0",
                        width: maskContainer.width(),
                        height: maskContainer.height(),
                        zIndex: opts.maskZ
                    }).click(function() { Close(gallery); });
                    maskContainer.append(mask);
                    mask.fadeTo("fast", opts.maskOpacity); //, function() { slidershow.fadeIn("fast"); });
                }

                if (galleryHeight > windowHeight) gallery.css("top", 0);
                else gallery.css("top", (windowHeight / 2 - galleryHeight / 2) + scrollTop);
                gallery.css("left", (windowWidth / 2) - (galleryWidth / 2));
                if ($.browser.msie) gallery.show();
                else gallery.fadeIn("normal");

                return false;
            });
        });
        function Select(gallery, idx, skipAnim) {
            var indexWrapper = $(gallery).children(".gallery-index-wrapper");
            var li = $("ul.gallery-index", indexWrapper).children("li:nth(" + idx + ")");
            if (li.hasClass("gallery-item-current")) return;
            li.siblings().removeClass("gallery-item-current").children(".gallery-index-item-mask,.gallery-index-item-mask-count").remove();
            var textual = li.children().not("img.thumb,img.full").clone().show();
            var img = li.children("img.full").clone().removeClass().show();

            var current = gallery.children(".gallery-current-item");
            var reveal = gallery.children(".gallery-reveal-item");
            var content = gallery.children(".gallery-item-content");
            var mask = $('<div class="gallery-index-item-mask" />').css("opacity", opts.indexMaskOpacity);
            var count = $('<div class="gallery-index-item-mask-count" />').text((idx + 1) + " of " + indexWrapper.data("numPics"));
            li.append(mask);
            li.append(count);
            count.css({
                width: mask.css("width"),
                left: 0,
                top: (parseInt(mask.css("height")) / 2 - parseInt(count.css("font-size")) / 2)
            });

            if (skipAnim) {
                reveal.empty();
                current.empty().append(img);
                content.empty().append(textual).show();
            } else {
                reveal.append(img);
                current.fadeOut("fast", function() {
                    $(this).remove();
                    reveal.addClass("gallery-current-item").removeClass("gallery-reveal-item").css("z-index", opts.currentZ);
                    $('<div class="gallery-reveal-item" />').css("z-index", opts.revealZ).insertAfter(reveal);
                });
                content.hide().empty().append(textual).fadeIn("fast");
            }

            $(li).addClass("gallery-item-current");
        }
        function Slide(gallery, dir, reset) {

            var indexWrapper = gallery.children(".gallery-index-wrapper");
            var index = indexWrapper.children("ul.gallery-index");

            if (index.filter(":animated").length != 0) return;

            var numPages = indexWrapper.data("numPages");
            var currentPage = indexWrapper.data("currentPage");
            var nextPage = reset ? 1 : currentPage + dir * -1;
            var width = indexWrapper.outerWidth();
            var left = index.position().left;
            var offsetLeft = (left + ((index.children("li").outerWidth(true) * opts.picsPerPage) * dir)) + "px";

            if (reset) index.css("left", 0);
            else index.animate({ left: offsetLeft }, opts.slideSpeed, "swing");

            indexWrapper.data("currentPage", nextPage);
            currentPage = indexWrapper.data("currentPage");

            var prev = gallery.children("a.gallery-previous-item");
            var next = gallery.children("a.gallery-next-item");

            if (currentPage == 1) prev.addClass("gallery-previous-item-disabled");
            else prev.removeClass("gallery-previous-item-disabled");

            if (currentPage == numPages) next.addClass("gallery-next-item-disabled");
            else next.removeClass("gallery-next-item-disabled");
        }
        function Close(gallery) {
            var mask = $("." + opts.maskClass);
            if ($.browser.msie) {
                gallery.hide();
                mask.remove();
            } else {
                gallery.fadeOut("fast", function() { $(this).hide() });
                mask.fadeOut("normal", function() { $(this).remove(); });
            }
        }
    };
    $(function() {
        $("a.gallery").gallery();
    });
})(jQuery);