var SOLUTION_ID = 0;
var LAYOUT_ID = 0;
var GS_INITIAL = 3;
var GS_MAX = 6; // glue-saw limiter (3 glues + 3 saws)
var GS_COUNT = GS_INITIAL; // glue-saw counter
var HARDCORE_SECTION_PATH = "";

var GAME_OVER_SHOWN = false;

var LC_CODE = "en";

var goWrap;

var hintEl;
var currentHint;
var hintsNum = 0;

var CPLX = 1;
var CPLX_MAX = 2;
var CPLX_MIN = 0;

var DEFAULT_LY_SIZE_SQUARES = 0;
var SQUARE_SIZE = 0;

var TIMEOUT_SWITCH_HINT = 15000;
var SWITCH_HINT_DO = true;
var HINTS = { glue: 2, saw: 2, randomm: 5, enter: 1 };

var glued = new Array();
var sawed = new Array();

$(document).ready(function() {

  CPLX = 1;

  if ($.cookie("idh_cplx") != null) {
    CPLX = parseInt($.cookie("idh_cplx"));
  }

  updateLayoutId();
  adjustPageLayout();

  //initOutButtons();
  //initRegisterForm();
  //initLoginForm();



  initLogoutBtn();
  initSavedBtn();
  initSaveBtn();
  initNewBtn();
  initCplxBtn();
  initLayoutBtn();
  initFlushBtn();
  initRemoveBtn();

  initSavedCont();

  initAddQuestionForm();

  initBombBtn();
  initRandomBtn();
  initEnterBtn();

  initHints();
  initButtonHints();

  initGameOver();

  LC_CODE = $("#lc_code_value").val();

  logg("init okay, LOGD=" + LOGD);

});

var adjustPageLayout = function() {

  var square_size = parseInt($("#square_size").val());

  var ly_bk_w = parseInt($("#ly_back_width").val());
  var ly_bk_h = parseInt($("#ly_back_height").val());

  var x_len = parseInt($("#ly_x_len").val());
  var y_len = parseInt($("#ly_y_len").val());

  var default_ly_size_px = parseInt($("#default_ly_size_px").val());

  var ly_ml = 0;
  var ly_mt = 0;

  if (ly_bk_w < default_ly_size_px) {

    ly_ml = Math.round((default_ly_size_px - ly_bk_w)/2);
    $("#ly").css({
        left: ly_ml + "px",
    });

    ly_bk_w = default_ly_size_px;
    if ($(document).width() < 1200) {
      $("#left-sidebar").css("width", "55%");
      //$("#content").css("marginLeft", "60%");
    }
  } else {
    if ($(document).width() < 1200) {
      $("#left-sidebar").css("width", "63%");
      //$("#content").css("marginLeft", "68%");
    } else {
      $("#left-sidebar").css("width", "55%");
      //$("#content").css("marginLeft", "60%");
    }
  }

  if (ly_bk_h < default_ly_size_px) {

    ly_mt = Math.round((default_ly_size_px - ly_bk_h)/2);
    $("#ly").css({
        top: ly_mt + "px" // ie7 won't accept comma here
    });
    ly_bk_h = default_ly_size_px;
  }

  $("#layout_wrap").css({
      "width": ly_bk_w + "px",
      "height": ly_bk_h + "px" // ie7 won't accept comma here // line 174
  });

  //$("#ls_body").css("width", (ly_bk_w + 99) + "px"); //
  $("#ls_body").css("width", (ly_bk_w + 99) + "px"); //

  //if (ly_bk_h < default_ly_size_px) {

  //}

  $("#sub_icons").css("width", (ly_bk_w-60) + "px");
  $("#hint").css("width", (ly_bk_w) + "px");
  $("#sup_logo, #logo_wrap, #global_feedback").css("width", (ly_bk_w-20) + "px");

}

var updateLayoutId = function() {
  LAYOUT_ID = parseInt($("#ly_id").val());
}

var initOutButtons = function() {
  $("#register_form_btn").click(function() {
    $("#register_form_wrap").toggle();
    return false;
  }).mouseover(function() {
    $("#register_btn_title").css("display", "inline");
  }).mouseout(function() {
    $("#register_btn_title").css("display", "none");
  });

  $("#login_form_btn").click(function() {
    $("#login_form_wrap").toggle();
    return false;
  }).mouseover(function() {
    $("#login_btn_title").css("display", "inline");
  }).mouseout(function() {
    $("#login_btn_title").css("display", "none");
  });
}

