
var VGallery = Class.create(
{
  gallery: null,
  data: null,
  options: {  },

  thumbsSpacing: null,
  thumbsPosition: null,
  thumbsContainerWidth: null,
  thumbsContainerHeight: null,

  _relief: 10,
  _scrollBarWidth: 24,

  _thumbsContainer: null,
  _thumbsList: null,
  _previewContainer: null,

  _thumbsContainerMetrics: { x: null, y: null, width: null, height: null },
  _previewContainerMetrics: { x: null, y: null, width: null, height: null },

  _preview: null,
  _thumbs: [],
  _previews: [],

  _current: null,

  _hasLayout: false,

  initialize: function(gallery, data, options) {
    this.gallery = $(gallery);
    this.data = data;
    this.options = options;

    this.thumbsSpacing = options.thumbsSpacing || 10;
    this.thumbsPosition = options.thumbsPosition || 'left';
    this.thumbsContainerWidth = options.thumbsContainerWidth || 0.3;
    this.thumbsContainerHeight = options.thumbsContainerHeight || 0.3;

    this.setSize(this.gallery.getWidth(), this.gallery.getHeight());
  },

  setSize: function(w, h) {
    this.size(w, h);

    this.sizeLayout();
    if(! this._hasLayout) {
      this.createLayout();
    }
    this.resizeLayout();

    this.destroyThumbs();
    this.sizeThumbs();
    this.createThumbs();
  },

  getCurrent: function() {
    return (this._current >= 0) ? this._thumbs[this._current] : null;
  },

  isHorizontal: function() {
    return (this.thumbsPosition == 'left' || this.thumbsPosition == 'right');
  },

  size: function(w, h) {
    this.gallery.setStyle({ width: w + 'px', height: h + 'px' });
  },

  sizeLayout: function() {
    if (this.isHorizontal()) {
      if (this.thumbsContainerWidth < 1) {
        this._thumbsContainerMetrics.width = this.gallery.getWidth() * this.thumbsContainerWidth;
      }

      this._thumbsContainerMetrics.height = this.gallery.getHeight();

      if (this.thumbsPosition == 'left') {
        this._thumbsContainerMetrics.x = 0;
      } else {
        this._thumbsContainerMetrics.x = this.gallery.getWidth() - this._thumbsContainerMetrics.width;
      }

      this._thumbsContainerMetrics.y = 0;

      this._previewContainerMetrics.width = this.gallery.getWidth() - this._thumbsContainerMetrics.width - this._relief;
      this._previewContainerMetrics.height = this.gallery.getHeight();
      this._previewContainerMetrics.x = (this.thumbsPosition == 'left')
        ? this._thumbsContainerMetrics.width
        : 0;
      this._previewContainerMetrics.y = 0;
    } else {
      if (this.thumbsContainerHeight < 1) {
        this._thumbsContainerMetrics.height = this.gallery.getHeight() * this.thumbsContainerHeight;
      }

      this._thumbsContainerMetrics.width = this.gallery.getWidth();

      if (this.thumbsPosition == 'top') {
        this._thumbsContainerMetrics.y = 0;
      } else {
        this._thumbsContainerMetrics.y = this.gallery.getHeight() - this._thumbsContainerMetrics.height;
      }

      this._thumbsContainerMetrics.x = 0;

      this._previewContainerMetrics.height = this.gallery.getHeight() - this._thumbsContainerMetrics.height;
      this._previewContainerMetrics.width = this.gallery.getWidth();
      this._previewContainerMetrics.y = (this.thumbsPosition == 'top')
        ? this._thumbsContainerMetrics.height
        : 0;
      this._previewContainerMetrics.x = 0;
    }
  },

  getThumbsContainerAvailableWidth: function() {
    // subtract the width of the scrollbar
    return this._thumbsContainerMetrics.width - this._scrollBarWidth;
  },

  getThumbsContainerAvailableHeight: function() {
    // subtract the width of the scrollbar
    return this._thumbsContainerMetrics.height - this._scrollBarWidth;
  },

  resizeLayout: function() {
    this._thumbsContainer.setStyle({
      left: this._thumbsContainerMetrics.x + 'px',
      top: this._thumbsContainerMetrics.y + 'px',
      width: this._thumbsContainerMetrics.width + 'px',
      height: this._thumbsContainerMetrics.height + 'px'
    });

    this._previewContainer.setStyle({
      right: 0 + 'px',//this._previewContainerMetrics.x,
      top: this._previewContainerMetrics.y + 'px',
      width: this._previewContainerMetrics.width + 'px',
      height: this._previewContainerMetrics.height + 'px'
    });
  },

  createLayout: function() {
    this.gallery.setStyle({
      position: 'relative'
    });

    this._thumbsContainer = new Element('div', { 'class': 'thumbsContainer' });
    this._thumbsContainer.setStyle({
      position: 'absolute',
      overflow: 'auto'
    });

    this._previewContainer = new Element('div', { 'class': 'previewContainer' });
    this._previewContainer.setStyle({
      position: 'absolute',
      textAlign: 'center'
    });

    this._thumbsList = new Element('ul');
    this._thumbsList.setStyle({
      display: 'block',
      margin: 0 + 'px',
      padding: 0 + 'px',
      listStyle: 'none'
    });

    this._thumbsContainer.insert(this._thumbsList);
    this.gallery.insert(this._thumbsContainer);
    this.gallery.insert(this._previewContainer);

    this._hasLayout = true;
  },

  destroyThumbs: function() {
    this._thumbs.each(
      function(thumb) {
        thumb.destroy();
      }
    );

    this._thumbs = [];
  },

  sizeThumbs: function() {
    //
  },

  createThumbs: function() {
    this.firstThumbLoaded = false;

    this.data.each(function(data) {
        data.loaderImage = this.options.loaderImage;
        data.width = this.options.thumbWidth;
        data.height = this.options.thumbHeight;

        var thumb = this.createThumb(data);

        this.handleThumbLoaded = this.handleThumbLoaded.bindAsEventListener(this);
        thumb.image.observe('load', this.handleThumbLoaded);

        this._thumbsList.insert(thumb.load());
      }.bind(this)
    );
  },

  handleThumbLoaded: function(event) {
    var thumb = event.element().obj;

    event.stop();

    if (thumb.index == 0) {
      this.loadPreview(0);
    } else {
      thumb.idle();
    }
  },

  createThumb: function(data) {
    var thumb = new VGalleryThumb(data);

    this._thumbs.push(thumb);

    thumb.index = this._thumbs.size() - 1;

    this.handleClick = this.handleClick.bindAsEventListener(this);
    thumb.container.observe('click', this.handleClick);

    if (this.isHorizontal()) {
      if (this.thumbsPosition == 'left') {
        thumb.container.setStyle({ marginRight: this.thumbsSpacing + 'px' });
      } else {
        thumb.container.setStyle({ marginLeft: this.thumbsSpacing + 'px' });
      }

      thumb.container.setStyle({ marginBottom: this.thumbsSpacing + 'px' });
    } else {
      if (this.thumbsPosition == 'top') {
        thumb.container.setStyle({ marginBottom: this.thumbsSpacing + 'px' });
      } else {
        thumb.container.setStyle({ marginTop: this.thumbsSpacing + 'px' });
      }

      thumb.container.setStyle({ marginRight: this.thumbsSpacing + 'px' });
    }

    thumb.container.setStyle({ textAlign: 'center' });

    return thumb;
  },

  destroyPreview: function() {
    if (this._preview) {
      this._preview.hide();
      this._preview.container.remove();
      this._preview = null;
    }
  },

  sizePreview: function() {
    //
  },

  createPreview: function(data) {
    this._preview = new VGalleryPreview(data);
    this._previewContainer.insert(this._preview.load());
  },

  handleClick: function(event) {
    var thumb = event.element();
    var thumbObj = thumb.obj;
    var index = thumbObj.index;

    if (this._current != index) {
      this.loadPreview(index);
    }
  },

  loadPreview: function(index) {
    var thumb = this._thumbs[index];

    this.destroyPreview();

    this.sizePreview();

    this._thumbs.each(function(thumb) {
      thumb.deactivate();
    });

    this._current = index;

    this.getCurrent().activate();

    var data = {
      src: thumb.href + this.noCache(),
      loaderImage: this.options.loaderImage,
      width: this._previewContainerMetrics.width,
      height: this._previewContainerMetrics.height
    };

    if (! this._previews[index]) {
      this.createPreview(data);
      this._previews[index] = this._preview;
    } else {
      this._preview = this._previews[index];
      this._preview.show();
      this._previewContainer.insert(this._preview.container);
    }
  },

  noCache: function() {
    // trick the browser into thinking this is a different image
    // disables loading image from cache
    // when loading from cache, IE (others?) forget image width and height
    return '#' + Math.random();
  },

  reloadPreview: function() {
    if (this.getCurrent()) {
      this.loadPreview(this._current);
    }
  },

  loadPrevious: function() {
    if (this._current > 0) {
      this.loadPreview(--this._current);
    }
  },

  loadNext: function() {
    if (this._current < this._thumbs.size() - 1) {
      this.loadPreview(++this._current);
    }
  }
});

