Lightbox = function(){
  var container,
      contentTemplate,
      clicked,
      defaultItem = false,
      imageGroups = $H(),
      groupIndex,
      itemDataContainer,
      imageDataTemplate,
      items,
      lightboxType,
      options,
      overlay,
      overlayPanel,
      overlayPanelClose,
      overlayPanelInner,
      overlayPanelInnerFg,
      nextButton,
      nextImageDims = { height : 0, width : 0 },
      numInGroup,
      ph,
      prevButton,
      pv,
      viewportDims,
      videoDataTemplate,
      videoGroups = $H(),
      visible;

  function build() {
    overlay = new Element('div', { 'id' : 'overlay' }).setStyle({
      opacity : 0.75
    }).hide();

    Element.insert(document.body, overlay);

    overlayPanelClose = new Element('a').addClassName('close simple-module').update('<span class="fg">Close</span><span class="bg"></span>');
    overlayPanel = new Element('div', { 'id' : 'overlay-panel' }).update(options.contentHtml).hide();

    overlayPanel.insert(overlayPanelClose);

    //overlayPanelInner = new Element('div', { 'id' : 'overlay-panel-inner' }).update(options.contentHtml);
    //overlayPanel.insert(overlayPanelInner);

    Element.insert(document.body, overlayPanel);

    overlayPanelInnerFg = overlayPanel.down('div.fg');
    ph = parseInt(overlayPanelInnerFg.getStyle('paddingLeft'), 10) + parseInt(overlayPanelInnerFg.getStyle('paddingRight'), 10);
    pv = parseInt(overlayPanelInnerFg.getStyle('paddingTop'), 10) + parseInt(overlayPanelInnerFg.getStyle('paddingBottom'), 10);

    contentTemplate = new Template(options.contentHtml);

    items = container.select('a.lightbox');

    itemDataContainer = new Element('div').addClassName('item-data');
    overlayPanel.insert(itemDataContainer);

    imageDataTemplate = new Template(options.imageDataHTML);
    videoDataTemplate = new Template(options.videoDataHTML);

    insertNavButtons();

    getImageGroups();
    getVideoGroups();

    Event.observe(document.body, 'click', onClick);

    if(defaultItem) {
      viewportDims = document.viewport.getDimensions();
      var attrs = {
        href : defaultItem.href,
        title: defaultItem.name,
        id : defaultItem.id,
        rel : defaultItem.type
      };

      clicked = new Element('a', attrs).addClassName('lightbox').update('<span class="name">'+defaultItem.name+'</span><span class="desc">'+defaultItem.desc+'</span>').hide();
      Element.insert(document.body, clicked);

      lightboxType = getLightboxType(clicked.rel);

      if(defaultItem.type == 'image') {
        loadImg(defaultItem.href);
      } else if(defaultItem.type == 'video') {
        insertVideo(getEmbedHTML(defaultItem.href));
      }

      showLightbox();
    }
  }

  function getDocHeight() {
    var D = document;
    return Math.max(
      Math.max(D.body.scrollHeight, D.documentElement.scrollHeight),
      Math.max(D.body.offsetHeight, D.documentElement.offsetHeight),
      Math.max(D.body.clientHeight, D.documentElement.clientHeight)
    );
  }

  function getEmbedHTML(_embedUrl) {
    var embedTemplate = new Template(options.videoEmbedHTML);
    return embedTemplate.evaluate({
      embedUrl : _embedUrl,
      height : options.videoDims.height,
      width : options.videoDims.width
    });
  }

  function getItemData() {
    if(lightboxType.type == 'image' || lightboxType.type == 'video') {
      var _link = clicked;
    } else if(lightboxType.type == 'imageGroup') {
      var _link = imageGroups.get(lightboxType.groupName)[groupIndex];
    } else if(lightboxType.type == 'videoGroup') {
      var _link = videoGroups.get(lightboxType.groupName)[groupIndex];
    }

    return {
      name : _link.down('span.name').innerHTML,
      desc : _link.down('span.desc').innerHTML
    }
  }

  function getImageGroups() {
    var groupImages = items.findAll(function(el) {
      return el.match('a[rel^=imageGroup]');
    });

    if(groupImages.length > 0) {
      groupImages.each(function(el) {
        var groupName = getLightboxType(el.rel).groupName;
        if(imageGroups.keys().include(groupName)){
          imageGroups.get(groupName).push(el);
        } else {
          var groupItems = [el];
          imageGroups.set(groupName, groupItems);
        }
      });
    }
  }

  function getLightboxType(rel) {
    var r = rel.split(':');
    return {
      type : r[0],
      groupName : r[1]
    };
  }

  function getVideoGroups() {
    var groupVideos = items.findAll(function(el) {
      return el.match('a[rel^=videoGroup]');
    });

    if(groupVideos.length > 0) {
      groupVideos.each(function(el) {
        var groupName = getLightboxType(el.rel).groupName;
        if(videoGroups.keys().include(groupName)){
          videoGroups.get(groupName).push(el);
        } else {
          var groupItems = [el];
          videoGroups.set(groupName, groupItems);
        }
      });
    }
  }

  function hideLightbox() {
    visible = false;
    overlay.hide();
    overlayPanelInnerFg.update("");
    overlayPanel.hide();
  }

  function insertNavButtons() {
    nextButton = new Element('a').addClassName('next simple-module').update('<span class="fg">Next</span><span class="bg"></span>').hide();
    prevButton = new Element('a').addClassName('prev simple-module').update('<span class="fg">Prev</span><span class="bg"></span>').hide();

    overlayPanel.insert(nextButton);
    overlayPanel.insert(prevButton);
  }

  function insertVideo(emdedHTML) {
    var panelWidth = options.videoDims.width+ph;
    var panelHeight = options.videoDims.height+pv;

    var panelTop = document.viewport.getScrollOffsets().top + (viewportDims.height / 2) - (panelHeight / 2);

    overlayPanel.setStyle({
      height : panelHeight+'px',
      marginLeft : -(panelWidth / 2)+'px',
      top : Math.round(Math.max((document.viewport.getScrollOffsets().top + 10), panelTop))+'px',
      width : panelWidth+'px'
    });

    updateItemData(options.videoDims.width);

    overlayPanelInnerFg.update(emdedHTML);

    if(lightboxType.type == 'videoGroup'){
      if(videoGroups.keys().include(lightboxType.groupName)){
        var groupVideos = videoGroups.get(lightboxType.groupName);
        numInGroup = groupVideos.length;
        if(numInGroup > 1){
          if(groupIndex == 0) {
            prevButton.hide();
            nextButton.show();
          } else if(groupIndex == numInGroup-1) {
            prevButton.show();
            nextButton.hide();
          } else {
            prevButton.show();
            nextButton.show();
          }
        }
      }
    }
  }

  function loadImg(href) {
    var img = new Image();
    img.onload = onImgLoad.curry(img);
    img.src = href;
  }

  function onClick(e) {
    if(clicked = e.findElement('a.lightbox')) {
      e.stop();
      var contentId = clicked.hash.substring(1);
      lightboxType = getLightboxType(clicked.rel);
      viewportDims = document.viewport.getDimensions();

      switch(lightboxType.type) {
        case 'image':
          prevButton.hide();
          nextButton.hide();
          loadImg(clicked.href);
          showLightbox();
          break;

        case 'video':
          prevButton.hide();
          nextButton.hide();
          insertVideo(getEmbedHTML(clicked.href));
          showLightbox();
          break;

        case 'imageGroup':
          groupIndex = imageGroups.get(lightboxType.groupName).indexOf(clicked);
          loadImg(clicked.href);
          showLightbox();
          break;

        case 'videoGroup':
          groupIndex = videoGroups.get(lightboxType.groupName).indexOf(clicked);
          insertVideo(getEmbedHTML(clicked.href));
          showLightbox();
          break;

        case 'inline':
          // TODO  - implement inline content display in lightbox.
          // =====================================================
          //var content = contentTemplate.evaluate({ content : $(contentId).innerHTML });
          //showLightbox();
          break;
      }
    } else if(clicked = e.findElement('a.next')) {
      e.stop();
      navigate(1);
    } else if(clicked = e.findElement('a.prev')) {
      e.stop();
      navigate(-1);
    } else if(visible && (!e.target.descendantOf(overlayPanel) || e.target == overlayPanelClose || e.target.descendantOf(overlayPanelClose))) {
      e.stop();
      clicked = e.target;
      hideLightbox();
    }
  }

  function onImgLoad(image) {
    var href = image.src;
    var imgHeight = image.height;
    var imgWidth = image.width;

    if(imgWidth > viewportDims.width-ph) {
      var newWidth = Math.round(viewportDims.width-ph-50);
      var newHeight = Math.round((imgHeight/imgWidth)*newWidth);

      imgHeight = newHeight;
      imgWidth = newWidth;
    }

    if(imgHeight > viewportDims.height-pv) {
      var newHeight = Math.round(viewportDims.height-pv-50);
      var newWidth = Math.round((imgWidth/imgHeight)*newHeight);

      imgHeight = newHeight;
      imgWidth = newWidth;
    }

    var panelWidth = imgWidth+ph;
    var panelHeight = imgHeight+pv;

    var panelTop = document.viewport.getScrollOffsets().top + (viewportDims.height / 2) - (panelHeight / 2);

    overlayPanel.setStyle({
      height : panelHeight+'px',
      marginLeft : -(panelWidth/2)+'px',
      top : Math.round(Math.max((document.viewport.getScrollOffsets().top + 10), panelTop))+'px',
      width : panelWidth+'px'
    });

    var img = new Template('<img src="#{src}" alt="" id="lightboxImg" height="#{height}" width="#{width}" />');
    overlayPanelInnerFg.update(img.evaluate({
      src : href,
      height : imgHeight,
      width : imgWidth
    }));

    updateItemData(imgWidth);

    if(lightboxType.type == 'imageGroup'){
      if(imageGroups.keys().include(lightboxType.groupName)){
        var groupImages = imageGroups.get(lightboxType.groupName);
        numInGroup = groupImages.length;
        if(numInGroup > 1){
          if(groupIndex == 0) {
            prevButton.hide();
            nextButton.show();
          } else if(groupIndex == numInGroup-1) {
            prevButton.show();
            nextButton.hide();
          } else {
            prevButton.show();
            nextButton.show();
          }
        }
      }
    }
  }

  function navigate(offset){
    var nextToShow = groupIndex + offset;

    if(nextToShow > 0 || nextToShow < numInGroup-1) {
      groupIndex = nextToShow;
      overlayPanelInnerFg.hide();
      if(lightboxType.type == 'imageGroup') {
        loadImg(imageGroups.get(lightboxType.groupName)[groupIndex].href);
      } else if(lightboxType.type == 'videoGroup') {
        insertVideo(getEmbedHTML(videoGroups.get(lightboxType.groupName)[groupIndex].href));
      }
      overlayPanelInnerFg.show();
    }
  }

  function showLightbox() {
    visible = true;

    overlay.setStyle({
      height: getDocHeight()+'px',
      width: viewportDims.width+'px'
    });

    overlay.show()
    overlayPanel.show();
  }

  function updateItemData(width) {
    if(lightboxType.type == 'imageGroup' || lightboxType.type == 'image') {
      itemDataContainer.update(imageDataTemplate.evaluate(getItemData()));
    } else if (lightboxType.type == 'videoGroup' || lightboxType.type == 'video') {
      itemDataContainer.update(videoDataTemplate.evaluate(getItemData()));
    }
    //itemDataContainer.insert(overlayPanelClose);
    itemDataContainer.setStyle({
      width: width+'px'
    });
  }

  return {
    initialize: function(element, _options) {
      options = Object.extend({
        contentHtml : '<div class="fg"></div><div class="bg"><div class="hd"><div class="hd-r"></div><div class="hd-l"></div><div class="hd-c"><div></div></div></div><div class="bd"><div class="bd-r"></div><div class="bd-l"></div><div class="bd-c"><div></div></div></div><div class="ft"><div class="ft-r"></div><div class="ft-l"></div><div class="ft-c"><div></div></div></div></div>',
        imageDataHTML :  '<span class="image-title">#{title}</span><span class="image-credit">#{credit}</span><div class="share-links"><div><a href="#{fbShare}" class="facebook share">Share on Facebook</a></div><div><a href="#{twShare}" class="twitter share">Share on Twitter</a></div></div>',
        videoDims : {
          height : 385,
          width : 642
        },
        videoDataHTML :  '<span class="name">#{name}</span><p class="desc">#{desc}</p>',
        videoEmbedHTML : '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="#{width}" height="#{height}"><param name="movie" value="#{embedUrl}"></param><param name="allowFullScreen" value="false"></param><param name="wmode" value="transparent"></param><param name="allowscriptaccess" value="always"></param><embed src="#{embedUrl}" type="application/x-shockwave-flash" wmode="transparent" allowscriptaccess="always" allowfullscreen="false" width="#{width}" height="#{height}"></embed></object>'
      }, _options||{});

      container = $(element);

      if (typeof window.defaultItem != 'undefined') {
        defaultItem = window.defaultItem;
      }

      build();
    }
  }
}();