var initSavedList = function() {
  $("#saved_list li").click(function() {
    var solId = parseInt($(this).attr("id").split("_")[2]);
    var postData =
      "sol_id=" + solId;

    led.on();
    $.ajax({
      type: "POST",
      url: CONTEXT_PATH + "x/solution_load",
      data: postData,
      success: function(rawResponse) {
        led.off();
        var bits = rawResponse.split("|||");

        var newLyWrap = $(document.createElement("div"));
        newLyWrap.attr("id", "ly_wrap");
        newLyWrap.html(bits[0]);
        //$("#ly_wrap").before(newLyWrap).remove();
        $("#ly_wrap").replaceWith(newLyWrap);

        ly_cont = $("#ly_wrap");

        var newQu = $(document.createElement("div"));
        newQu.attr("id", "qu");
        newQu.html(bits[1]);
        $("#qu").before(newQu).remove();

        SOLUTION_ID = solId;

        adjustPageLayout();

        initStarts();
        initSquares();
        initQuestions();
        //initSaveBtn();
        initEnterBtn();

        updateLayoutId();
        showRemoveBtn();

        putGlyphs();

        hideSavedCont();
        resetGlueSawCounter();

        GAME_OVER_SHOWN = false;


      },
      error: function(request, error) {
        led.off();
        messageError("Something went terribly wrong");
      }
    });
  });
}

var initLayoutBtn = function() {
  $("#layout_btn").click(function() {
    $("#new_btn_wrap").toggle();
  });
}

var initLogoutBtn = function() {
//  $("#logout_btn").click(function() {
//    return true;
//  }).mouseover(function() {
//    $("#logout_btn_title").css("display", "inline");
//  }).mouseout(function() {
//    $("#logout_btn_title").css("display", "none");
//  });
//  $("#btn_logout_wrap")
//  .mouseenter(function() {
//    $("#logout_username").show();
//  })
//  .mouseleave(function() {
//    $("#logout_username").hide();
//  });
}

var initSavedBtn = function() {
  $("#btn_saved").click(function() {

    if (LOGD == false) {
      alert("Please, log in first");
      // TODO make something friendlier here
      return false;
    }

    var savedListEl = $("#saved_list");
    if (savedListEl.is("div")) {
      logg("saved list present");
      toggleSavedCont();
      return;
    }
    var data = "";

    led.on();
    $.ajax({
      type: "POST",
      url: CONTEXT_PATH + "x/solutions_list",
      data: data,
      dataType: "json",
      success: function(response) {
        led.off();
        if (response.status) {
          addSavedList(response.sol_list);
          $("#saved_list").show();
        } else {
          messageError(response.msg_text);
        }
      },
      error: function(request, error) {
        led.off();
        messageError("Something went terribly wrong");
      }
    });

    return false;
  }).mouseover(function() {
    $(this).attr("src", CONTEXT_PATH + "static/img/icon_load_hl.png");
  }).mouseout(function() {
    $(this).attr("src", CONTEXT_PATH + "static/img/icon_load.png");
  });
}

var initSavedCont = function() {
  var cont = $("#saved_list_wrap").eq(0);
  cont.fadeTo(300, 0, function() {
    //$(this).css("display", "block");
  });
}

var showSavedCont = function() {
  var cont = $("#saved_list_wrap").eq(0);
  cont.css("display", "block");
  cont.fadeTo(300, 1);
}

var hideSavedCont = function() {
  var cont = $("#saved_list_wrap").eq(0);
  cont.fadeTo(300, 0, function() {
    cont.css("display", "none");
  });
}

var flushSavedCont = function() {
  var cont = $("#saved_list_wrap").eq(0);
  cont.removeClass("sh");
  cont.slideUp("normal", function() {
    $("#saved_list").remove();
  });
}

var toggleSavedCont = function() {
  var wrap = $("#saved_list_wrap");
  wrap.stop(true, true);
  if (wrap.css("display") == "block") {
    hideSavedCont();
  } else {
    showSavedCont();
  }

}

var initSaveBtn = function() {
  $("#btn_save").click(function() {
    if (LOGD == false) {
      messageError($("#message_login_first").val());
      return false;
    }
    saveSolution();
    return false;
  }).mouseover(function() {
    $(this).attr("src", CONTEXT_PATH + "static/img/icon_save_hl.png");
  }).mouseout(function() {
    $(this).attr("src", CONTEXT_PATH + "static/img/icon_save.png");
  });
}

var initNewBtn = function() {
  $("#btn_new").click(function() {
    //var comp = parseInt($(this).attr("id").split("_")[1]);
    //newLayout(0);
    //$("#wrap_complexity_selector").toggle();
    newLayout(CPLX);
    return false;
  }).mouseover(function() {
    $(this).attr("src", CONTEXT_PATH + "static/img/icon_new_hl.png");
  }).mouseout(function() {
    $(this).attr("src", CONTEXT_PATH + "static/img/icon_new.png");
  });
}

var initCplxBtn = function() {
  /*$("#wrap_complexity_selector>a").click(function() {
    var btn = $(this);
    var cplx = parseInt(btn.attr("id").substring(btn.attr("id").lastIndexOf("_")+1));
    btn.parent().hide(); // hide complexity selector
    newLayout(cplx);
  });*/
  $("#btn_cplx").attr("src", CONTEXT_PATH + "static/img/icon_cplx_"
      + CPLX.toString() + ".png");
  $("#btn_cplx").click(function() {
    toggleCplx();
  });
}

