(function(){
  $.fn.preview = function(baseUrl){
    var config = jQuery.extend({
      baseUrl : baseUrl
    }, baseUrl);

    function initialize() {
      $('embed, object, select').css({ 'visibility' : 'hidden' });
      if (!$('#preview').length) {
        $('body').append('<div id="preview"><div id="preview-overlay"></div><div id="preview-box"><div class="preview-info"><div class="preview-detail"><span class="preview-title"></span></div><table class="preview-navigation"><tr><td class="preview-navigation-prev"><a href="#">前へ</a></td><td class="preview-navigation-close"><a href="#">拡大イメージを閉じる</a></td><td class="preview-navigation-next"><a href="#">次へ</a></td></tr></table></div><div id="preview-image-box"><img id="preview-image" src="/images/preview-loading.gif"><div id="preview-image-loading"><a href="#"><img src="/images/preview-loading.gif"></a></div></div><div class="preview-info"><table class="preview-navigation"><tr><td class="preview-navigation-prev"><a href="#">前へ</a></td><td class="preview-navigation-close"><a href="#">拡大イメージを閉じる</a></td><td class="preview-navigation-next"><a href="#">次へ</a></td></tr></table></div></div></div>');
      }

      $('#preview,#preview-overlay,#preview-box,.preview-info,#preview-image-box,#preview-image,#preview-image-loading').hide();

      var pageSize = getPageSize();
      $('#preview-overlay').css({
        opacity : 0.8,
        width   : (jQuery.browser.msie) ? pageSize[2] : pageSize[0]
      });

      var scrollSize = getPageScroll();
      $('#preview-box').css({
        top  : scrollSize[1] + (pageSize[3] / 10),
        left : scrollSize[0]
      });

      $('#preview-overlay,#preview-box').click(function(){
        close();
      });

      $('.preview-navigation-close a').each(function(){
        $(this).click(function(){
          close();
          return false;
        });
      });

      $(window).resize(function(){
        var pageSize = getPageSize();
        $('#preview-overlay').css({
          width : (jQuery.browser.msie) ? pageSize[2] : pageSize[0]
        });

        var scrollSize = getPageScroll();
        $('#preview-box').css({
          top  : scrollSize[1] + (pageSize[3] / 10),
          left : scrollSize[0]
        });
      });

      imageSrc.length = 0;
      
      activeImageSrcObj = $(this);
      if (previewObj.length == 1) {
        imageSrc.push(new Array(activeImageSrcObj.attr('href'), activeImageSrcObj.attr('title')));
      } else {
        for (var i=0; i<previewObj.length; i++) {
          imageSrc.push(new Array($(previewObj[i]).attr('href'), $(previewObj[i]).attr('title')));
        }
      }

      activeNum = 0;
      while (imageSrc[activeNum][0] != activeImageSrcObj.attr('href')) {
        activeNum++;
      }

      $('#preview').show();
      $('#preview-overlay').fadeIn();
      $('#preview-box').show();

      view();
      
      return false;
    };

    function view() {
      $('#preview-image,.preview-info').hide();
      $('#preview-image-loading').show();

      var image = new Image();
      image.onload = function(){
        $('#preview-image').attr('src', this.src);
        $('#preview-image').unbind().bind('click', function(){
          if (activeNum < imageSrc.length - 1) {
            activeNum++;
            view();
            return false;
          } else {
            close();
            return false;
          }
        });
        $('#preview-image').css({ cursor : 'pointer' });

        var width  = image.width + 15;
        var height = image.height + 5;
        $('.preview-info').css({
          width  : width
        });
        $('.preview-title').each(function(){
          $(this).html(imageSrc[activeNum][1]);
        });
        // navigation setting
        // previous
        $('.preview-navigation-prev a').each(function(){
          if (activeNum != 0) {
            $(this).show();
            $(this).unbind().bind('click', function(){
              activeNum--;
              view();
              return false;
            });
          } else {
            $(this).hide();
          }
        });
        // next
        $('.preview-navigation-next a').each(function(){
          if (activeNum < imageSrc.length - 1) {
            $(this).show();
            $(this).unbind().bind('click', function(){
              activeNum++;
              view();
              return false;
            });
          } else {
            $(this).hide();
          }
        });

        $('#preview-image-box').animate({ width: width, height: height }, 500, function(){
          if (jQuery.browser.msie) {
            $('.preview-info').css({ display : 'block' });
            $('#preview-image-loading').css({
              height  : 0,
              width   : 0,
              display : 'none',
              zIndex  : -100
            });
          } else {
            $('.preview-info').slideDown('slow');
            $('#preview-image-loading').hide();
          }
          $('#preview-image').fadeIn();
        });
        image.onload = function(){};
      };

      var image_src = getImageUrl(activeNum);
      image.src = image_src;

      // preload
      if (imageSrc.length > 1) {
        if (activeNum != 0) {
          back_image_src = getImageUrl(activeNum - 1);
          backImage = new Image();
          backImage.src = back_image_src;
        }
        if (activeNum < imageSrc.length - 1) {
          next_image_src = getImageUrl(activeNum + 1);
          nextImage = new Image();
          nextImage.src = next_image_src;
        }
      }
    };

    function close()
    {
      $('#preview-box').hide();
      $('#preview-image').attr('src', '');
      $('#preview-overlay').fadeOut(function(){
        $('#preview').hide();
      });
      $('embed, object, select').css({ 'visibility' : 'visible' });
    };

    function getPageSize() {
      var xScroll, yScroll;
      if (window.innerHeight && window.scrollMaxY) {
        xScroll = window.innerWidth + window.scrollMaxX;
        yScroll = window.innerHeight + window.scrollMaxY;
      } else if (document.body.scrollHeight > document.body.offsetHeight) { // all but Explorer Mac
        xScroll = document.body.scrollWidth;
        yScroll = document.body.scrollHeight;
      } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
        xScroll = document.body.offsetWidth;
        yScroll = document.body.offsetHeight;
      }
      var windowWidth, windowHeight;
      if (self.innerHeight) { // all except Explorer
        if (document.documentElement.clientWidth) {
          windowWidth = document.documentElement.clientWidth;
        } else {
          windowWidth = self.innerWidth;
        }
        windowHeight = self.innerHeight;
      } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
        windowWidth  = document.documentElement.clientWidth;
        windowHeight = document.documentElement.clientHeight;
      } else if (document.body) { // other Explorers
        windowWidth  = document.body.clientWidth;
        windowHeight = document.body.clientHeight;
      }
      // for small pages with total height less then height of the viewport
      if (yScroll < windowHeight) {
        pageHeight = windowHeight;
      } else {
        pageHeight = yScroll;
      }
      // for small pages with total width less then width of the viewport
      if (xScroll < windowWidth){
        pageWidth = xScroll;
      } else {
        pageWidth = windowWidth;
      }
      arrayPageSize = new Array(pageWidth, pageHeight, windowWidth, windowHeight);
      return arrayPageSize;
    };

    function getPageScroll() {
      var xScroll, yScroll;
      if (self.pageYOffset) {
        yScroll = self.pageYOffset;
        xScroll = self.pageXOffset;
      } else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict
        yScroll = document.documentElement.scrollTop;
        xScroll = document.documentElement.scrollLeft;
      } else if (document.body) { // all other Explorers
        yScroll = document.body.scrollTop;
        xScroll = document.body.scrollLeft;
      }
      arrayPageScroll = new Array(xScroll, yScroll);
      return arrayPageScroll;
    };

    function getImageUrl(index) {
      if (!config.baseUrl) {
        return imageSrc[index][0];
      }

      if (config.baseUrl.match(/{%(\d+)d}/)) {
        var formats = RegExp.$1;
        var str = formats.substr(0, 1);
        var num = formats.substr(1, 1);

        var base = '';
        if (parseInt(num) != 1) {
          var rem = Math.abs(((index + 1).toString().length) - parseInt(num));
          for (var i=0; i<rem; i++) {
            base += str.toString();
          }
          base += (index + 1).toString();
        } else {
          base = (index + 1).toString();
        }

        return config.baseUrl.replace(/{%(\d+)d}/, base);
      } else {
        return config.baseUrl;
      }
    };

    var previewObj = this;
    var imageSrc   = new Array();
    var activeNum  = 0;

    return this.unbind('click').click(initialize);
  };
})(jQuery);