/* Copyright (2008) Jigsawbreak.com. All rights reserved */
function JigSaw() {
  var self = this;
  var jsaw = $('jsaw');
  var numx,numy,dw,dh,pieces,cells;
  var image;
  var jsmoves;
  var fromcell;
  var isIE = navigator.appName == 'Microsoft Internet Explorer';

  function getMovesHTML(maxMoves,moves) {
    var px=1;
    while(px*maxMoves <= 100 && px*moves <= 100) px++;
    var html;
    if(moves < maxMoves) {
      html = "<div style='border:1px solid green;width:"+(px*maxMoves)+"px;height:10px;'>";
      html += "<div style='background-color:#88ff88;width:"+(px*moves)+"px;height:10px;float:left;'></div>";
      html += "<div style='background-color:#eeeeee;width:"+(px*(maxMoves-moves))+"px;height:10px;float:right;'></div>";
      html += "</div>";
    }
    else {
      html = "<div style='border:1px solid green;width:"+(px*moves)+"px;height:10px;'>";
      html += "<div style='background-color:#88ff88;width:"+(px*maxMoves)+"px;height:10px;float:left;'></div>";
      html += "<div style='background-color:#ff8888;width:"+(px*(moves-maxMoves))+"px;height:10px;float:right;'></div>";
      html += "</div>";
    }
    return html;
  }
  function processDrop(dra,dro,event) {
    if(dra.parentNode == dro || fromcell == dro) return;
    self.moves++;
    if(jsmoves) {
       jsmoves.innerHTML = "Moves: "+self.moves+" "+getMovesHTML(cells.length*cells.length,self.moves);
    }
    dra.parentNode.removeChild(dra);
    var op = dro.firstChild;
    var jspieces = $('jsawpieces');
    if(op) {
      var nearby = false;
      for(var y=0;y<cells.length;y++)
        for(var x=0;x<cells.length;x++) {
          if(dro == cells[y][x]) {
            for(var j=y-1;j<cells.length&&j<=y+1;j++) {
              if(j<0) continue;
              var i = x-1; if(i<0) i = 0;
              for(;i<cells.length&&i<=x+1;i++) {
                if(!cells[j][i].firstChild) {
                  cells[j][i].appendChild(op);
                  nearby = true;
                  break;
                }
              }
              if(nearby) break;
            }
            break;
          }
        }
      if(!nearby) {
        if(jspieces.firstChild) 
          jspieces.insertBefore(op,jspieces.firstChild);
        else
          jspieces.appendChild(op);
      }
    }
    dra.style.left = '0';
    dra.style.top = '0';
    dro.appendChild(dra);
    if(jspieces.childNodes.length == 0) {
      if(self.validate()) {
        var img = document.createElement("IMG");
        img.src = image.src;
        img.width = image.width;
        img.height = image.height;
        jsaw.removeChild(jsaw.firstChild);
        jsaw.appendChild(img);
        var maxmoves = pieces.length*pieces.length;
        if(!self.solving) {
          setTimeout('new Effect.Pulsate("'+jsmoves.id+'");alert("Done!")',500);
          // if(pieces.length >= 5 && self.moves < maxmoves)
          new Ajax.Request("completed.do", { parameters : { moves : self.moves, jigsaw : self.jigsawurl.substr(1) } });
        }
        if(self.moves <= maxmoves)
          jsmoves.innerHTML = "<span class='wex'>Moves: "+self.moves+". Excellent!</span>";
        else
          jsmoves.innerHTML = "<span class='wok'>Moves: "+self.moves+". Congratulations!<br>Try doing in "+maxmoves+" or fewer moves.";
      }
    }
    dra.droppable = dro;
  }

  function startMove(e) {
    if(e.parentNode.getAttribute("class") == 'cell') {
      fromcell = e.parentNode;
      document.body.appendChild(e);
    }
  }

  function endMove(e) {
    if(e.droppable) {
      e.droppable = null;
      fromcell = null;
      return false;
    }
    if(fromcell) {
      var curp = Element.cumulativeOffset(e);
      var op = Element.cumulativeOffset(fromcell);
      fromcell.appendChild(e);
      e.style.left = (curp[0]-op[0])+'px';
      e.style.top = (curp[1]-op[1])+'px';
      fromcell = null;
    }
  }

  function revertp(e) {
    endMove(e);
    return true;
  }

  function starth(dra,event) {
    if(!isIE) return;
    startMove(dra.element);
  }

  function getPiece(pieces) {
    var i = 0;
    while(true) {
      i += Math.floor(Math.random()*pieces.length);
      i %= pieces.length;
      if(pieces[i]) return i;
    }
  }

  function createJigSawPuzzle() {
    self.solving = 0;
    jsaw.innerHTML = '';
    if(jsmoves) jsmoves.innerHTML = '';
    self.moves = 0;
    var jsawtable = document.createElement("table");
    jsawtable.setAttribute("cellspacing","0");
    jsawtable.cellSpacing = 0;
    jsawtable.setAttribute("cellpadding","0");
    jsawtable.cellPadding = 0;
    jsaw.appendChild(jsawtable);
    var tbody = document.createElement("tbody");
    jsawtable.appendChild(tbody);
    jsawtable = tbody;
    var lpieces = new Array();
    for(var y=0;y<numy;y++) {
      pieces[y] = new Array();
      cells[y] = new Array();
      var row = document.createElement("tr");
      jsawtable.appendChild(row);
      for(var x=0;x<numx;x++) {
        var col = document.createElement("td");
        var cellid = "jsaw_cell_"+y+"_"+x;
        col.setAttribute("id",cellid);
        col.setAttribute("class","cell");
        col.setAttribute("className","cell");
        col.style.width = dw+'px';
        col.style.height = dh+'px';
        row.appendChild(col);
        var piece = document.createElement('div');
        piece.setAttribute("className","piece");
        piece.setAttribute("class","piece");
        piece.style.width = dw+'px';
        piece.style.height = dh+'px';
        piece.setAttribute("style","width:"+dw+"px;height:"+dh+"px;");
        var ipiece = document.createElement('img');
        ipiece.setAttribute("src",image.src);
        ipiece.width = image.width;
        ipiece.height = image.height;
        ipiece.style.left = -x*dw+"px";
        ipiece.style.top = -y*dh+"px";
        ipiece.setAttribute("style","left:"+(-(x*dw))+"px;top:"+(-(y*dh))+"px;");
        piece.appendChild(ipiece);
        pieces[y][x] = piece;
        lpieces[lpieces.length] = piece;
        cells[y][x] = col;
        Droppables.add(cellid,{ accept: 'piece', hoverclass: 'drophover', onDrop: processDrop });
        var pieceid = "jsaw_piece_"+y+"_"+x;
        piece.setAttribute("id",pieceid);
      }
    }
    var spieces = lpieces.clone();
    for(var y=0;y<numy;y++) {
      for(var x=0;x<numx;x++) {
        var cell = cells[y][x];
        var piece;
        while(true) {
          var pi = getPiece(spieces);
          if(pi == y*numx+x) {
            if(pi == numy*numx-1) {
              var sp = Math.floor(Math.random()*(pieces.length-1));
              var sy = Math.floor(sp/numx);
              var sx = sp%numx;
              spieces[sp] = cells[sy][sx].firstChild;
              cells[sy][sx].replaceChild(spieces[pi],spieces[sp]);
              new Draggable(spieces[pi].id,{ revert: revertp, onStart: starth });
              pi = sp;
            }
            else
              continue;
          }
          piece = spieces[pi];
          spieces[pi] = null;
          break;
        }
        if(piece) {
          cell.appendChild(piece);
          new Draggable(piece.id,{ revert: revertp, onStart: starth });
        }
      }
    }
    $('jsawpieces').style.width = dw+'px';
    jsaw.parentNode.style.height = Element.Methods.getHeight(jsaw)+"px";
  }

  this.validate = function() {
    for(var y=0;y<numy;y++)
      for(var x=0;x<numx;x++)
        if(cells[y][x].firstChild != pieces[y][x]) {
          return false;
        }
    return true;
  }

  var hlcount = 0;
  this.highlightInvalid = function() {
    if(hlcount > 0) return;
    for(var y=0;y<cells.length;y++) {
      for(var x=0;x<cells.length;x++) {
        var piece = cells[y][x].firstChild;
        if(piece && piece != pieces[y][x]) {
          hlcount++;
          new Effect.Pulsate(piece,{ afterFinish : function() { hlcount--; }});
        } 
      }
    }
  }

  this.moveTo = function(piece,j,i,mode) {
    var ps = Element.cumulativeOffset(piece);
    var pd = Element.cumulativeOffset(cells[j][i]);
    startMove(piece);
    var pbs = Element.cumulativeOffset(piece);
    pd[0] -= pbs[0];
    pd[1] -= pbs[1];
    ps[0] -= pbs[0];
    ps[1] -= pbs[1];
    piece.style.top = ps[1]+'px';
    piece.style.left = ps[0]+'px';
    var cell = cells[j][i];
    new Effect.Move(piece,{ x: pd[0]-ps[0], y: pd[1]-ps[1], mode: 'relative', duration: mode == 1 ? 1.0 : 0.8, 
              afterFinish: function() { processDrop(piece,cell); endMove(piece); if(mode == 2) self.solve(mode); } });
    return true;
  }

  this.placePiece = function(piece,mode,blankOnly) {
    for(var j=0;j<cells.length;j++)
      for(var i=0;i<cells.length;i++) {
        if(piece != pieces[j][i]) continue;
        if(blankOnly) {
          if(cells[j][i].firstChild) continue; 
        }
        return this.moveTo(piece,j,i,mode);
      }
    return false;
  }

  this.solveAux = function(mode,blankOnly) {
    for(var y=0;y<cells.length;y++) {
      for(var x=0;x<cells.length;x++) {
        var piece = cells[y][x].firstChild;
        if(piece == pieces[y][x]) continue;
        if(!piece) continue;
        var placed = self.placePiece(piece,mode,blankOnly);
        if(placed)
          if(mode != 3) return true;
      }
    }
    var ps = $('jsawpieces').childNodes;
    for(var i=0;i<ps.length;i++) {
      var placed = self.placePiece(ps[i],mode,blankOnly);
      if(placed)
        if(mode != 3) return true;
    }
    return false;
  }

  // mode: 1 = hint, 2 = solve, 3 = fastsolve;
  this.solve = function(mode) {
    for(var y=0;y<cells.length;y++) {
      for(var x=0;x<cells.length;x++) {
        var piece = cells[y][x].firstChild;
        if(piece == pieces[y][x]) continue;
        if(!piece) continue;
        for(var j=y-1;j>=0&&j<=y+1&&j<cells.length;j++) {
          for(var i=x-1;i>=0&&i<=x+1&&i<cells.length;i++) {
            if(j == y && i == x) continue;
            if(piece != pieces[j][i]) continue;
            return this.moveTo(piece,j,i,mode);
          }
        }
      }
    }
    var placed = this.solveAux(mode,true);
    if(!placed) this.solveAux(mode,false);
  }

  $('jshighlight').onclick = this.highlightInvalid;
  $('jssolve').onclick = function(event) { self.solving = 1; self.solve(2); };
  $('jshint').onclick = function(event) { self.solve(1); };

  this.setSize = function() {
    this.jigsawurl = jsBookmark(image.src);
    $('jsbookmark').href = this.jigsawurl;
    $('jsawpieces').innerHTML = '';
    var w = image.width;
    var h = image.height;
    var size = parseInt($('jssize').value);
    numx = size;
    numy = size;
    dw = parseInt(w/numx);
    dh = parseInt(h/numy);
    pieces = new Array();
    cells = new Array();
    createJigSawPuzzle();
  }

  function jsBookmark(imgurl) {
    var size = parseInt($('jssize').value);
/*
    var url = document.location.href;
    var ind = url.indexOf("/jigsaw/");
    if(ind > 0) {
      url = url.substr(0,ind+8);
    }
    else {
      ind = url.indexOf('?');
      if(ind > 0) url = url.substring(0,ind);
      url += "jigsaw/";
    }
    return url+size+"/"+imgurl.substr(7);
*/
    var url = document.getElementsByTagName("BASE")[0].href;
    return url+"jigsaw/"+size+"/"+imgurl.substr(7);
  }

  this.setImage = function (imgurl) {
    this.jigsawurl = jsBookmark(imgurl);
    $('jsbookmark').href = this.jigsawurl;
    $('jscompletions').innerHTML = '';
    jsaw.innerHTML = 'Loading image ...';
    $('jsawpieces').innerHTML = '';
    var fullimg = $('jsfullimg');
    fullimg.src = 'images/loading.jpg';
    image = new Image();
    image.onload = function() {
      if(this.width > 600) {
        this.height *= 600/this.width;
        this.width = 600;
      }
      if(this.height > 600) {
        this.width *= 600/this.height;
        this.height = 600;
      }
      $('jsimage').value = image.src;
      fullimg.src = image.src;
      fullimg.width = image.width/2 < 200 ? 200 : image.width/2;
      self.setSize();
    }
    image.src = imgurl;
  }
  this.reset = function() { this.setSize(); } 
  this.setMovesElement = function(me) { jsmoves = me; }
}
function jsonFlickrFeed(data) {
  var photo = data.items;
  if(photo) photo = photo[0];
  var img = 'http://farm1.static.flickr.com/42/77156587_fa5aef2c4c.jpg';
  var title = '';
  if(photo) {
    title = photo.title;
    img = photo.media.m;
    img = img.substring(0,img.length-6)+".jpg";
  }
  $('jsfullimg').title = title;
  jsaw.setImage(img);
}