var VGalleryImage = Class.create(
{
  src: null,
  href: null,
  width: 0,
  height: 0,
  loaderImage: null,

  container: null,
  link: null,
  image: null,
  loader: null,

  duration: null,

  initialize: function(data) {
    this.src = data.src;
    this.href = data.href;
    this.loaderImage = data.loaderImage;
    this.width = data.width;
    this.height = data.height;
    this.duration = data.duration || 0.3;

    this.createChildren();
  },

  load: function(src) {
    if (! src) src = this.src;
    this.handleLoad = this.handleLoad.bindAsEventListener(this);
    this.image.observe('load', this.handleLoad);
    this.image.src = src;

    return this.container;
  },

  destroy: function() {
    if (this.container) {
      this.container.remove();
      this.container = null;
      this.link = null;
      this.image = null;
      this.loader = null;
    }
  },

  createChildren: function() {
    this.image = new Element('img');
    this.image.hide();
    this.image.obj = this;

    this.container = new Element('div');
    this.container.setStyle({
      position: 'relative',
      'float': 'left',
      width: this.width + 'px',
      height: this.height + 'px'
    });

    if (this.href) {
      this.link = new Element('a', { href: '#' });
      this.image.wrap(this.link);
      this.container.insert(this.link);
    } else {
      this.container.insert(this.image);
    }

    if (this.loaderImage) {
      this.loader = new Element('img', { 'class': 'preloader' });
      this.handleLoaderLoad = this.handleLoaderLoad.bindAsEventListener(this);
      this.loader.observe('load', this.handleLoaderLoad);
      this.loader.src = this.loaderImage;
      //this.loader.hide();
      this.image.insert({ after: this.loader });
    }
  },

  handleLoaderLoad: function(event) {
    event.stop();

    this.loader.setStyle({
      position: 'absolute',
      top: ((this.height - this.loader.getHeight()) / 2) + 'px',
      left: ((this.width - this.loader.getWidth()) / 2) + 'px'
    });

    //this.loader.show();
  },

  handleLoad: function(event) {
    event.stop();

    if (this.loaderImage) {
      this.loader.remove();
    }

    this.image.setStyle({
      position: 'absolute',
      top: ((this.height - this.image.getHeight()) / 2) + 'px',
      left: ((this.width - this.image.getWidth()) / 2) + 'px'
    });

    this.afterLoad();
  },

  afterLoad: function() {
    // callback
  }
});

