        
            
            (function($) {
                $.fn.fotoGallery = function(options) {
                    var me = this;
                    var defaults = {
                        photos: [],
                        categories: [],
                        onSelect: null,
                        collapsedHeight: "345px"
                    };

                    var options = $.extend(defaults, options);

                    function preloadImages(el, photos, onComplete) {
                        var imagesLoaded = 0;
                        var lis = $("ul.gallery-viewport", el).children();

                        for (var i = 0; i < photos.length; i++) {
                            var photo = photos[i];
                            var img = new Image(photo.width_sq, photo.height_sq);
                            $(img).load(function(e) {
                                imagesLoaded++;
                                if (imagesLoaded == photos.length) {
                                    onComplete();
                                }
                            });
                            img.src = photo.url_sq;
                            $("a", lis[i]).html(img);
                        }
                    }

                    function filterPhotos(photos) {
                        var matches = [];
                        for (var i = 0; i < photos.length; i++) {
                            var photo = photos[i];
                            //console.log(photo.tags);
                            var tags = photo.tags.split(" ");

                            for (var j = 0; j < options.categories.length; j++) {
                                var tagCat = options.categories[j].replace(/\s/g, "").replace(/&/g, "and").toLowerCase();
                                //console.log($.inArray(options.categories[j], tags));
                                //console.log(options.categories[j] + ":" + tags);
                                if ($.inArray(tagCat, tags) > -1) {
                                    //console.log(options.categories[j] + ":" + tags);
                                    photo.category = options.categories[j];
                                    matches[matches.length] = photo;
                                }
                            }
                        }
                        matches.sort(function() { return 0.5 - Math.random()});
                        return matches;
                    }

                    return this.each(function() {

                        var el = $(this);
                        //var a = ["all"];
                        options.categories = ["all"].concat(options.categories);
                        // Show loading screen
                        el.append("<div class=\"loading-panel\" style=\"height: " + (options.collapsedHeight + 37) + "px; position: absolute; z-index: 99;\"></div>");

                        // filter out photos without matching tags
                        $.getJSON(options.flickApiCallUrl, function(data) {

                            var photos = filterPhotos(data.photos.photo);

                            // Gallery markup
                            var markup = [];

                            markup[markup.length] = "<div class=\"gallery-viewport-container\" style=\"overflow:hidden;\">";
                            markup[markup.length] = "<ul class=\"gallery-viewport\">";
                            for (var i = 0; i < photos.length; i++) {
                                //var photo = photos[i];
                                //console.log(photo.tags);
                                markup[markup.length] = "<li><a href=\"javascript:;\"></a></li>";
                            }
                            markup[markup.length] = "</ul>";
                            markup[markup.length] = "<div style=\"clear:both;\"></div>";
                            markup[markup.length] = "</div>";

                            markup[markup.length] = "<ul class=\"gallery-categories\">";
                            for (var i = 0; i < options.categories.length; i++) {
                                markup[markup.length] = "<li><a href=\"javascript:;\">" + options.categories[i] + "</a></li>";
                            }
                            markup[markup.length] = "</ul>";
                            markup[markup.length] = "<div class=\"gallery-buttons\"><a class=\"toggle-button\" href=\"javascript:;\">View Full Gallery</a></div>";

                            el.append(markup.join(""));

                            // Set initial gallery state
                            $("div.gallery-viewport-container", el).css("height", options.collapsedHeight);
                            $("ul.gallery-categories", el).toggle();
                            //console.log(markup.join(""));

                            preloadImages(el, photos, function() {
                                $("div.loading-panel", el).toggle();
                                //console.log($("div.gallery-viewport-container", el).height() +":" + $("div.gallery-viewport-container", el).css('height'));
                                var expandedHeight = $("ul.gallery-viewport", el).height();
                                var isExpanded = false;

                                // Expand/Collapse handler
                                $("div a.toggle-button", el).click(function() {
                                    if (!isExpanded) {
                                        $(this).text("Hide Full Gallery").addClass("expanded");
                                        $("div.gallery-viewport-container", el).animate({ height: expandedHeight }, "slow", function() {
                                            $("ul.gallery-categories", el).toggle();
                                        });
                                    }
                                    else {
                                        $(this).text("View Full Gallery").removeClass("expanded");
                                        $("ul.gallery-viewport li a img", el).removeClass("inactive");
                                        $("ul.gallery-categories", el).toggle();
                                        $("div.gallery-viewport-container", el).animate({ height: options.collapsedHeight }, "slow");
                                    }
                                    isExpanded = !isExpanded;
                                });

                                // Image click handler
                                $("ul.gallery-viewport li a", el).click(function(e) {
                                    if ($.isFunction(options.onSelect) && !$("img", this).hasClass("inactive")) {
                                        var items = $(this).parent().parent().children();
                                        var activePhotos = $("img:not(.inactive)", items);
                                        var selectedIndex = $(activePhotos).index($("img", this));
                                        var p = [];
                                        for (var i = 0; i < activePhotos.length; i++) {
                                            var item = $(activePhotos[i]).parent().parent();
                                            p[i] = photos[$(items).index(item)];
                                        }

                                        options.onSelect({ selected: selectedIndex, photos: p });
                                    }
                                });

                                // Category menu click handler
                                $("ul.gallery-categories li a", el).click(function(s) {

                                    var li = $(this).parent();
                                    var ul = li.parent();

                                    //ul.find("li a").css('background', '');
                                    //$(this).css('background', '#aaccaa');

                                    var category = options.categories[ul.children().index(li)];

                                    var images = $("ul.gallery-viewport li a img", el);
                                    $(images).removeClass("inactive");


                                    if (category != "all") {
                                        for (var i = 0; i < photos.length; i++) {
                                            if (photos[i].category != category) {
                                                $(images[i]).addClass("inactive");
                                            }
                                        }
                                    }
                                });

                            });
                        });

                    });
                }
            })(jQuery);