function jsonFlickrApi(data) {
  var photo = data.photos;
  if(photo) photo = photo[0];
  var img = 'http://farm1.static.flickr.com/42/77156587_fa5aef2c4c.jpg';
  var title = '';
  if(photo) {
    title = photo.title;
    img = "http://farm"+photo.farm+".static.flickr.com/"+photo.server+"/"+photo.id+"_"+photo.secret+".jpg";
  }
  $('jsfullimg').title = title;
  jsaw.setImage(img);
}
function jsonFlickrApiSearch(data) {
  var images = $('jsfimages');
  images.innerHTML = '';
  var photos = data.photos;
  if(!photos) return;
  photos = photos.photo;
  for(var i=0;i<photos.length;i++) {
    var photo = photos[i];
    var timg = "http://farm"+photo.farm+".static.flickr.com/"+photo.server+"/"+photo.id+"_"+photo.secret+"_t.jpg";
    var image = document.createElement("IMG");
    image.border = 0;
    image.src = timg;
    image.title = photo.title;
    var link = document.createElement("A");
    link.href = '';
    link.appendChild(image);
    link.img = "http://farm"+photo.farm+".static.flickr.com/"+photo.server+"/"+photo.id+"_"+photo.secret+".jpg";
    link.onclick = function(event) {
      jsaw.setImage(this.img);
      return false;
    }
    images.appendChild(link);
    if(i == photos.length/2 - 1)
       images.appendChild(document.createElement('BR'));
  }
}

