
  var Feedback = (function() {

    var $alertBox, $messageBox, $hintBox;
    var $content;

    function htmlize(content) {
      if (typeof(content) == "object") {
        var a = [];
        $.each(content, function(_, v) { a.push(v); });
        content = a.join("<br>");
      }
      return content;
    }

    function formAlert($form, formErrors) {
      if (!$form || !$form.length || !formErrors || $.isEmptyObject(formErrors)) {
        return false;
      }

      var unsorted = [];
      $.each(formErrors, function(k, v) {

        var $elem = $form.find("[name^=" + k + "]");

        if (!$elem.length) {
          alert(v);
          return;
        }

        // $elem.css({ backgroundColor: "#ffd258", color: "#aa2626" });
        $elem.css({ color: "#aa2626" });

        // position relative to content $content.offset();
        var elemPos = $elem.offset();

        var elemTop = elemPos.top + $elem.outerHeight() / 2;
        var elemLeft = elemPos.left - $alertBox.outerWidth();

        unsorted.push({ elem: $elem, msg: v, top: elemTop, left: elemLeft });
      });

      var a = unsorted.sort(function(v1, v2) { return v1.top - v2.top; }).shift();
      if (!a) return false;

      a.elem.focus().select();
      var b = $content.offset();

      $alertBox.find("p").html(a.msg).end().css({ top: a.top - b.top - 12, left: a.left - b.left - 16 }).show();
      $alertBox.find("span.arrow").show();

      return true;
    }

    function alert(content) {
      if (!content || $.isEmptyObject(content)) {
        return false;
      }

      $alertBox.find("span.arrow").hide();
      $alertBox.find("p").html(htmlize(content)).end().show();
      return true;
    }

    function message(content) {
      if (!content || $.isEmptyObject(content)) {
        return false;
      }

      $messageBox.find("p").html(htmlize(content)).end().show();
      return true;
    }

    function hint(content) {
      if (!content || $.isEmptyObject(content)) {
        return false;
      }

      $hintBox.find("p").html(htmlize(content)).end().show();
      return true;
    }
    
    function init() {
      $alertBox = $("#alertBox");
      $messageBox = $("#messageBox");
      $hintBox = $("#hintBox");

      $content = $("#content");

      $alertBox.find("span.x").click(function() { $alertBox.hide(); });
      $messageBox.find("span.x").click(function() { $messageBox.hide(); });
      $hintBox.find("span.x").click(function() { $hintBox.hide(); });
    }

    function clear() {
      $alertBox.stop(true, true).hide();
      $messageBox.stop(true, true).hide();
      $hintBox.stop(true, true).hide();
    }

    return {
      init: init,
      alert: alert,
      message: message,
      hint: hint,
      formAlert: formAlert,
      clear: clear
    };
  })();