var toggleCplx = function() {
  if (CPLX >= CPLX_MAX) {
    CPLX = CPLX_MIN;
  } else {
    CPLX = CPLX + 1;
  }

  $.cookie("idh_cplx", CPLX, { expires: 120 });

  $("#btn_cplx").attr("src", CONTEXT_PATH + "static/img/icon_cplx_"
      + CPLX.toString() + ".png");
}

var initFlushBtn = function() {
  $("#flush_btn").click(function() {
    if (confirm("Really? Delete everything? EVERYTHING?")) {
      flushSolution();
      // TODO ALSO RESET ALL GLUES AND SAWS
    }
    return false;
  });
}

var initRemoveBtn = function() {
  var btn = $("#remove_btn");
  btn.fadeTo(0,0);
  btn.css("display", "inline");
  btn.click(function() {
    if (confirm("You will now delete saved solution.")) {
      removeSolution();
    }
    return false;
  });
}

var showRemoveBtn = function() {
  $("#remove_btn").fadeTo(500, 1);
}

var hideRemoveBtn = function() {
  $("#remove_btn").fadeTo(500, 0);
}

var addLogoutBtn = function() {

  var logoutBtn = $(document.createElement("a"));
  logoutBtn.attr("id", "btn_logout");
  logoutBtn.attr("href", CONTEXT_PATH + "logout/");
  logoutBtn.text("Выйти");

  return logoutBtn;
}

var addSavedBtn = function() {
  $("#btn_saved").show();
}

var addSaveBtn = function() {
  var saveBtn = $(document.createElement("span"));
  saveBtn.text("Save");
  saveBtn.attr("id", "btn_save");
  $("#bottom_buttons").append(saveBtn);
  initSaveBtn();
}

var addSavedList = function(rawList) {
  var list = $(document.createElement("div"));
  list.attr("id", "saved_list");
  var listEl = $(document.createElement("ul"));
  list.append(listEl);
  for (var i = 0; i < rawList.length; i++) {
    var el = $(document.createElement("li"));
    el.attr("id", "load_sid_" + rawList[i].sol_id);
    el.text(rawList[i].ly_name + " " + rawList[i].sol_id);
    listEl.append(el);
  }
  var savedWrap = $("#saved_list_wrap");
  savedWrap.append(list);
  showSavedCont();

  initSavedList();
}

var loginOkay = function(response) {
  logg("loginOkay()");

  var logoutBtnWrap = addLogoutBtn();

  $("#form_login").remove();
  $("#form_register").remove();
  $("#form_forgot").remove();

  $("#login_register_wrap").empty().append(logoutBtnWrap);

  addSavedBtn();
  initLogoutBtn();

  LOGD = true;

}

var saveSolution = function() {

  logg("saveSolution()");
  //////// glued/sawn debug log
  var gluedEls = "";
  for (var i = 0; i < glued.length; i++) {
    gluedEls += glued[i] + ":";
  }
  gluedEls = gluedEls.substring(0, gluedEls.lastIndexOf(":"));
  logg("glued: " + gluedEls);

  var sawedEls = "";
  for (var i = 0; i < sawed.length; i++) {
    sawedEls += sawed[i] + ":";
  }
  sawedEls = sawedEls.substring(0, sawedEls.lastIndexOf(":"));
  logg("sawed: " + sawedEls);
  ////////

  var list = "";
  ly_cont.find(".el_st").each(function() { // "el_st = element start

    var el = $(this);
    var el_ie = this;

    var word = el.val().length > 0 ? el.val() : " ";
    var pars = el.attr("class").split(" ");

    var el_ids = [0, 0];
    var qu_ids = [0, 0];

    var el_id = 0;
    var qu_id = 0;

    // we might have two words starting fromt teh same square
    for (var i = 0; i < pars.length; i++) {
      // find the element id
      if (pars[i].lastIndexOf("_st_") > -1) {
        if (el_ids[0] == 0) {
          el_ids[0] = pars[i].split("_")[2]; // el_st_5
        } else {
          el_ids[1] = pars[i].split("_")[2]; // el_st_5
        }
      }

      // find the correspoding question id
      if (pars[i].indexOf("qid_") > -1) {
        if (qu_ids[0] == 0) {
          qu_ids[0] = pars[i].split("_")[1]; // qid_81
          var tr_id = pars[i].split("_").length > 2
            ? pars[i].split("_")[2]
            : 0;
          qu_ids[0] += "-" + tr_id;
        } else {
          qu_ids[1] = pars[i].split("_")[1]; // qid_81
          var tr_id = pars[i].split("_").length > 2
            ? pars[i].split("_")[2]
            : 0;
          qu_ids[1] += "-" + tr_id;
        }
      }
    }

    list += addSolutionElement(word, el_ids[0],
        qu_ids[0].split("-")[0], qu_ids[0].split("-")[1]);
    if (el_ids[1] > 0) {
      list += addSolutionElement(word, el_ids[1],
          qu_ids[1].split("-")[0], qu_ids[1].split("-")[1]);
    }
  });

  logg("saving: " + list);

  var postData =
    "ly_id=" + LAYOUT_ID +
    "&sol_id=" + SOLUTION_ID +
    "&list=" + list +
    "&glued=" + gluedEls +
    "&sawed=" + sawedEls;

  if (SOLUTION_ID < 1) {
    resetSavedSolutions();
  }
  led.on($("#message_saving").val());
  $.ajax({
    type: "POST",
    url: CONTEXT_PATH + "x/save",
    data: postData,
    dataType: "json",
    success: function(response) {
      //showRemoveBtn();
      led.off();
      if (response.status == true) {
        messageOkay(response.msg_text);
        SOLUTION_ID = parseInt(response.solution_id);
      } else {
        messageError(response.msg_text);
      }
      logg("saved solution id: " + SOLUTION_ID);
      // saved, now scrap the list
      flushSavedCont();

    },
    error: function(request, error) {
      led.off();
      messageError("Something went terribly wrong");
    }
  });
}