function searchFImages() {
  var text = $('jsquery').value;
  if(!text) return false;
  $('jsfimages').innerHTML = 'Searching Flickr ...';
  jsonFlickrApi = jsonFlickrApiSearch;
  var fscript = $('flickrscript');
  if(fscript) fscript.parentNode.removeChild(fscript);
  fscript = document.createElement("script");
  fscript.id = 'flickrscript';
  fscript.src = 'http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=0ee97016b0849d509a454bfdb592840f&per_page=10&page=1&format=json&sort=relevance&text='+text;
  document.body.appendChild(fscript);
  return false;
}

function GApp() {
  this.searchControl = new google.search.SearchControl();
  this.searchControl.setResultSetSize(google.search.Search.LARGE_RESULTSET);
  var options = new google.search.SearcherOptions();
  options.setExpandMode(google.search.SearchControl.EXPAND_MODE_OPEN);
  var searcher = new google.search.ImageSearch();
  searcher.setRestriction(google.search.ImageSearch.IMAGESIZE_LARGE);
  this.searchControl.addSearcher(searcher);
  this.searchControl.draw($('gdummy'));
  this.searchControl.setSearchCompleteCallback(this,GApp.prototype.OnSearchComplete);
}

GApp.prototype.OnSearchComplete = function(sc,searcher) {
  var images = $('jsgimages');
  images.innerHTML = '';
  if(searcher.results && searcher.results.length < 0) {
    images.innerHTML = "No results found. Please try again";
    return;
  }
  for(var i=0;i<searcher.results.length;i++) {
    var result = searcher.results[i];
    var img = document.createElement("IMG");
    img.title = result.title+" ("+result.width+" x "+result.height+")";
    img.src = result.tbUrl;
    img.border = 0;
    var link = document.createElement("A");
    link.href = '';
    link.appendChild(img);
    link.result = result;
    link.onclick = function() {
    var imgurl = this.result.unescapedUrl;
    $('jsimage').value = imgurl;
    jsaw.setImage(imgurl);
      return false;
    }
    images.appendChild(link);
    if(i == searcher.results.length/2 - 1) {
      images.appendChild(document.createElement("BR"));
    }
  }
}

