(function($){

var ns = "PhotoSlide";

var zIndex = {
  overlay: 900,
  loading: 910,
  image: 950,
  button: 999
};

window[ns] = function ( buffer, index, callback ) {
  this.buffer = buffer;
  this.callback = callback;
  this.index = index;
  
  this.prepare();
  this.observe();
  
  this.position();
  this.start();
}

window[ns].prototype = {
  
  prepare: function () {
    // overlay
    this.overlay = $('<div>').hide().appendTo('body');
    this.overlay.css({
      position: 'absolute',
      top: 0, left: 0,
      zIndex: zIndex.overlay,
      background: 'black',
      opacity: 0.8
    });
    
    // loading
    this.loading = $('<div>').hide().addClass('loading-32').appendTo('body');
    this.loading.css({
      position: 'absolute',
      top: 0, left: 0,
      zIndex: zIndex.loading
    });
    
    // close
    this.closeButton = $('<div>').hide().addClass('close-20').appendTo('body');
    this.closeButton.css({
      position: 'absolute',
      top: 0, left: 0,
      zIndex: zIndex.button,
      cursor: 'pointer'
    });
    
    // next Button
    this.nextButton = $('<div>').hide().addClass('next-20').appendTo('body');
    this.nextButton.css({
      position: 'absolute',
      top: 0, left: 0,
      zIndex: zIndex.button,
      cursor: 'pointer',
      color: 'white'
    });
    
    // prev Button
    this.prevButton = $('<div>').hide().addClass('prev-20').appendTo('body');
    this.prevButton.css({
      position: 'absolute',
      top: 0, left: 0,
      zIndex: zIndex.button,
      cursor: 'pointer',
      color: 'white'
    });
    
    // current image
    this.currentImage = null;
    this.imageCSSreset = {
      opacity: 0.0,
      position: 'absolute',
      top: 0, left: 0,
      zIndex: zIndex.image
    };
    this.loadProxy = $.proxy( this.loaded, this );
    
    // next image
    this.nextImage = null;
    
    // title
    this.title = $('<div>').hide().addClass('image-title').appendTo('body');
    this.title.css({
      position: 'absolute',
      top: 0, left: 0,
      zIndex: zIndex.image,
      color: '#ddd'
    });
  },
  
  observe: function () {
    this.windowObserver = $.proxy( this.resize, this );
    this.closeButton.click( $.proxy( this.exit, this ) );
    $(window).bind('resize', this.windowObserver);
    $(window).bind('scroll', this.windowObserver);
    
    this.nextButton.click( $.proxy( this.go_next, this ) );
    this.prevButton.click( $.proxy( this.go_prev, this ) );
  },
  
  resize: function () {
    this.position();
    this.positionImage( this.currentImage );
  },
  
  position: function () {
    var offset = this.getOffset();

    this.overlay.css({
      width: offset.width, height: offset.height,
      top: offset.top, left: offset.left
    });
    
    this.loading.css({
      top: offset.height / 2 - 16 + offset.top,
      left: offset.width / 2 - 16 + offset.left
    });
    
    this.closeButton.css({
      left: offset.width - 30 + offset.left,
      top:  10 + offset.top
    });
    
    this.nextButton.css({
      width: offset.width / 2,
      height: offset.height - 40,
      left: offset.width / 2 + offset.left,
      top:  40 + offset.top
    });

    this.prevButton.css({
      width: offset.width / 2,
      height: offset.height - 40,
      left: offset.left,
      top:  40 + offset.top
    });
    
  },
  
  go_next: function () {
    var index = this.index + 1;
    if ( index >= this.buffer.length ) return;
    this.loadImage(index);
    this.checkNav();
  },
  
  go_prev: function () {
    var index = this.index - 1;
    if ( index < 0 ) return;
    this.loadImage(index);
    this.checkNav();
  },
  
  start: function () {
    this.overlay.fadeIn();
    this.loading.fadeIn();
    this.closeButton.fadeIn();

    this.loadImage(this.index);
    this.checkNav();
  },
  
  loadImage: function ( index ) {
    if ( this.currentImage ) {
      this.currentImage.fadeOut(function(){$(this).remove();});
      this.loading.fadeIn();
    }
    this.title.hide();
    
    this.nextImage = $('<img>').css(this.imageCSSreset)
                    .appendTo('body')
                    .load( this.loadProxy )
                    .attr('src', this.getSource( index ) );

    this.index = index;
  },
  
  checkNav: function () {
    var hasPrev = this.index != 0;
    var hasNext = this.index != this.buffer.length - 1;
    if ( hasPrev && this.prevButton.is(':hidden') ) {
      this.prevButton.fadeIn();
    } else if ( ! hasPrev && this.prevButton.is(':visible') ) {
      this.prevButton.fadeOut();
    }

    if ( hasNext && this.nextButton.is(':hidden') ) {
      this.nextButton.fadeIn();
    } else if ( ! hasNext && this.nextButton.is(':visible') ) {
      this.nextButton.fadeOut();
    }
  },
  
  loaded: function ( event ) {
    var me = $(event.currentTarget);
    this.loading.fadeOut();
    this.positionImage( me );
    me.delay(10).animate({opacity:1.0});
    
    this.title.html( this.getTitle( this.index ) ).fadeIn();
    
    this.currentImage = this.nextImage;
  },
  
  positionImage: function ( img ) {
    if ( ! img ) return;

    var width  = img.width();
    var height = img.height();
    var offset = this.getOffset();
    
    var top = (offset.height - height) / 2;
    if ( top < 20 ) top = 20;
    top += offset.top;
    
    var left = (offset.width - width) / 2;
    if ( left < 20 ) left = 20;
    left += offset.left;
    
    img.css({ top: top, left: left });

    this.title.css({
      left: left,
      top: top + height + 8
    });

  },
  
  getOffset: function () {
    var win = $(window);
    var doc = $(document);
    
    return {
      width:  win.width(),
      height: win.height(),
      top:    doc.scrollTop(),
      left:   doc.scrollLeft()
    };
  },
  
  getSource: function ( index ) {
    return this.buffer[index].getAttribute('href');
  },
  
  getTitle: function ( index ) {
    return this.buffer[index].getAttribute('title');
  },
  
  exit: function ( event ) {
    var $this = this;
    if ( this.currentImage ) this.currentImage.remove();
    if ( this.nextImage    ) this.nextImage   .remove();
    this.closeButton.remove();
    this.nextButton.remove();
    this.prevButton.remove();
    this.loading.remove();
    this.title.remove();

    this.overlay.fadeOut(function() {
      $this.overlay.remove();
    });
    
    $(window).unbind('resize', this.windowObserver);
    $(window).unbind('scroll', this.windowObserver);
    
    (this.callback || $.noop)();
  }
  
};

})(jQuery);
