bgcolor = "#fff";
errcolor = "#f00";
bgactive = "#B6E673";
activesq  = null;

function getEl(id) {
  return document.getElementById(id);
}

function Board() {
  this.available = new Array(9);
  this.placed    = new Array(9);
  this.setDone   = false;

  for (var r = 0; r < 9; r++) {
    this.available[r] = new Array(9);
    this.placed[r]    = new Array(9);

    for (var c = 0; c < 9; c++) {
      this.available[r][c] = new Array(0,1,1,1,1,1,1,1,1,1);
      this.placed[r][c]    = 0;
    }
  }

  this.updatePencil = function(r, c) {
    var av = this.available[r][c];
    var str = '';
    for (var i = 1; i < av.length; i++) {
      str += (1 == av[i] ? i : '&nbsp;');
      if (3 == i || 6 == i) {
        str += '<br />';
      }
      else if (9 > i) {
        str += '&nbsp;';
      }
    }

    var sq = getSquare(r, c);
    var pencil = getPencil(sq);
    pencil.innerHTML = str;
  }

  this.getAffected = function(r_set, c_set) {
    var aff = new Array(27);
    var i = 0;
    for (var r = 0; r < 9; r++) {
      aff[i++] = new Array(r, c_set);
    }
    for (var c = 0; c < 9; c++) {
      aff[i++] = new Array(r_set, c);
    }
    for (var r = 3 * Math.floor(r_set / 3);
         r < 3 * (1 + Math.floor(r_set / 3));
         r++) {
      for (var c = 3 * Math.floor(c_set / 3);
           c < 3 * (1 + Math.floor(c_set / 3));
           c++) {
        aff[i++] = new Array(r, c);
      }
    }
    return aff;
  }

  this.updateLocation = function(r_set, c_set) {
    var av = new Array(0,1,1,1,1,1,1,1,1,1);
    var aff = this.getAffected(r_set, c_set);
    for (var i = 0; i < aff.length; i++) {
      av[this.placed[aff[i][0]][aff[i][1]]] = 0;
    }
    this.available[r_set][c_set] = av;
    this.updatePencil(r_set, c_set);
  }

  this.updateAffectedLocations = function(r_set, c_set) {
    var aff = this.getAffected(r_set, c_set);
    for (var i = 0; i < aff.length; i++) {
      this.updateLocation(aff[i][0], aff[i][1]);
    }
  }

  this.findBlocker = function(val, r_set, c_set) {
    var sq = null;
    var aff = this.getAffected(r_set, c_set);
    for (var i = 0; i < aff.length; i++) {
      if (val == this.placed[aff[i][0]][aff[i][1]]) {
        sq = getSquare(aff[i][0], aff[i][1]);
        return sq;
      }
    }
    return sq;
  }

  this.place = function(val, r, c) {
    var av = this.available[r][c];
    var placed = false;
    if ((this.setDone && getEl('impossibles_permit').checked) || 1 == av[val]) {
      this.placed[r][c] = val;
      this.updateAffectedLocations(r, c);
      placed = true;
    }
    return placed;
  }

  this.unplace = function(r, c) {
    this.placed[r][c] = 0;
    this.updateAffectedLocations(r, c);
  }

}


function clearListener() {
  if (activesq) {
    activesq.style.backgroundColor = bgcolor;
    activesq = null;
  }
  document.onkeypress = null;
}

function setListener(sq) {
  clearListener();
  sq.style.backgroundColor = bgactive;
  activesq = sq;
  document.onkeypress = setSquare;
}

function setSquare(e) {
  var k = (e == null ? event.keyCode : e.which);
  if (activesq) {
    var r = activesq.getAttribute('row');
    var c = activesq.getAttribute('col');
    var activepen = getPen(activesq);
    var activepencil = getPencil(activesq);

    if (47 < k && k < 58) {
      var val = String.fromCharCode(k);
      if (myBoard.place(val, r, c)) {
        activepencil.style.visibility = 'hidden';
        activepen.innerHTML = val;
      }
      else {
        var sq = myBoard.findBlocker(val, r, c);
        blinkSquare(sq, errcolor);
      }
    }
    else if (8 == k || 127 == k) {
      myBoard.unplace(r, c);
      activepen.innerHTML = ' ';
      if (getEl('pencil_show').checked) {
        activepencil.style.visibility = 'visible';
      }
    }
  }
  clearListener();
  return false;
}

function blinkSquare(sq, color) {
  if (sq) {
    var sqjs = getSquareJS(sq);
    var rate = 100;
    for (var i = 0; i < 4; i++) {
      var delay = i * 2 * rate;
      setTimeout(sqjs + '.style.backgroundColor = errcolor', rate     + delay);
      setTimeout(sqjs + '.style.backgroundColor = bgcolor',  (rate*2) + delay);
    }
  }
}

function getSquare(r, c) {
  return getEl('sq_' + r + '_' + c);
}

function getSquareJS(sq) {
  var r = sq.getAttribute('row');
  var c = sq.getAttribute('col');
  return "document.getElementById('sq_" + r + "_" + c + "')";
}

function getPen(sq) {
  var id = 'pen_' + sq.getAttribute('row') + '_' + sq.getAttribute('col');
  return getEl(id);
}

function getPencil(sq) {
  var id = 'pencil_' + sq.getAttribute('row') + '_' + sq.getAttribute('col');
  return getEl(id);
}

function showAllPencil(show) {
  var vis = (show ? 'visible' : 'hidden');
  var sq;
  var pencil;
  for (var r = 0; r < 9; r++) {
    for (var c = 0; c < 9; c++) {
      if (0 == myBoard.placed[r][c]) {
        sq = getSquare(r, c);
        pencil = getPencil(sq);
        pencil.style.visibility = vis;
      }
    }
  }
}












function setBoard() {
  var sq;
  var pen;

  for (var r = 0; r < 9; r++) {
    for (var c = 0; c < 9; c++) {
      sq = getEl('sq_' + r + '_' + c);
      pen = getPen(sq);
      if ('' == pen.innerHTML) {
        pen.style.fontFamily = "'Comic Sans MS', 'Trebuchet MS', 'Arial', sans-serif";
        pen.style.color = "#55c";
        pen.style.fontStyle = "italic";
      }
      else {
        sq.onclick = null;
      }
    }
  }
  getEl('setboardbtn').disabled = true;
  getEl('pencil_none').disabled = false;
  getEl('pencil_show').disabled = false;
  getEl('impossibles_permit').disabled = false;
  getEl('impossibles_deny').disabled = false;
  myBoard.setDone = true;
}


myBoard = new Board();

function bodyOnLoad() {
  getEl('pencil_none').disabled = true;
  getEl('pencil_show').disabled = true;
  getEl('pencil_none').checked  = true;
  getEl('pencil_show').checked  = false;

  getEl('impossibles_permit').disabled = true;
  getEl('impossibles_deny').disabled   = true;
  getEl('impossibles_permit').checked  = false;
  getEl('impossibles_deny').checked    = true;
}