/*
 * Fade Slider Toggle plugin
 * 
 * Copyright(c) 2009, Cedric Dugas
 * http://www.position-relative.net
 *	
 * A sliderToggle() with opacity
 * Licenced under the MIT Licence
 */

$.fn.puzzle = function(config) {
  config = jQuery.extend({
    speed: 300,
    xCount: 4,
    yCount: 4
  }, config)

  return $(this).each(function() {
    var element = $(this);
    if (element.attr("tagName") != "IMG")
      return;
    var image = new Image();
    image.src = element.attr('src');
    if (image.complete)
      imageLoaded(element);
    else
      addListener(image, 'load', function() { imageLoaded(element); });
  });

  function addListener(element, type, expression, bubbling) {
    bubbling = bubbling || false;
    if (window.addEventListener) { // Standard
      element.addEventListener(type, expression, bubbling);
      return true;
    } else if (window.attachEvent) { // IE
      element.attachEvent('on' + type, expression);
      return true;
    }
    return false;
  }

  function imageLoaded(element) {
    var tileWidth = element.width() / config.xCount;
    var tileHeight = element.height() / config.yCount;
    //var puzzleTimer;
    var puzzleStartTime = 0;
    var puzzleSeconds = 0;
    var puzzleMoves = 0;

    var imgSrc = element.attr('src');

    element.wrap('<div class="puzzleContainer" />');
    var container = element.parent();

    container.append('<ul class="pieces" />');
    var pieces = $('.pieces', container);

    container.append('<div class="stats"><span class="moves">0</span> moves, <span class="timer">0</span> seconds</div>');
    container.append('<a href="" class="finished"></a>');

    container.append('<div class="startmenu" />');
    var startmenu = $('.startmenu', container);
    startmenu.append('<a href="" class="start2"></a>');
    startmenu.append('<a href="" class="start"></a>');

    container.append('<div class="menu" />');
    var menu = $('.menu', container);
    menu.append('<a href="" class="shifttop"></a>');
    menu.append('<a href="" class="shiftbottom"></a>');
    menu.append('<a href="" class="shiftleft"></a>');
    menu.append('<a href="" class="shiftright"></a>');
    menu.append('<a href="" class="numbers">#</a>');
    menu.append('<a href="" class="cheat">c</a>');

    $(".startmenu", container).hover(startMouseIn, startMouseOut);
    $(".start", container).click(toggleSimplePuzzle);
    $(".start2", container).click(toggleAdvancedPuzzle);
    $(".cheat", container).toggle(showImage, showPuzzle);
    $(".numbers", container).click(toggleNumbers);
    $(".finished", container).click(hideFinished);
    $(".shiftleft", container).click(shiftLeft);
    $(".shiftright", container).click(shiftRight);
    $(".shifttop", container).click(shiftTop);
    $(".shiftbottom", container).click(shiftBottom);
    //startPuzzle();

    function startMouseIn() {
      $(".start2").stop().fadeTo('fast', 1);
    }

    function startMouseOut() {
      $(".start2").stop().fadeTo('slow', 0, function() { $(this).hide(); });
    }

    function togglePuzzle() {
      if ($(".pieces li", container).length == 0)
        return startPuzzle();
      else
        return stopPuzzle();
    }

    function toggleSimplePuzzle() {
      config.xCount = 5;
      config.yCount = 4;
      return togglePuzzle();
    }

    function toggleAdvancedPuzzle() {
      config.xCount = 8;
      config.yCount = 5;
      return togglePuzzle();
    }

    function startPuzzle() {
      tileWidth = element.width() / config.xCount;
      tileHeight = element.height() / config.yCount;
      hideFinished();
      initCounter();
      $(".numbers, .cheat, .shiftleft, .shiftright, .shifttop, .shiftbottom", container).fadeIn(config.speed);
      createPieces();
      return false;
    }

    function initCounter() {
      puzzleSeconds = 0;
      puzzleMoves = 0;
      $(".moves", container).text("0");
      $(".timer", container).text("0");
      //puzzleTimer = setInterval(function() { puzzleSeconds++; }, 1000);
      puzzleStartTime = new Date().getTime();
    }

    function stopPuzzle() {
      puzzleSeconds = Math.floor((new Date().getTime() - puzzleStartTime) / 1000);
      //clearInterval(puzzleTimer);
      $(".numbers, .cheat, .shiftleft, .shiftright, .shifttop, .shiftbottom", container).fadeOut(config.speed);
      $(".puzzle", container).show();
      $(".pieces li", container).fadeOut(config.speed, function() {
        $(this).remove();
      });
      return false;
    }

    function showImage() {
      $(".numbers, .startmenu, .shiftleft, .shiftright, .shifttop, .shiftbottom", container).fadeOut(config.speed);
      $(".puzzle", container).show();
      $(".pieces li", container).fadeOut(config.speed);
      return false;
    }

    function showPuzzle() {
      $(".numbers, .startmenu, .shiftleft, .shiftright, .shifttop, .shiftbottom", container).fadeIn(config.speed);
      $(".pieces li", container).fadeIn(config.speed, function() {
        $(".puzzle", container).hide();
      });
      return false;
    }

    function toggleNumbers() {
      $(".pieces li p", container).fadeToggle(config.speed);
      return false;
    }

    function hideFinished() {
      $(".finished", container).fadeOut(config.speed);
      return false;
    }

    // function to break main image into tiles
    function createPieces() {
      $(".puzzle", container).hide();
      $(".pieces", container).empty();
      for (var y = 0, z = 0; y < config.yCount; y++) {
        for (var x = 0; x < config.xCount; x++) {
          var xpos = tileWidth * x;
          var ypos = tileHeight * y;
          $(".pieces", container).append('<li class="img_' + z + '"><p>' + (z + 1) + '</p></li>');
          $(".img_" + z, container).width(tileWidth).height(tileHeight)
					  .css("background-image", "url(" + imgSrc + ")")
					  .css("background-position", "-" + xpos + "px -" + ypos + "px")
					  .css("left", xpos).css("top", ypos)
				  ;
          z++;
        }
      }
      $(".pieces", container).shuffle();
      animatePieces();
      bindPieces();
    }

    function animatePieces() {
      for (var y = 0, z = 0; y < config.yCount; y++) {
        for (var x = 0; x < config.xCount; x++) {
          var xpos = tileWidth * x;
          var ypos = tileHeight * y;
          var child = $(".pieces", container).children()[z];
          $(child).stop().animate({ 'left': xpos, 'top': ypos }, config.speed, function() {
            $(this).removeClass("dragsrc dragdest draghover");
            $(this).draggable("option", "disabled", false);
          });
          z++;
        }
      }
    }

    function shiftLeft() {
      for (var y = 0; y < config.yCount; y++) {
        var srcItem = $(".pieces", container).children()[y * config.xCount];
        var destItem = $(".pieces", container).children()[(y + 1) * config.xCount - 1];
        $(srcItem).addClass("dragsrc").insertAfter(destItem);
      }
      animatePieces();
      checkFinish();
      return false;
    }

    function shiftRight() {
      for (var y = 0; y < config.yCount; y++) {
        var srcItem = $(".pieces", container).children()[(y + 1) * config.xCount - 1];
        var destItem = $(".pieces", container).children()[y * config.xCount];
        $(srcItem).addClass("dragsrc").insertBefore(destItem);
      }
      animatePieces();
      checkFinish();
      return false;
    }

    function shiftTop() {
      for (var x = 0; x < config.xCount; x++) {
        var srcItem = $(".pieces li", container).first();
        $(".pieces", container).append(srcItem)
        $(srcItem).addClass("dragsrc");
      }
      animatePieces();
      checkFinish();
      return false;
    }

    function shiftBottom() {
      for (var x = 0; x < config.xCount; x++) {
        var srcItem = $(".pieces li", container).last();
        $(".pieces", container).prepend(srcItem)
        $(srcItem).addClass("dragsrc");
      }
      animatePieces();
      checkFinish();
      return false;
    }

    function bindPieces() {
      $(".pieces li", container).draggable({
        cursor: "pointer", revert: "invalid", revertDuration: config.speed,
        start: function() { $(".pieces li", container).droppable("option", "disabled", false); },
        stop: function() { $(".pieces li", container).droppable("option", "disabled", true); }
      });
      $(".pieces li", container).droppable({
        disabled: true,
        tolerance: "pointer",
        accept: ".pieces li",
        hoverClass: "draghover",
        drop: function(event, ui) {
          $(ui.draggable).addClass("dragsrc").draggable("option", "disabled", true);
          $(this).addClass("dragdest draghover").draggable("option", "disabled", true);

          var srcIndex = ui.draggable.index();
          var destIndex = $(this).index();
          if (srcIndex < destIndex) {
            $(ui.draggable).insertAfter(this);
            var srcItem = $(".pieces", container).children()[srcIndex];
            if (srcItem != this)
              $(this).insertBefore(srcItem);
          }
          else if (srcIndex > destIndex) {
            $(ui.draggable).insertBefore(this);
            var srcItem = $(".pieces", container).children()[srcIndex];
            if (srcItem != this)
              $(this).insertAfter(srcItem);
          }

          animatePieces();
          checkFinish();
        }
      });
    }

    function checkFinish() {
      puzzleMoves++;
      var finished = true;
      var z = 0;
      $(".pieces li", container).each(function() {
        finished &= $(this).hasClass("img_" + z);
        z++;
      });
      if (finished) {
        setTimeout(function() {
          stopPuzzle();
          var minutes = Math.floor(puzzleSeconds / 60);
          var seconds = puzzleSeconds % 60;
          var text = 'Puzzle gel&ouml;st in ';
          if (minutes == 1)
            text = text + '1 Minute und ';
          else if (minutes > 1)
            text = text + minutes + ' Minuten und ';
          if (seconds == 1)
            text = text + '1 Sekunde';
          else
            text = text + seconds + ' Sekunden';
          text = text + '. Herzlichen Gl&uuml;ckwunsch!';
          $(".finished", container).html(text).fadeIn(config.speed * 2);
        }, config.speed);
      }
    }
  }
}; 