var addSolutionElement = function(word, el_id, qu_id, term_id) {
  logg("addSolutionElement(" + word.toString() + ", " + el_id.toString()
      + ", " + qu_id.toString() + ", " + term_id.toString() + ")");
  var result = el_id + ":" + qu_id + "-" + term_id + ":";
  var num = 1;
  var next = ly_cont.find(".el_" + el_id + "_" + num).eq(0);
  // ...fetch the whole word...
  while (next.is("input")) {
    word += next.val().length > 0 ? next.val() : " ";
    next = ly_cont.find(".el_" + el_id + "_" + ++num).eq(0);
    logg("next: " + ".el_" + el_id + "_" + num);
  }
  result += word + ";";

  return result;
}

var resetSavedSolutions = function() {
  hideSavedCont();
  $("#saved_list_cont").remove();
}

var newLayout = function(complexity) {

  logg("newLayout(" + complexity + ")");

  if (parseInt(complexity) < 0) {
    complexity = 0;
  }

  var postData =
    "cplx=" + complexity;
  led.on();
  $.ajax({
    type: "POST",
    url: CONTEXT_PATH + "x/new",
    data: postData,
    success: function(rawResponse) {
      led.off();
      hideRemoveBtn();
      var bits = rawResponse.split("|||");
      var newLyW = $(document.createElement("div"));
      newLyW.attr("id", "ly_wrap");
      newLyW.html(bits[0]);
      $("#ly_wrap").before(newLyW).remove();

      ly_cont = $("#ly_wrap");

      adjustPageLayout();

      var newQu = $(document.createElement("div"));
      newQu.attr("id", "qu");
      newQu.html(bits[1]);
      $("#qu").before(newQu).remove();

      SOLUTION_ID = 0;
      resetGlueSawCounter();

      initStarts();
      initSquares();
        initQuestions();
      //initSaveBtn();
      updateLayoutId();
      initEnterBtn();
      GAME_OVER_SHOWN = false;
    },
    error: function(request, error) {
      led.off();
      messageError("Something went terribly wrong");
    }
  });
}

var flushSolution = function() {
  $(".el").each(function() {
    var el = $(this);
    el.val("");
    scrapeGlyph(el);
  });
  if (SQ != null) {
    SQ.removeClass("hl");
    SQ.blur();
    SQ = null;
  }
}

var removeSolution = function() {
  var postData = "sol_id=" + SOLUTION_ID;
  led.on();
  $.ajax({
    type: "POST",
    url: CONTEXT_PATH + "xhr/remove",
    data: postData,
    success: function(rawResponse) {
      var response = JSON.parse(rawResponse);
      if (response.status == true) {
        led.off();
        messageOkay(response.msg_text);
        SOLUTION_ID = 0;
        hideRemoveBtn();
        resetSavedSolutions();
      } else {
        messageError(response.msg_text);
      }
    },
    error: function(request, error) {
      led.off();
      messageError("Something went terribly wrong");
    }
  });
}

var initButtonHints = function() {
  $("#btn_glue").parent()
  .mouseenter(function() {
    unforceHint();
    forceHint(parseInt(HINTS.glue));
  })
  .mouseleave(function() {
    unforceHint();
  });

  $("#btn_saw").parent()
  .mouseenter(function() {
    forceHint(parseInt(HINTS.glue));
  })
  .mouseleave(function() {
    unforceHint();
  });

  $("#btn_enter").parent()
  .mouseenter(function() {
    forceHint(parseInt(HINTS.enter));
  })
  .mouseleave(function() {
    unforceHint();
  });

  $("#btn_random").parent()
  .mouseenter(function() {
    forceHint(parseInt(HINTS.randomm));
  })
  .mouseleave(function() {
    unforceHint();
  });
}

