(function ($) {
    $.fn.photoNav = function (options) {
        function pageTo(n, pager, dist) {
            var viewer = [];
            n = parseInt(n);
            
            if (n == 0) n = 1;
            
            if (n) {
                e = n + dist;
                s = n - dist;
                if (s < pager[0]) {
                    e += (pager[0] - s);
                    s = pager[0];
                    n = s;
                }
                
                if (e > pager[pager.length-1]) {
                    s -= (e - pager[pager.length-1]);
                    e = pager[pager.length-1];
                    n = e;
                }
                
                viewer = [];
                for (var i = s; i <= e; i++) {
                    viewer.push(pager[i-1]);
                }
            }
            
            return [viewer, pager[n-1]];
        }

        var defaults = {
            showAll: false,
            start: 1,
            end: 3,
            active: 1,
            photoList: null,
            photo: null
        };
        
        var settings = $.extend({}, defaults, options);

        return this.each(function () {
            if (this.nodeName != 'UL') {
                throw new Error('needs to be set against a list');
            }
            
            var $$ = $(this);
            var pager = [];
            this.settings = $.extend({}, defaults, options);
            var match = null;
            var dist = null;
            var allHTML = (this.settings.showAll ? '<li><a class="revealAllPhotos" href="?image=all#allUploadedPhotos">All</a></li> ' : '');
            this.settings.photo = $('#' + settings.photo);
            
            function drawNav() {
                $$.empty();

                this.settings.end = settings.end;

                /* initial setup and hooks */            
                if (match = this.className.match(/target:([\S]*)/)) {
                    this.settings.photoList = $('#' + match[1] + ' img');
                } else {
                    this.settings.photoList = $('#' + settings.photoList + ' img');
                }

                this.settings.max = this.settings.photoList.length;

                var s = this.settings.start;
                if (this.settings.end >= this.settings.max) {
                    this.settings.end = this.settings.max;
                }

                var e = (this.settings.end >= this.settings.max ? this.settings.max : this.settings.end);
                dist = (e-s)/2;
                var view = (this.settings.end - this.settings.start) + 1;

                var html = '<li class="leftArrow"><a class="previous" href="?image=previous">&lt;</a></li><li class="rightArrow"><a href="?image=next" class="next">&gt;</a></li>';
                
                $$.append(html);

                pager = [];
                for (var i = 0; i < this.settings.max; i++) {
                    pager.push(i+1);
                }
                
                var list = pageTo(settings.active, pager, dist);
                pagerToHTML.call(this, list[0], list[1]);
            }
                        
            function pagerToHTML(pager, selected) {
                var html = '';
                for (var i = 0; i < pager.length; i++) {
                    html += '<li><a href="?image=' + pager[i] + '">' + pager[i] + '</a></li> ';
                }

                $('li:gt(1)', this).remove().end().append(html);
                
                if (allHTML) {
                    $('li:last', this).after(allHTML);
                }
                
                this.selected = selected;
                $('li:eq(' + (pager.indexOf(this.selected) + 2) + ')', this).addClass('active');
                this.settings.photo.attr('src', this.settings.photoList[selected - 1].src);
                
                if (typeof settings.callback == 'function') {
                    settings.callback.call(this, this.selected);
                }
            }
            
            $$.click(function (e) {
                var target = e.target;
                
                // we're using ems for text replacement
                if (target.nodeName == 'EM') target = target.parentNode;
                
                if (target.nodeName == 'A') {
                    // important the image is the last variable
                    var n = target.search.substring(target.search.lastIndexOf('=') + 1);
                    
                    if (n == 'all') {
                        $(target.hash).slideDown();
                        $(this).unbind('click').parents('ul:first').hide();
                    } else {
                        if (n == 'next') {
                            n = this.selected+1;
                        } else if (n == 'previous') {
                            n = this.selected-1;
                        }

                        var list = pageTo(n, pager, dist);
                        pagerToHTML.call(this, list[0], list[1]);                        
                    }
                }

                return false;
            });
            
            // init
            $$.bind('update', drawNav).trigger('update');
        });
    };
})(jQuery);