(function($) {
    $.fn.dupersize = function(childSelector, showFirst, thumbnailContainer) {

      $.fn.dupersize.state.parentElement = $(this);

      // Collect children
      var i = 0;
      $(childSelector).each(function() {
        addThumbnail(i);
        $(this).load(function(){
          j = $.fn.dupersize.state.images.length;
          image = $(this);
          $.fn.dupersize.state.images.push({ width: image.width(),
                                            height: image.height(),
                                           element: image });
           // Show the first image?
           if (j==0 && showFirst == true) $.fn.dupersize.showElement(0);

           // Display thumbnail
           thumbSrc = image.attr('src').replace(/_[mbt]/, "_s")
           $.fn.dupersize.state.thumbnails[j].attr({src: thumbSrc});
        });
        i++;
      });
      
      function addThumbnail(index){
        thumb = $('<img id="thumnail-'+i+'" />');
        link  = $('<a href="#" onclick="  hideUI(true, \'slow\'); $(\'#dupersized\').dupersize.showElement('+index+'); return false;" />').append(thumb);
        $(thumbnailContainer).append(link);
        $.fn.dupersize.state.thumbnails.push(thumb);
        return thumb;
      };
      
      // Set styles
      $(this).css( { overflow: 'hidden',
                      padding: 0,
                       margin: 0});
      
      // Capture resize event
      $(window).resize(function() {
        $.fn.dupersize.refresh();
      });
    };

    // Fire this when you changed settings or resized windows
    $.fn.dupersize.refresh = function() {
      activeElement = $.fn.dupersize.state.images[$.fn.dupersize.state.shownImageIndex]
      if(activeElement != null) { 
        $.fn.dupersize.dupersizeElement($.fn.dupersize.state.parentElement,
                                        activeElement.element);
      }
    };

    // Resizes an element to fill it's parent
    $.fn.dupersize.dupersizeElement = function(parent, element){

      // Figure out scale factor
      factor = scaleFactor(parent, element);

      // Resize
      element.css({height: Math.ceil(element.height() * factor)+'px',
                    width: Math.ceil(element.width()  * factor)+'px'});
      element.vAlign(true);
    };
    
    $.fn.dupersize.toggleSize = function() {
      $.fn.dupersize.options.crop = !$.fn.dupersize.options.crop;
      $.fn.dupersize.refresh();
    };
    
    // Positions an element correctly according to it's parent
    $.fn.dupersize.positionElement = function(element){
      element.css({ padding: 0,
                     margin: 0,
                   position: 'absolute',
                        top: 0,
                       left: 0
      });
    };
    
    // Hides the currently shown element and shows another one
    $.fn.dupersize.showElement = function(index){
      indexx = (index < 0) ? $.fn.dupersize.state.images.length + index : index;

      currentElement().fadeOut({duration: 400, queue: "crossfade", position: "end"});
      $.fn.dupersize.dupersizeElement($.fn.dupersize.state.parentElement,
                                      $.fn.dupersize.state.images[index].element);
      $.fn.dupersize.state.images[index].element.fadeIn({duration: 400, queue: "crossfade", position: "end"});

      setActiveIndex(index);
    };
    
    // Show next/previous element
    $.fn.dupersize.nextElement = function(offset){
      newIndex = (($.fn.dupersize.state.shownImageIndex || 0) + offset) % $.fn.dupersize.state.images.length;
      $.fn.dupersize.showElement(newIndex);
    };

    // Find out which size to use
    function scaleFactor(parent, element){
      heightFactor = parent.height() / element.height();
      widthFactor  = parent.width()  / element.width();
      if ($.fn.dupersize.options.crop) {
        if(parent.height() > parent.width()) {
          return heightFactor;
        }
        return widthFactor;
      }
      if( parent.width()  >= element.width()  * widthFactor &&
          parent.height() >= element.height() * widthFactor) {
        return widthFactor;
      }
      return heightFactor;
    };

    // Returns the element currently shown
    function currentElement(){
      shownIndex = $.fn.dupersize.state.shownImageIndex;
      if(shownIndex!=null) {
        return $($.fn.dupersize.state.images[shownIndex].element);
      } else {
        return $(null);
      }
    };
    
    // Stores the currently active index
    function setActiveIndex(index){
      $.fn.dupersize.state.shownImageIndex = index;
    };

    // Log
    function debug($obj) {
      if (window.console && window.console.log)
        window.console.log($obj);
    };

    // Default options
    $.fn.dupersize.options = {
      parent: $($('body')[0]),
      crop: false
    };
    
    $.fn.dupersize.state = {         images: [],
                                 thumbnails: [],
                            shownImageIndex: null };
  })(jQuery);