// JavaScript 15 by Jesse Ruderman http://www.squarefree.com/
// Based on ideas from http://www.dragonflydigital.com/samples/imedia/puzzle.html
// 08/07/01

image = null;

R = /image=([^&]*)/; 
if (x=R.exec(location.search)) 
  image = unescape(x[1]);

if (!image)
  image = "http://www.gaoshukai.com/album/m/0030.jpg";

document.f.image.value = image;

scramble = false;
R = /scramble=([^&]*)/; 
if (x=R.exec(location.search) && x[1].toString())
  scramble = true;

function makeGame(im) // takes an image node
{

var width, height, tileWidth, tileHeight, 
width = im.width; // or naturalWidth, or computed width...
height = im.height;

// Allow bottom/right of image to be cut off. better than introducing Obvious White Pixels and 
// giving away where the edge is.

tileWidth = parseInt(width/4);
tileHeight = parseInt(height/4);

var tiles = [[],[],[],[]];
var grid = [[],[],[],[]];

var game = document.createElement("div");
game.className = "game";
game.style.position = "absolute"; // give tiles something to "stick" to
game.style.width = width + "px";
game.style.height = height + "px";


var theEmptyT, emptyp, emptyq;

for (var i=0; i<4; ++i)
 for (var j=0; j<4; ++j)
 {
  var t = document.createElement("div");
  var x = i * tileWidth;
  var y = j * tileHeight;

  t.style.position = "absolute";
  t.style.width = tileWidth + "px";
  t.style.height = tileHeight + "px";

  t.style.backgroundImage = "url(" + im.src + ")";
  t.style.backgroundAttachment = "scroll";
  t.style.backgroundPosition = "-" + x + "px -" + y + "px";
  t.style.backgroundRepeat = "no-repeat";

  // setting using shorthand works in ie but not in moz:
  // t.style.background = "url(" + im.src + ") scroll -" + x + " -" + y + " no-repeat";
 
  t.className = "tile";

  if (i == 3 && j == 3)
  {
    t.style.display = "none"; // hide last block until game is over
    t.isEmpty = true;
    theEmptyT = t;
    t.className = "empty";
  }

  // i,j is original position. used to determine when you've won.
  t.i = i;
  t.j = j;
  // p,q is current position. initially set by repositionAll();

  grid[i][j] = t;

  t.onclick = 
    function()
    {
      var p = this.p;
      var q = this.q;
      if (p == emptyp) // horizontally in line with empty square
      {
        if (q < emptyq) // empty square is to my right
          for (j=emptyq; j!=q; --j)
            grid[emptyp][j] = grid[emptyp][j - 1];
        else
          for (j=emptyq; j!=q; ++j)
            grid[emptyp][j] = grid[emptyp][j + 1];
        grid[p][q] = theEmptyT;
      } 
      else if (this.q == emptyq) // vertically in line with empty square
      {
        if (p < emptyp) // empty square is to my right
          for (i=emptyp; i!=p; --i)
            grid[i][emptyq] = grid[i - 1][emptyq];
        else
          for (i=emptyp; i!=p; ++i)
            grid[i][emptyq] = grid[i + 1][emptyq];
        grid[p][q] = theEmptyT;
      }
      repositionAll();
    }

  game.appendChild(t);
 } // huge for loop to create tiles

function gradual(ob, prop, start, fin)
{
  var n = 5;
  var step = (fin - start) / n;
  ob[prop] = start;
  for (var i=1; i<=n; ++i)
   (function(){
     var I = i;
     setTimeout(function() { ob[prop] = (start + step*I) + "px"; }, 30*i)
   })()
     
}

function repositionAll()
{
  var correct = 0, i, j;

  for (i=0; i<4; ++i)
   for (j=0; j<4; ++j)
   {
     t = grid[i][j];
     if (t.p != i)
     {
       if (t.p != null && !t.isEmpty)
         gradual(t.style, "left", tileWidth * t.p, tileWidth * i)
       else
         t.style.left = tileWidth * i + "px";
       t.p = i;
     }
     if (t.q != j)
     {
       if (t.q != null && !t.isEmpty)
         gradual(t.style, "top", tileHeight * t.q, tileHeight * j)
       else  
         t.style.top = tileHeight * j + "px";
       t.q = j;
     }
     if (t.isEmpty)
     {
       emptyp = i;
       emptyq = j;
     }
     if (t.i == i && t.j == j)
       ++correct;
   }

   theEmptyT.style.display = (correct == 16) ? "block" : "none";
   game.style.borderColor = (correct == 16) ? "#FFF" : "#FFF";
}

repositionAll();

if (scramble)
{

  for (var s = 0; s < 128; ++s)
  {
    var r = Math.random();
    var sp, sq;
    if (r < .5)
    {
      sp = emptyp + (r < .25 ? 1 : -1);
      sq = emptyq;
    }
    else
    {
      sp = emptyp;
      sq = emptyq + (r > .75 ? 1 : -1);
    }

    // "reflect" if try to swap with something outside of board

    if (sp == -1) sp = 1;
    if (sp == 4) sp = 2;
    if (sq == -1) sq = 1;
    if (sq == 4) sq = 2;

    var swaptemp = grid[sp][sq];
    grid[sp][sq] = grid[emptyp][emptyq];
    grid[emptyp][emptyq] = swaptemp;
    emptyp = sp;
    emptyq = sq;
  }
} // if scramble

repositionAll();
var par = im.parentNode;
par.insertBefore(game, im);
par.removeChild(im);

} // function makeGame

function replaceImage()
{
  var url = document.f.image.value;
  var im = document.createElement("img");
  var h = document.getElementById("imageHolder");
  while (h.firstChild)
    h.removeChild(h.firstChild);
  h.appendChild(im);
  im.onload = function() { makeGame(this); }
  im.src = url;
}