var initGlueBtn = function(btn) {

  logg("initGlueBtn()");

  $("#btn_glue").unbind("click").one("click", function() {

    $(this).unbind("click");
    $(this).attr("src", CONTEXT_PATH + "static/img/icon_glue.png")

    logg("glue button clicked");

    if (GS_COUNT <= 0) {
      noMoreGlues();
      return;
    }

    var params = wasSQ.attr("class").split(" ");
    var id = wasSQ.attr("id");

    var dir = DIR.UNDEFINED;
    /*for (var i = 0; i < params.length; i++) {
      // lez find out the direction now
      if (params[i] == "d_long") {
        if (dir == null) {
          dir = DIR.LONG;
        } else {
          dir = DIR.UNDEFINED;
        }
      } else if (params[i] == "d_acro") {
        if (dir == null) {
          dir = DIR.ACROSS;
        } else {
          dir = DIR.UNDEFINED;
        }
      }
    }

    if (dir == DIR.UNDEFINED) {
      // now check there ain't already squares to the right/down
      var assertOnly = true;
      goingDir = DIR.ACROSS;
      var next = nextSquareCheck(wasSQ.attr("class"), DIR.FORWARD, assertOnly);
      if (next != null && next.is("input")) {
        logg("right is input");
        // no glue rightwards
        // since we know we have glue here, then it has to be downwards
        dir = DIR.LONG;
      } else {
        logg("right is NOT input");
        // can glue rightwards, lets also check downwards
        goingDir = DIR.LONG;
        var next = nextSquareCheck(wasSQ.attr("class"), DIR.FORWARD, assertOnly)
        if (next != null && next.is("input")) {
          logg("bottom is input");
          // cant glue downwards, so go across
          dir = DIR.ACROSS;
        } // otherwise can go both rightwards and downwards ergo dir.undef
          // ergo call the selector
      }
    }

    logg("direction: " + dir);
    logg("wasSq: " + wasSQ.attr("class"));
    //logg("SQ: " + SQ.attr("class"));*/

    if (wasSQ.hasClass("d_acro") && wasSQ.hasClass("d_long") == false) {
      dir = DIR.ACROSS;
    } else if (wasSQ.hasClass("d_long") && wasSQ.hasClass("d_acro") == false) {
      dir = DIR.LONG;
    } // otherwise it's both and UNDEFINED

    if (dir == DIR.UNDEFINED) {
      var allowGluingAcross = allowGluing(wasSQ, DIR.ACROSS);
      var allowGluingLong = allowGluing(wasSQ, DIR.LONG);

      if (allowGluingAcross != true) {
        dir = DIR.LONG;
      }

      if (allowGluingLong != true) {
        dir = DIR.ACROSS;
      }
    }

    if (dir == DIR.UNDEFINED) {
      appendGlueSelector(wasSQ);
    } else {
      glueSquare(wasSQ, dir);
    }

  }).mouseover(function() {
    $(this).attr("src", CONTEXT_PATH + "static/img/icon_glue_hl.png");
    showGlueHint();
  }).mouseout(function() {
    $(this).attr("src", CONTEXT_PATH + "static/img/icon_glue.png");
    hideGlueHint();
  });
}


var disableGlueBtn = function(btn) {
  logg("disableGlueBtn()");
  btn.unbind("click");
}

var appendGlueSelector = function(sq) {

  logg("appendGlueSelector");

  var glueSelector = $(document.createElement("span"));
  glueSelector.attr("id", "glue_dir_selector");

  var acro = $(document.createElement("span"));
  acro.addClass("acro");
  acro.text("→");
  glueSelector.append(acro);

  var longg = $(document.createElement("span"));
  longg.addClass("long");
  longg.text("↓");
  glueSelector.append(longg);

  sq.parent().append(glueSelector);
  initGlueSelector(sq, glueSelector);
}

var initGlueSelector = function(prevSq, sel) {

  logg("initGlueSelector(" + prevSq.attr("class") + ", " + sel + ")");

  sel.find(".acro").eq(0).click(function() {
    logg("add across");
    glueSquare(prevSq, DIR.ACROSS);
    sel.remove();
  });

  sel.find(".long").eq(0).click(function() {
    logg("add long");
    glueSquare(prevSq, DIR.LONG);
    sel.remove();
  });
}