var VGalleryThumb = Class.create(VGalleryImage,
{
  listItem: null,
  idleOpacity: null,
  active: false,
  trans: null,

  initialize: function($super, data) {
    $super(data);

    this.idleOpacity = data.idleOpacity || 0.3;
  },

  createChildren: function($super) {
    $super();

    this.listItem = new Element('li', { 'class': 'thumb' });
    this.link.wrap(this.listItem);
  },

  afterLoad: function() {
    this.handleMouseOver = this.handleMouseOver.bindAsEventListener(this);
    this.handleMouseOut = this.handleMouseOut.bindAsEventListener(this);

    this.image.observe('mouseover', this.handleMouseOver);
    this.image.observe('mouseout', this.handleMouseOut);
  },

  handleMouseOver: function(event) {
    if (this.active == false) {
      this.over();
    }
  },

  handleMouseOut: function(event) {
    if (this.active == false) {
      this.out();
    }
  },

  activate: function() {
    if (! this.active) {
      this.active = true;
      this.over();
    }
  },

  deactivate: function() {
    if (this.active) {
      this.active = false;
      this.out();
    }
  },

  idle: function() {
    if (this.trans) {
      this.trans.cancel();
    }

    this.trans = Effect.Appear(this.image, { duration: this.duration, to: this.idleOpacity });
  },

  over: function() {
    if (this.trans) {
      this.trans.cancel();
    }

    this.trans = Effect.Appear(this.image, { duration: this.duration, to: 1.0 });
  },

  out: function() {
    if (this.trans) {
      this.trans.cancel();
    }

    this.trans = Effect.Fade(this.image, { duration: this.duration, to: this.idleOpacity });
  }
});

var VGalleryPreview = Class.create(VGalleryImage,
{
  initialize: function($super, data) {
    $super(data);
  },

  afterLoad: function() {
    this.show();
  },

  hide: function() {
    this.image.hide();
  },

  show: function() {
    Effect.Appear(this.image, { duration: this.duration });
  }
});
