var field = null;
var game = null;
var fieldStats = [
  {level: 1, highscores: 11},
  {level: 2, highscores: 11},
  {level: 3, highscores: 11},
  {level: 4, highscores: 11},
  {level: 5, highscores: 11}
];
var difficulties = ["beginner", "easy", "normal", "hard", "extreme"];
var difficulty = null;
var puzzlesource = null;
var strings = null;
var lastUpdate = 0;

function loadStrings() {
  var lang = getCookie("sd-lang");
  if (!lang) lang = getCookie("lang");
  if (!lang && navigator && (navigator.language || navigator.userLanguage)) {
    var l = navigator.language ? navigator.language : navigator.userLanguage;
    var i = l.indexOf("-");
    if (i != -1)
      l = l.substr(0, i);
    if (langstrings[l])
      lang = l;
  }
  if (!langstrings[lang])
    lang = "en";
  if (!getCookie("lang"))
    setCookie("lang", lang);
  setCookie("sd-lang", lang);
  if (strings == langstrings[lang]) return;
  strings = langstrings[lang];
  $("difficultylbl").innerHTML = strings["choosedifficulty"];
  $("intro0").innerHTML = strings["intro0"];
  $("intro1").innerHTML = strings["intro1"];
  $("intro2").innerHTML = strings["intro2"];
  $("introlbl").innerHTML = strings["sudoku"];
  $("highscoreslbl").innerHTML = strings["highscores"];
  $("nameinput").observe("keypress", onNameInput);
  $("namelbl").innerHTML = strings["name"];
  $("playagain").innerHTML = strings["playagain"];
  $("changedifficulty").innerHTML = strings["changedifficulty"];
  $("instructions").innerHTML = strings["instructions"];
  $("newslbl").innerHTML = strings["recenthighscores"];
  $("commentz").innerHTML = strings["commentsplz"];
  $("commentz2").innerHTML = strings["commentsplz"];
  $("unassign").setAttribute("title", strings["unassign"]);
  $("giveup").innerHTML = strings["giveup"];
  for (var i = 0; d = difficulties[i]; ++i) {
    $(d + "lbl").innerHTML = strings[d];
    $(d + "desc").innerHTML = ""; //strings[d];
  }
}

function initialize() {
  loadStrings();
  for (var i = 0; d = difficulties[i]; ++i) {
    var fn = function(j) {
      $(d).observe("click", function() { onDifficulty(j); });
    };
    fn(i);
  }
  new Effect.Appear($("start"));
  puzzlesource = new Puzzlesource();
  if (initialPuzzles)
    initialPuzzles.each(function(f) { puzzlesource.push(f); });
  var langs = langstrings.keys();
  $("languages").innerHTML =
    langs.collect(function(l) {
		    return '<a href="javascript:changeLanguage(\'' + l + '\')">' + langstrings[l]["languagename"] + '</a>';
		  }).join(" &mdash; ");
  $("start").setStyle({visibility: "visible"});
  lastUpdate = getTime();
  showRecentHighscores();
  $("showmarkup").observe("change", onShowMarkup);
}

function onShowMarkup() {
  var on = $F("showmarkup");
  if (on) {
    field.showMarkup();
    flashMarkupElements(true);
  }
  else field.hideMarkup();
}

function flashMarkupElements(on) {
  var elms = document.getElementsByClassName("markup");
  elms.each(function(e) {
	      e.setStyle({backgroundColor: on ? "red" : "transparent"});
	    });
  if (on) setTimeout(flashMarkupElements, 200);
}

function changeLanguage(l) {
  setCookie("sd-lang", l);
  if (!getCookie("lang")) setCookie("lang", l);
  loadStrings();
  showRecentHighscores();
}

function onDifficulty(lvl) {
  if (difficulty != null) return;
  difficulty = lvl;
  if (!standalone && !puzzlesource.has(lvl + 1))
    puzzlesource.request(lvl + 1);
  var effects = [];
  for (var i = 0; i < difficulties.length; ++i)
    if (i != lvl)
      effects.push(new Effect.Fade($(difficulties[i]), { from: 1, to: 0.1, duration: 0.4, sync: true }));
  new Effect.Parallel(effects, { afterFinish: fadeoutStart, delay: 0.01 });
}

function fadeoutStart() {
  if (Prototype.Browser.IE) {
    var effects = [];
    effects.push(new Effect.Fade($("start"), { sync: true }));
    for (var i = 0; d = difficulties[i]; ++i)
      effects.push(new Effect.Fade($(d + "lbl"), { sync: true }));
    new Effect.Parallel(effects, { delay: 0.1, afterFinish: showGame });
  }
  else
    new Effect.Fade($("start"), { delay: 0.1, afterFinish: showGame });
}