var glueSquare = function(prevSq, dir) {

  logg("glueSquare(" + prevSq.attr("class") + ", " + dir + ")");
  logg("GS_COUNT: " + GS_COUNT);
  if (GS_COUNT <= 0) {
    return;
  }

  var PREV_PREV = 0;

  var nextSqIn = dir == DIR.LONG
    ? parseInt($("#ly_x_len").val())
    : 1;
  var sq = $("#sqi_" + (
      parseInt((prevSq.attr("id").split("_")[1])) +
      nextSqIn));

  sq.parent().addClass("on");

  goingDir = dir;

  var sibling = prevSq;

  if (prevSq.attr("class").indexOf("d_long") >= 0
      && prevSq.attr("class").indexOf("d_acro") >= 0) {
    logg("prev is crossing, go for prev-prev");
    sibling = nextSquare(prevSq.attr("class"), DIR.BACKWARD);
    PREV_PREV = 1;
  }

  logg("sibling: " + sibling.attr("class"));

  // now must select for which el this new square will belong
  // if prevSq is a crossing, it actually has two "el_*_*" classes
  // actual el_id and sq_num must be selected according to direction
  // so find prev to prev in selected direction -- it can't be crossing fo sure
  // thus will give proper el-id and sq-num.

  // however, if previous is not crossing, must look for its (previous) el-id
  // and sq-num as prev-prev might be crossing itself.

  // NOTE: this also assumes there can't be any 1sq-long

  // this is searching in class="..." for "el_*_*"

  var ps = sibling.attr("class").split(" ");

  var elId = 0; // element id
  var sqNm = 0; // square number
  var nDir = dir == DIR.ACROSS ? "d_acro" : "d_long"; // direction

  for (var i = 0; i < ps.length; i++) {
    if (ps[i].length > 4 && ps[i].substring(0, 3) == "el_") { // "> 4" means el_*_*
      //logg(ps[i]);
      var ps2 = ps[i].split("_");
      elId = ps2[1];
      sqNm = ps2[2];
      break;
    }
  }

  sqNm = parseInt(sqNm) + 1 + PREV_PREV; // +2 if went for prev-prev

  var directionId = "di_" + (DIR.ACROSS ? "a" : "l") + "_" + elId;

  logg("glue sq: elid=" + elId + ", sqnm=" + sqNm);
  sq.addClass("el " + nDir + " el_" + elId + "_" + sqNm + " " + directionId);
  sq.removeAttr("disabled");

  var span = sq.parent()
  span.attr("value", span.css("backgroundColor"));
  span.css("backgroundColor", "");

  initSquares();

  addGlued(elId);

  sq.focus();
}

var noMoreGlues = function() {
  logg("No more glues.");
  messageError("No more glues!");
}

var noMoreSaws = function() {
  messageError("No more saws!");
}

var resetGlueSawCounter = function() {

  logg("resetGlueSawCounter()");

  glued = new Array();
  sawed = new Array();

  GS_COUNT = GS_INITIAL;

  if ($("#glued_val").is("input")) {
    var justGlued = $("#glued_val").val().split(":");
    for (var i = 0; i < justGlued.length; i++) {
      if (parseInt(justGlued[i]) > 0) {
        glued.push(parseInt(justGlued[i]));
      }
    }
    GS_COUNT = GS_COUNT - glued.length;
  }

  if ($("#sawed_val").is("input")) {
    var justSawed = $("#sawed_val").val().split(":");
    for (var i = 0; i < justSawed.length; i++) {
      if (parseInt(justSawed[i]) > 0) {
        sawed.push(parseInt(justSawed[i]));
      }
    }
    GS_COUNT = GS_COUNT + sawed.length;
  }

  //////// debug log
  var gluedEls = "";
  for (var i = 0; i < glued.length; i++) {
    gluedEls += glued[i] + ":";
  }
  gluedEls = gluedEls.substring(0, gluedEls.lastIndexOf(":"));
  logg("glued: " + gluedEls);

  var sawedEls = "";
  for (var i = 0; i < sawed.length; i++) {
    sawedEls += sawed[i] + ":";
  }
  sawedEls = sawedEls.substring(0, sawedEls.lastIndexOf(":"));
  logg("sawed: " + sawedEls);

  logg("GS_COUNT: " + GS_COUNT);
  //////// debug log
}

var addGlued = function(elId) {
  logg("addGlued(" + elId + ")");
  for (var i = 0; i < sawed.length; i++) {
    if (sawed[i] == elId) {

      sawed.splice(i, 1);
      GS_COUNT--;

      return;
    }
  }

  glued.push(elId);
  GS_COUNT--;

  updateGlueHint();
}

/**
 *
 */
var initSawBtn = function(btn) {
  logg("initSawBtn()");

  btn.unbind("click").click(function() {

    $(this).unbind("click");
    $(this).attr("src", CONTEXT_PATH + "static/img/icon_saw.png")

    if (GS_COUNT >= GS_MAX) {
      noMoreSaws();
      return;
    }

    sawSquare(wasSQ);
  }).mouseover(function() {
    $(this).attr("src", CONTEXT_PATH + "static/img/icon_saw_hl.png");
    showSawHint();
  }).mouseout(function() {
    $(this).attr("src", CONTEXT_PATH + "static/img/icon_saw.png");
    hideSawHint();
  });
}

/**
 * Actually saws the square.
 * Disables the square (input and wrapper) by removing all classes related to
 * square identification, removes "on" class from wrapper, unbinds everything
 * from the input.
 */