var gapp;
function ginit() {
  gapp = new GApp();
}

function searchGImages() {
  if(!gapp) {
    setTimeout(searchGImages,500);
    return;
  }
  var input = $('jsquery');
  if(!input.value) return false;
  $('jsgimages').innerHTML = 'Searching Google ...';
  gapp.searchControl.execute(input.value);
  return false;
}

function searchImages() {
  searchGImages();
  searchFImages();
}

function doSearch(str) {
  $('jsquery').value = str;
  searchImages();
}

function wodjigsaw(wodid) {
  var jse = document.createElement("SCRIPT");
  jse.onload = function() {
    var wod = window.WordOfTheDay;
    $(wodid).innerHTML = '';
    if(wod) {
      var wl = document.createElement("A");
      wl.href = '';
      wl.innerHTML = wod[0];
      wl.title = wod[1]+": "+wod[2];
      wl.onclick = function() { doSearch(this.innerHTML); return false; };
      $(wodid).appendChild(wl);
    }
    else {
      $(wodid).innerHTML = '?';
    }
  };
  jse.onreadystatechange = function() { if(this.readyState == 2 || this.readyState == 4 || this.readyState == 'loaded' || this.readyState == 'complete') this.onload(); };
  jse.src = "http://www.thefreedictionary.com/_/WoD/jsa.aspx";
  document.getElementsByTagName('HEAD')[0].appendChild(jse);
}