function showRecentHighscores() {
  if (!recentHighscores) return;
  var str = '<table>';
  var lastlvl = 0;
  var lines = 0;
  var since = parseInt((getTime() - lastUpdate) / 1000);
  for (var i = 0; (h = recentHighscores[i]) && lines < 12; ++i) {
    if (h[0] != lastlvl) {
      str += '<tr><td' + (lastlvl != 0 ? ' style="padding-top: 8px"' : '') + '><h3>' + strings[difficulties[h[0] - 1]] + "</h3></td></tr>";
      lastlvl = h[0];
      ++lines;
    }
    str += '<tr><td>' + formatSeconds(h[1]) + ' <b>' + h[2] + "</b></td></tr>";
    str += '<tr><td><small>' + formatAgo(h[3] + since) + '</small></td></tr>';
    lines += 2;
  }
  str += '</table>';
  $("newsdiv").innerHTML = str;
}

function showGame() {
  $("start").style.visibility = "hidden";
  $("game").style.visibility = "visible";
  //  new Effect.Appear($("game"), { afterFinish: constructGame });
  constructGame();
}

function constructGame() {
  game = new Game();
  game.construct(fieldStats[difficulty]);
}

function playAgain() {
  game.reset();
  game.hideCurtain();
}

function changeDifficulty() {
  //  new Effect.Fade($("game"), { afterFinish: showStart });
  game.hideCurtain();
  showStart();
}

function showStart() {
  difficulty = null;
  $("game").style.visibility = "hidden";
  game.destruct();
  $("start").setStyle({opacity: 0});
  $("start").style.visibility = "visible";
  new Effect.Appear($("start"));
  difficulties.each(function(id) {
		      $(id).setStyle({opacity: 1});
		    });
  showRecentHighscores();
}

function onNameInput(evt) {
  if (evt.keyCode != Event.KEY_RETURN) return;
  var name = $F("name");
  if (name.length == 0) return;
  registerHighscore(name);
  if (game) game.submitHighscoreName(name);
}

var Puzzlesource = Class.create();
Puzzlesource.prototype = {
  initialize: function() {
    this.data = $A([$A(), $A(), $A(), $A(), $A()]);
    this.requesting = false;
  },

  push: function(x) {
    this.data[x.lvl - 1].push(x.grid);
  },

  has: function(lvl) {
    return this.data[lvl - 1].length > 0;
  },

  get: function(lvl) {
    var ary = this.data[lvl - 1];
    if (ary.length <= 1) this.request(lvl);
    return ary.shift();
  },

  count: function(lvl) {
    return this.data[lvl - 1].length;
  },

  request: function(lvl) {
    if (this.requesting) return;
    this.requesting = true;
    new Ajax.Request(baseUrl + "fetch/" + lvl,
		     {
		     method: "post",
			 parameters: {
		       level: lvl.toString()
			   },
			 onSuccess: this.fieldFetched.bind(this),
			 onFailure: this.onFailure.bind(this)
			 });
  },

  fieldFetched: function(req) {
    var res = req.responseText.evalJSON();
    for (var i = 0; i < res.fields.length; ++i)
      this.push(res.fields[i]);
    this.requesting = false;
  },

  onFailure: function() {
    this.requesting = false;
  }
};

var assigns = $A();

function reportAssign(r, c, n, immediate) {
  if (!game.online) return;
  assigns.push([r, c, n]);
  if (immediate) scheduleReport(null);
}

var reportTimeout = null;
var reporting = false;

function scheduleReport(secs) {
  if (!game.online) return;
  var int = secs ? secs * 1000 : 50;
  clearTimeout(reportTimeout);
  reportTimeout = setTimeout(sendReport, int);
}

function stopReporting() {
  clearTimeout(reportTimeout);
}

function sendReport() {
  if (!game.online) return;
  if (reporting) {
    scheduleReport(1);
    return;
  }
  if (assigns.length == 0) {
    scheduleReport(10);
    return;
  }
  reporting = true;
  var old = assigns;
  assigns = $A();
  var str = old.flatten().join("x");
  new Ajax.Request(baseUrl + "assign",
		   {
		   method: "post",
		       parameters: {
		     level: field.stats.level,
			 field: field.id,
			 coords: str
			 },
		       onSuccess: onReportSuccess,
		       onFailure: onReportFailure
		       });
}

function onReportSuccess(req) {
  reporting = false;
  scheduleReport(60);
  var res = req.responseText.evalJSON();
  debugmsg("res: " + res.r);
  if (res.r != "ok" && res.r != "end")
    game.goOffline();
  if (res.r == "end") {
    game.gameTime = res.time;
    game.highscoresReceived(res.hs, res.gratz);
    game.updateTime();
    if (res.rhs) {
      recentHighscores = res.rhs;
      lastUpdate = getTime();
    }
  }
}

function onReportFailure(req) {
  reporting = false;
  scheduleReport(1);
  debugmsg("report failure");
}

function debugmsg(msg) {
  if (debug)
    window.status = msg;
}

function registerHighscore(name) {
  new Ajax.Request(baseUrl + "register", {
    method: "POST",
		       parameters: {
		     name: name
			 }
    });
  if (!recentHighscores) return;
  var diff = parseInt((getTime() - lastUpdate) / 1000);
  recentHighscores.unshift([field.stats.level, game.gameTime, name, diff]);
}

function giveUp() {
  assigns.push("giveup");
  game.gameOver(false);
}

