var JawakerFormElement = Class.create({
  initialize: function(elem, opts) {
    this.elem   = $(elem);
    this.opts   = opts;
    this.form   = null;
    this.findex = null;
    this.old_ajax = null;
    this.status = this.opts['optional'] ? true : this.elem.tagName == "SELECT"; // Selects are preselected and are valid
    // [ [f, msg], ... ]
    this.validators = this.opts.validators;
    new Form.Element.Observer(this.elem, 0.3, this.check.bind(this));
    this.elem.observe('focus', this.show_tip.bind(this));
    this.elem.observe('blur', this.hide_tip.bind(this));
    this.illegal_re = /['"~!@#\$%^&*()=+\[\]{};:|\\,?\/<>\s]/;
  },
  set_form: function(frm, idx) {
    this.form = frm; this.findex = idx;
  },
  show_valid: function() {
    var e = this.elem.up().next();
    e.writeAttribute('class', 'correct');
    e.update("<img src='/images/OK.png' alt='OK'/> " + G._("OK")).show();
  },
  show_checking: function() {
    var e = this.elem.up().next();
    e.writeAttribute('class', 'checking');
    e.update("<img src='/images/checking.gif' alt='Checking'/> " + G._("Checking ...")).show();
  },
  show_invalid: function(msg) {
    msg = msg || "Invalid Field";
    var e = this.elem.up().next();
    e.writeAttribute('class', 'error');
    e.update("<img src='/images/error.png' alt='Error'/> " + G._(msg)).show();
  },
  doAjax: function(url, prms) {
    if (this.old_ajax && this.old_ajax.transport.readyState == 1) { // old req still running
      this.old_ajax.transport.abort();
      this.old_ajax.transport.onreadystatechange = Prototype.emptyFunction; // IE memory leak
    }
    this.old_ajax = new Ajax.Request(url, {method: 'get', parameters: Object.extend(prms, {jfi: this.findex})});
    return "async";
  },
  check: function() {
    var async = false;
    for (var i = 0; i < this.validators.length; i++) {
      var res = true;
      try {
        res = this.validators[i][0].apply(this);
      } catch(e) { if (typeof console != "undefined" && typeof console.log == "function") { console.log(e); } }
      if (res === "async") {
        async = true;
        this.status = false;
        this.show_checking();
        this.msg = this.validators[i][1];
        this.finished = function(resp) {
          if (resp == 'true') {
            this.status = true;
            this.show_valid();
          } else {
            this.status = false;
            this.show_invalid(this.msg);
          }
        };
      }
      else if(!res) {
        this.status = false;
        this.show_invalid(this.validators[i][1]);
        break;
      }
    }
    if (i == this.validators.length && !async) { this.status = true; this.show_valid(); }
  },
  flash: function() {
    var f = function() { this.elem.up('tr').toggleClassName("focusederror"); }.bind(this);
    var t = setInterval(f, 400);
    setTimeout(function() { clearTimeout(t); }, 400 * 6);
  },
  show_tip: function() {
    var e = this.elem.up().next();
    if (!e.visible() && this.opts.tip && this.opts.tip.length != 0) {
      e.writeAttribute('class', 'onclick');
      e.update("<img src='/images/arrow_" + G.lang() + ".gif' alt='tip'/> " + G._(this.opts.tip)).show();
    }
  },
  hide_tip: function() {
    var e = this.elem.up().next();
    (function() { if (e.visible() && e.readAttribute('class') == 'onclick') { e.hide(); } }).delay(0.15);
  }
});

var JawakerForm = Class.create({
  initialize: function(elem, opts) {
    this.elem = $(elem);
    this.opts = opts;
    this.form_elems = [];
    this.elem.observe("submit", this.validate.bind(this));

    Ajax.Responders.register({
      onComplete: function(req) {
        if ('jfi' in req.parameters) { // A checking request
          this.form_elems[parseInt(req.parameters.jfi, 10)].finished(req.transport.responseText);
        }
      }.bind(this)
    });
  },
  set_focus: function() {
    this.form_elems.first().elem.focus();
  },
  add_form_elem: function(e) {
    e.set_form(this, this.form_elems.length);
    this.form_elems.push(e);
    return true;
  },
  validate: function(ev) {
    for (var i = 0; i < this.form_elems.length; i++) {
      if (!this.form_elems[i].status) {
        this.form_elems[i].flash();
        ev.stop();
        return false;
        break;
      }
    }
    if (this.opts.beforeSubmit) { this.opts.beforeSubmit(); }
    return true;
  }
});
