/**
 * jQuery Gallery Plugin
 *   http://code.google.com/p/jquery-gallery-plugin/
 *
 * Copyright (c) 2009 Yusuke Horie
 *
 * Released under the MIT License:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * Since  : 0.1.0 - 08/02/2009
 * Version: 0.3.0 - 08/25/2009
 */
(function(jQuery) {

  /** private properties **/

  var _inc = 0;

  /** public methods **/

  jQuery.fn.gallery = function (options) {
    var options = jQuery.extend({}, jQuery.fn.gallery.defaults, options);

    return this.each(function(i, e) {
      var
        $this = jQuery(e),
        id = options.prefix + _inc,
        i = 0,
        n = 0,
        limit = 5,
        step = 1,
        duration = Math.ceil(options.interval*0.3),
        timeId = null;

      var height;
      if (!options.height) {
        if (!parseInt($this.css('height'), 10)) {
          height = '450px';
        } else {
          height = $this.height();
        }
      } else {
        height = options.height;
      }

      var
       // width = (!options.width) ? $this.width(): options.width,
	   width =$this.width();
        paddingTop = parseInt($this.css('padding-top'), 10),
        paddingBottom = parseInt($this.css('padding-bottom'), 10),
        pheight = parseInt(height, 10),
        contentHeight = pheight - options.thumbHeight + paddingTop,
        o = $this.offset(),
        barWidth = jQuery(window).width() - o.left;

      // thumbnail bar
      var barTop = (options.barPosition == 'top') ? paddingTop: contentHeight;

      if (options.toggleBar) {
        if (options.barPosition == 'top') {
          $this.hover(
            function() {
              $('#thumbnails_' + id).animate({top: paddingTop}, {queue: false, duration: 300});
            },
            function() {
              $('#thumbnails_' + id).animate({top: barTop}, {queue: false, duration: 300});
            });
          barTop = (options.thumbHeight + paddingTop) * (-1);
        } else {
          var outerHeight = pheight + paddingTop + paddingBottom;
          $this.hover(
            function() {
              $('#thumbnails_' + id).animate({top: contentHeight}, {queue: false, duration: 300});
            },
            function() {
              $('#thumbnails_' + id).animate({top: outerHeight}, {queue: false, duration: 300});
            });
          barTop = outerHeight;
        }
      }

      $this
        .css({
          width: width,
          height: height,
          zIndex: options.zIndex
        })
        .prepend('<div id="' + id + '"></div>')
        .find('ul')
          .attr('id', 'thumbnails_' + id)
          .addClass(options.barClass)
          .css({
            top: barTop,
            height: options.thumbHeight + 'px',
            width: barWidth + 'px',
            zIndex: options.zIndex + 2000
          })
          .find('li')
            .css({
              width: options.thumbWidth + 'px',
              height: options.thumbHeight + 'px'
            })
            .each(function (index) {
              jQuery.data(this, 'index', index);
            })
            .click(function (event) {
              event.preventDefault();
              if (options.slideshow) clearInterval(timeId);

              if ($.isFunction(options.onSelect))
                options.onSelect.apply(this, [event]);

              var $e = this;
              bar.find('li').each(function (index, e) {
                if (e == $e) {
                  step = index;
                  return false;
                }
              });

              i = jQuery.data(this, 'index');

              // pre load
              for (var j=i; j<i+limit; j++) {
                var o = pictures.eq(j);
                if (o.length > 0 && typeof o.data('loaded') == 'undefined') {
                  preLoad(o.attr('href'));
                  o.data('loaded', true);
                }
              }

              display();
              if (options.slideshow)
                timeId = setInterval(display, options.interval);
            });

      if (options.showOverlay) {
        var
          itop = pheight*(1-options.ratio) + paddingTop,
          ileft = $this.css('padding-left'),
          iheight = (pheight*options.ratio) + paddingTop;

        // screen
        $('<div />')
          .addClass(options.screenClass)
          .css({
            opacity: 0.5,
            top: itop,
            left: 0,
            height: iheight,
            width: $this.outerWidth(),
            zIndex: options.zIndex + 1000
          })
          .insertAfter('#' + id);

        $('<div />')
          .addClass(options.infoClass)
          .html('<div id="gtitle_' + id + '" class="' + options.titleClass + '" style="display:none;"></div>' +
            '<div id="gdesc_' + id + '" class="' + options.descClass + '" style="display:none;"></div>')
          .css({
            top: itop,
            left: 0,
            height: iheight,
            zIndex: options.zIndex + 1500
          })
          .insertAfter('#' + id);
      }

      // content container
      var c = jQuery('#' + id).css({
        position: 'relative',
        width: width,
        height: height,
        overflow: 'hidden'
      }).addClass(options.contentClass);

      var
        bar = $this.find('ul').show(),
        thumbnails = bar.find('img'),
        pictures = $this.find('a').bind('click.gallery', function (e) { e.preventDefault(); }),
        gtitle = $('#gtitle_' + id),
        gdesc = $('#gdesc_' + id),
        len =  thumbnails.length,
        w = $this.find('li:first').outerWidth(true);

      var display = function () {
        var t = thumbnails.eq(i);
        var pict = pictures.eq(i);
        var p = pict.attr('href');
        var pid = id + '_' + i;

        // pre load
        var next = pictures.eq(i+limit);
        if (next.length > 0 && typeof next.data('loaded') == 'undefined') {
          preLoad(next.attr('href'));
        }

        // delete previous picture
        c.find('img').animate({opacity: 0.0}, {
          queue: false,
          duration: duration,
          easing: 'linear',
          complete: function() { jQuery(this).remove(); }
        });

        // append new picture
        jQuery('<img />')
          .attr('src', p)
          .attr('id', pid)
          .css({
            position: 'absolute',
            top: 0,
            left: 0,
            opacity: 0.0
          })
          .bind('click.gallery', function (event) {
            options.onClick.apply(this, [event, pict.get()]);
          })
          .appendTo('#' + id)
          .animate({opacity: 1.0}, {
            queue: false,
            duration: duration,
            easing: 'linear'
          })
          .load(function () {
            pict.data('loaded', true);
          });

        var title = t.attr('title');
        var id_of_desc = pict.attr('rel');
        var desc = (id_of_desc && $('#' + id_of_desc).length > 0)
          ? $('#' + id_of_desc).html(): pict.attr('title');

        if (n != 0) {
          // title
          if (typeof title != 'undefined')
            gtitle.fadeOut(duration*0.3, function () {
              jQuery(this).html(title).show();
            });

          // description
          if (typeof desc != 'undefined')
            gdesc.fadeOut(duration*0.3, function () {
              jQuery(this).html(desc).show();
            });

          // scrolle
          bar.animate({left: w*(-1)*step}, {
            queue: false,
            duration: 300,
            easing: options.easing,
            complete: function () {
              var $t = jQuery(this).css({left: 0});
              var f = $t.find('li').slice(0, step);
              var indexes = f.map(function () {
                return jQuery.data(this, 'index');
              });
              var cln = f.clone(true).each(function (j) {
                jQuery.data(this, 'index', indexes[j]);
              }).hide().appendTo(this).fadeIn(duration);
              f.remove();
              step = 1;
            }
          });
        } else {
          // title & description
          if (typeof title != 'undefined') gtitle.html(title).show();
          if (typeof desc != 'undefined') gdesc.html(desc).show();
        }

        options.onChange.apply($this.get(), [i, pict.get()]);

        if (i < (len-1)) {
          i++;
        } else {
          i = 0;
        }
        n++;
      };

      // pre load
      for (var j=0; j<limit; j++) {
        var o = pictures.eq(j);
        if (o.length > 0) {
          preLoad(o.attr('href'));
          o.data('loaded', true);
        }
      }

      display();
      if (options.slideshow)
        timeId = setInterval(display, options.interval);

      _inc++;
    });
  };

  jQuery.fn.gallery.defaults = {
    width: null,
    height: null,
    thumbWidth: 55,
    thumbHeight: 55,
    zIndex: 1000,
    interval: 4500,
    prefix: 'gallery_',
    easing: 'linear',
    ratio: 0.35,
    slideshow: true,
    toggleBar: true,
    showOverlay: true,
    barPosition: null,
    barClass: 'galleryBar',
    contentClass: 'galleryContent',
    infoClass: 'galleryInfo',
    screenClass: 'galleryScreen',
    titleClass: 'galleryTitle',
    descClass: 'galleryDesc',
    onClick: function () { return; },
    onSelect: function () { return; },
    onChange: function () { return; }
  };

  /** private methods **/

  var preLoad = function (url) {
    jQuery('<img />').attr('src', url);
  };

})(jQuery);