var sawSquare = function(sq) {
  logg("sawSquare(" + sq.attr("class") + "/" + sq.attr("id") + ")");
  // assume we can't saw from crossings

  // this is searching in class="..." for "el_*_*"

  var ps = sq.attr("class").split(" ");

  var elId = 0; // element id

  for (var i = 0; i < ps.length; i++) {
    if (ps[i].length > 4 && ps[i].substring(0, 3) == "el_") { // "> 4" means el_*_*
      var ps2 = ps[i].split("_");
      elId = ps2[1];
      break;
    }
  }

  sq.unbind();
  sq.attr("class", "square");
  sq.attr("disabled", "disabled");
  var span = sq.parent();
  span.removeClass("on");
  if (span.attr("value")) {
    span.css("backgroundColor", span.attr("value"));
    span.removeAttr("value");
  }

  sq.val("");

  addSawn(elId);
}

var addSawn = function(elId) {
  logg("addSawn(" + elId + ")");

  if (GS_COUNT >= GS_MAX) {
    logg("No moar saws.")
  }

  for (var i = 0; i < glued.length; i++) {
    if (glued[i] == elId) {
      glued.splice(i, 1);
      GS_COUNT++;
      return;
    }
  }

  sawed.push(elId);
  GS_COUNT++;

  updateSawHint();
}

var updateGlueHint = function() {
  $("#glue_hint_number").text(GS_COUNT);
}

var showGlueHint = function() {
  updateGlueHint();
  $("#glue_hint").show();
}

var hideGlueHint = function() {
  $("#glue_hint").hide();
}

var updateSawHint = function() {
  $("#saw_hint_number").text((GS_MAX-GS_COUNT));
}

var showSawHint = function() {
  updateSawHint();
  $("#saw_hint").show();
}

var hideSawHint = function() {
  $("#saw_hint").hide();
}

var lockHint = function() {
  SWITCH_HINT_DO = false;
}

var unlockHint = function() {
  SWITCH_HINT_DO = true;
}

var forceHint = function(id) {
  logg("forceHint(" + id + ")");
  lockHint();
  replaceHint(id);
}

var unforceHint = function(id) {
  unlockHint();
}

var initAddQuestionForm = function() {
  logg("initAddQuestionForm");

  initAddQuestionBtn();

  $("#add_question_wrap").hide(0, function() {
    $(this).css("display", "block");
  });

  $("#btn_add_question_form").click(function() {
    $("#add_question_wrap").toggle();
    $("#add_question").val("");
  });
}

var initAddQuestionBtn = function () {

  $("#add_question_form").submit(function() {

    var q = $("#add_question").val();
    saveQuestion(q);

    return false;

  });
}

var saveQuestion = function(text, replace_id) {

  logg("save question: " + text);

  var postData =
    "q=" + encodeURIComponent(text);
  led.on();
  $.ajax({
    type: "POST",
    url: CONTEXT_PATH + "x/question_add",
    dataType: "json",
    data: postData,
    success: function(response) {
      led.off();
      if (response.status == true) {
        messageOkay(response.msg_text);
        logg("added question: " + response.q_id);

        if (parseInt(replace_id) > 0) {

          var elSt = $(".qid_" + replace_id);
          elSt.removeClass("qid_" + replace_id);
          elSt.addClass("qid_" + response.q_id);

          logg("found " + elSt.length);
          logg("elSt: " + elSt.attr("class"));

          $("#q_" + replace_id + "_enter") // replace question form
              .attr("id", "#q_" + replace_id + "_enter")
              .val("")
              .parent().hide();

          $("#bqc_" + replace_id).attr("id", "bqc_" + replace_id);

          $("#qu_desc_" + replace_id)
              .attr("id", "qu_desc_" + replace_id)
              .text(text);


        }

        // clean up & change ids:

        $("#add_question_wrap").hide(); // add question from
        $("#add_question").val("");

      } else {
        messageError(response.msg_text);
      }
    }
  });
}

var initBombBtn = function() {
  //$("#btn_bomb").fadeTo(100, .1).css("cursor", "default");
}

var initRandomBtn = function() {
  $("#btn_random").unbind()
  .click(function() {
    engageRandom(wasSQ);
  }).mouseover(function() {
    $(this).attr("src", CONTEXT_PATH + "static/img/icon_random_hl.png");
  }).mouseout(function() {
    $(this).attr("src", CONTEXT_PATH + "static/img/icon_random.png");
  })
}

var initEnterBtn = function() {

  initQuestionChangeBtns();

  $(".enter_wrap").each(function() {
    $(this).hide(0, function() {
      $(this).css("display", "block");
    });
  });

  $("#btn_enter").unbind()
  .click(function() {

    // keep element highlit:
    KEEP_HIGHLIT_ELEMENT = true;
    wasSQ.focus(); // SQ is now wasSQ

    var qu_id = wasQU_ID;
    SQ.blur();



    var quEnter = $("#q_" + qu_id + "_enter");

    quEnter
        .val($("#qu_desc_" + qu_id).text().trim())
        .parent().show();

    quEnter.focus();

  }).mouseover(function() {
    $(this).attr("src", CONTEXT_PATH + "static/img/icon_enter_hl.png");
  }).mouseout(function() {
    $(this).attr("src", CONTEXT_PATH + "static/img/icon_enter.png");
  });
}

