jQuery.fn.imageviewer = function(options) {
  var settings = {
    images: [],
    duration: 4000,
    transitionDuration: 700,
    menu: false,
    menuContainer: null
  }
  
  // merge options
  $.extend(settings, options);
  
  var elm = this,
      currentImage = 0,
      interval = null,
      imagemenu= null,
      fullscreenHolder = null;
  
  
  function init() {
    // check if there are images
    if (settings.images.length == 0)
      return;
    
    // create menu container
    if (settings.menu) {
      settings.menuContainer.append($('<ul id="image-menu"><li><a href="#" id="playpause">Play/pauze</a></li></ul>'));
      imagemenu = $('#image-menu');
      imagemenu.click(menuClick);
    }
    
    // loop all images
    for (var i = 0; settings.images[i]; ++i) {
      elm.append($('<img src="' + settings.images[i] + '" alt="" id="image-' + i + '">'));
      
      if (i != currentImage)
        $('#image-' + i).hide();
      
      if (settings.menu) {
        imagemenu.append('<li><a href="#image-' + i + '" id="imagelink-' + i + '">' + (i + 1) + '</a></li>');
        $('#imagelink-0').addClass('active');
      }
    }
    
    // set loop
    interval = setInterval(showNext, settings.duration + settings.transitionDuration);
    
    // add fullscreen
    elm.append('<div id="fullscreen"><img alt=""></div>');
    fullscreenDiv = $('#fullscreen');
    fullscreenImg = fullscreenDiv.find('img');
    fullscreenDiv.click(hideFullscreen);
    
    elm.click(fullscreen);
  }
  
  
  // show the next image
  function showNext() {
    $('#image-menu .active').removeClass('active');
    $('#image-' + currentImage).fadeOut(settings.transitionDuration);
    currentImage = (currentImage + 1) % settings.images.length;
    $('#image-' + currentImage).fadeIn(settings.transitionDuration);
    $('#imagelink-' + currentImage).addClass('active');
  }
  
  
  // when a user clicks on the menu
  function menuClick(e) {
    e.preventDefault();
    var target = e.target;
    
    if (target.nodeName.toLowerCase() != 'a')
      return;
    
    if (target.id == 'playpause') {
      togglePlay();
    }
    else {
      if (currentImage == parseInt(target.id.substring(10), 10))
        return;
      
      $('#image-menu .active').removeClass('active');
      $('#image-' + currentImage).fadeOut(settings.transitionDuration);
      currentImage = parseInt(target.id.substring(10), 10);
      $('#image-' + currentImage).fadeIn(settings.transitionDuration);
      $('#imagelink-' + currentImage).addClass('active');
      togglePlay(false);
    }
  }
  
  
  // play/pause the loop
  function togglePlay(setTo) {
    if (typeof setTo == 'undefined')
      var setTo = !interval;
    
    if (setTo) {
      interval = setInterval(showNext, settings.duration + settings.transitionDuration);
      $('#playpause').removeClass('pause');
    }
    else {
      clearInterval(interval);
      interval = null;
      $('#playpause').addClass('pause');
    }
  }
  
  
  // preload fullscreen image
  function fullscreen(e) {
    if (e.target.nodeName.toLowerCase() != 'img')
      return;
    
    togglePlay(false);
    
    var bigImg = new Image();
    bigImg.onload = showFullscreen;
    bigImg.src = e.target.src.replace('570x570', '700x700');
  }
  
  
  function showFullscreen() {
    fullscreenDiv.css('display', 'block');
    
    fullscreenImg.attr('src', this.src);
    
    fullscreenDiv.animate({
      left: '-65px',
      top: '-40px'
    }, settings.transitionDuration, 'easeInOutCubic');
    
    fullscreenImg.animate({
      height: '700px',
      width: '700px'
    }, settings.transitionDuration, 'easeInOutCubic');
  }
  
  
  function hideFullscreen(e) {
    e.preventDefault();
    
    fullscreenDiv.animate({
      left: '0px',
      top: '0px'
    }, settings.transitionDuration, 'easeInOutCubic');
    
    fullscreenImg.animate({
      height: '570px',
      width: '570px'
    }, settings.transitionDuration, 'easeInOutCubic', function() {
      togglePlay(true);
      fullscreenDiv.css('display', 'none');
    });
  }
  
  
  init();
};
