var CALCOLANOTTI = function () {

  function parseDate(s)
  {
    var y, m, d, r;

    try {
      s = s.split("/");

      y = parseInt(s[2].replace(/^\s+|\s+$/g, "").replace(/^0+/, ""), 10);
      m = parseInt(s[1].replace(/^\s+|\s+$/g, "").replace(/^0+/, ""), 10) - 1;
      d = parseInt(s[0].replace(/^\s+|\s+$/g, "").replace(/^0+/, ""), 10);

      r = new Date();
      r.setFullYear(y, m, d);

      if (y == "NaN" || m == "NaN" || d == "NaN" || r == "NaN")
      {
        r = null;
      }
    } catch (ex) {
      r = null;
    }

    return r;
  }

  function writeDate(date)
  {
    var i, dateText, val;

    dateText = [];
    for (i = 0; i < 3; i += 1)
    {
      switch(i)
      {
      case 0:
        val = date.getDate();

        if (val < 10)
        {
          val = "0" + val;
        }
        break;
      case 1:
        val = date.getMonth() + 1;

        if (val < 10)
        {
          val = "0" + val;
        }
        break;
      case 2:
        val = date.getFullYear();
        break;
      }

      dateText.push(val);
    }

    return dateText.join("/");
  }

  return {
    install : function (locale, startDateNodeId, endDateNodeId, outputNodeId, errorNodeId, minimumDays) {
      var sNode, eNode, L13N = {
        "it" : [
          "Errori nelle date di inizio e di fine.",
          "Errore nella data di inizio.",
          "Errore nella data di fine.",
          "senza pernottamento",
          "1",
          ""
        ],
        "en" : [
          "Errors in the start and end dates.",
          "Error in the start date.",
          "Error in the end date.",
          "no overnight stay",
          "1",
          ""
        ],
        "de" : [
          "Fehler in den Start- und Enddaten.",
          "Fehler in der Startdate.",
          "Fehler in der Enddate.",
          "ohne Übernachtung",
          "1",
          ""
        ],
        "es" : [
          "Errores en la data de principio y de fin.",
          "Error en la data de principio.",
          "Error en la data de fin.",
          "no noche",
          "1",
          ""
        ],
        "fr" : [
          "Erreur dans les dates de début et de fin.",
          "Erreur dans la date de début.",
          "Erreur dans la date de fin.",
          "sans séjour de nuit",
          "1",
          ""
        ]
      };

      sNode = document.getElementById(startDateNodeId);
      eNode = document.getElementById(endDateNodeId);

      sNode.onchange = function (sNode, eNode, oNode, xNode, minDays) {
        return function (ev) {
          var sText, eText, sDate, eDate, days, errors, outText, eventTarget;

          sText = sNode.value.replace(/^\s+|\s+$/g, "");
          eText = eNode.value.replace(/^\s+|\s+$/g, "");

          sDate = parseDate(sText);
          eDate = parseDate(eText);

          if (sDate === null && eDate !== null)
          {
            sDate = new Date();
            sDate.setTime(eDate.getTime() - 86400000);
            sText = writeDate(sDate);
            sNode.value = sText;
          } else if (sDate !== null && eDate === null) {
            eDate = new Date();
            eDate.setTime(sDate.getTime() + 86400000);
            eText = writeDate(eDate);
            eNode.value = eText;
          }

          errors = "";
          outText = "0";

          if (sText === "" || eText === "")
          {
            // ignora
          } else if (sDate === null && eDate === null)
          {
            errors = L13N[locale][0];
          } else if (sDate === null && eDate !== null)
          {
            errors = L13N[locale][1];
          } else if (sDate !== null && eDate === null)
          {
            errors = L13N[locale][2];
          } else {
            days = Math.floor(eDate.getTime() / 86400000) - Math.floor(sDate.getTime() / 86400000);

            if (days < minDays)
            {
              ev = ev || event;
              eventTarget = ev.target || ev.srcElement;

              if (eventTarget === sNode)
              {
                eDate.setTime((Math.floor(sDate.getTime() / 86400000) + minDays) * 86400000); // add days (in ms)
                eNode.value = writeDate(eDate);
              } else {
                sDate.setTime((Math.floor(eDate.getTime() / 86400000) - minDays) * 86400000); // sub days (in ms)
                sNode.value = writeDate(sDate);
              }

              days = minDays;
            }

            if (days === 0)
            {
              outText = L13N[locale][3];
            } else if (days === 1) {
              outText = L13N[locale][4];
            } else {
              outText = days + L13N[locale][5];
            }
          }

          oNode.innerHTML = outText;
          xNode.innerHTML = errors;
        };
      }(sNode, eNode, document.getElementById(outputNodeId), document.getElementById(errorNodeId), minimumDays);

      eNode.onchange = sNode.onchange;
      sNode.onchange({ target : sNode });
    }
  };
}();