var initQuestionChangeBtns = function() {
  $(".btn_question_change").unbind()
  .click(function() {

    KEEP_HIGHLIT_ELEMENT = false;

    // collect question id
    var q_id = $(this).attr("id").split("_")[1];
    logg("change question " + q_id);

    var quEnter = $("#q_" + q_id + "_enter");

    if (quEnter.val().trim() == $("#qu_desc_" + q_id).text().trim()) {
      logg("Question unchanged");
      quEnter.val("").parent().hide();
      return;
    }

    saveQuestion(quEnter.val().trim(), q_id);
  });
}

var initHints = function() {

  logg("initHints");

  hintEl = $("#hint");
  currentHint = parseInt($("#hint_current").val());
  hintsNum = $(".hint").length;

  logg(hintsNum + " hints found");

  $("#hint").everyTime(TIMEOUT_SWITCH_HINT, function() { // magic! 15s

    var next = Math.floor(Math.random() * hintsNum);

    logg("next: " + next + ", current: " + currentHint);

    if (next == currentHint) {
      next++;
      if (next == hintsNum) {
        next = 0;
      }
    }

    if (SWITCH_HINT_DO == true) {
      replaceHint(next);
    }

  }).mouseover(function() {
    lockHint();
  }).mouseout(function() {
    unlockHint();
  });
}

var replaceHint = function(index) {
  logg("replaceHint(" + index + ")");
  var p = hintEl.find("p");
  var pNew = $(document.createElement("p"));
  pNew.text($("#hint_" + index).val());
  pNew.addClass("new");
  hintEl.append(pNew);

  pNew.fadeTo(0, 0, function() {
    $(this).css("visibility", "visible");
  });

  var oldHeight = p.innerHeight();
  var newHeight = pNew.innerHeight();

  logg("new height: " + newHeight);

  if (newHeight > oldHeight) {
    hintEl.animate({ height: pNew.outerHeight() }, function() {

      p.fadeTo(200, 0, function() { $(this).remove(); });

      pNew.fadeTo(400, 1, function() {
        $(this).css("position", "relative");
        currentHint = index;

      });
    });
  } else {
    p.fadeTo(200, 0, function() { $(this).remove(); });

    pNew.fadeTo(400, 1, function() {
      $(this).css("position", "relative");
      currentHint = index;
      hintEl.animate({ height: pNew.outerHeight() });
    });
  }
}

var engageRandom = function(elSq) {
  logg("engageRandom()");

  var sq = elSq;

  while (sq != null && sq.is("input")) {
    putRandomGlyph(sq);
    sq = nextSquare(sq.attr("class"), DIR.FORWARD, true);
  }

  sq = elSq;

  while (sq != null && sq.is("input")) {
    putRandomGlyph(sq);
    sq = nextSquare(sq.attr("class"), DIR.BACKWARD, true);
  }

}

var putRandomGlyph = function(sq) {

  var rand = Math.floor(Math.random()*100);
  if (rand > 50) {
    return;
  }

  var glyphStart = 65;
  var glyphsNum = 23;

  if (LC_CODE == "ru") {
    glyphStart = 1040;
    glyphsNum = 32;
  }

  rand = Math.floor(Math.random()*glyphsNum);
  sq.val(String.fromCharCode(glyphStart+rand));
  putGlyph(sq, glyphStart+rand);
}

var verifyDone = function() {
  if (GAME_OVER_SHOWN == true) {
    return;
  }
  var sqs = $("#ly").find(".el");
  var num = sqs.size();
  var filled_num = 0;
  sqs.each(function() {
    if ($(this).val().trim().length > 0) {
      filled_num++;
    }
  });

  if (filled_num+1 >= num) {
    gameOver();
  }
}

var initGameOver = function() {
  goWrap = $("#game_over_wrap");
  goWrap.fadeTo(1, 0);
  $("#btn_go_continue").click(function() {
    goWrap.fadeTo(300, 0, function() {
      $(this).css("display", "none");
    });
  });
  $("#btn_go_save").click(function() {
    goWrap.fadeTo(300, 0, function() {
      $(this).css("display", "none");
      $("#btn_save").click();
    });
  });

  $("#btn_go_new").click(function() {
    goWrap.fadeTo(300, 0, function() {
      $(this).css("display", "none");
      $("#btn_new").click();
    });
  });

  $("#btn_go_quit").click(function() {
    goWrap.fadeTo(300, 0, function() {
      $(this).css("display", "none");
      // whoopsie, quick and dirty
      var quitsies = new Array(
        "http://www.ljubo.ru/",
        "http://www.vioo.ru/",
        "http://ideasthatrock.ru/404",
        "http://oos.moxiecode.com/examples/reflex/");
      var rand = Math.floor(Math.random() * quitsies.length);
      window.location.replace(quitsies[rand]);
    });
  });
}

var gameOver = function() {
  logg("gameOver()");
  if (GAME_OVER_SHOWN == true) {
    return;
  }
  goWrap.css("display", "block");
  goWrap.fadeTo(300, 1);

}

