/**
 * Dumb HTML views. Mostly to demonstrate how the visitor pattern over these
 * views works, as driven by validation. I'm not convinced it's actually a good
 * idea to do validation.
 *
 * @provides javelin-view-html
 * @requires javelin-install
 *           javelin-dom
 *           javelin-view-visitor
 *           javelin-util
 */

JX.install('HTMLView', {
  extend: 'View',
  members : {
    render: function(rendered_children) {
      return JX.$N(this.getName(), this.getAllAttributes(), rendered_children);
    },
    validate: function() {
      this.accept(JX.HTMLView.getValidatingVisitor());
    }
  },

  statics: {
    getValidatingVisitor: function() {
      return new JX.ViewVisitor(JX.HTMLView.validate);
    },

    validate: function(view, children) {
      var spec = this._getHTMLSpec();
      if (!(view.getName() in spec)) {
        throw new Error("invalid tag");
      }

      var tag_spec = spec[view.getName()];

      var attrs = view.getAllAttributes();
      for (var attr in attrs) {
        if (!(attr in tag_spec)) {
          throw new Error("invalid attr");
        }

        var validator = tag_spec[attr];
        if (typeof validator === "function") {
          return validator(attrs[attr]);
        }
      }

      return true;
    },

    _validateRel: function(target) {
      return target in {
        "_blank": 1,
        "_self": 1,
        "_parent": 1,
        "_top": 1
      };
    },
    _getHTMLSpec: function() {
      var attrs_any_can_have = {
        className: 1,
        id: 1,
        sigil: 1
      };

      var form_elem_attrs = {
        name: 1,
        value: 1
      };

      var spec = {
        a: { href: 1, target: JX.HTMLView._validateRel },
        b: {},
        blockquote: {},
        br: {},
        button: JX.copy({}, form_elem_attrs),
        canvas: {},
        code: {},
        dd: {},
        div: {},
        dl: {},
        dt: {},
        em: {},
        embed: {},
        fieldset: {},
        form: { type: 1 },
        h1: {},
        h2: {},
        h3: {},
        h4: {},
        h5: {},
        h6: {},
        hr: {},
        i: {},
        iframe: { src: 1 },
        img: { src: 1, alt: 1 },
        input: JX.copy({}, form_elem_attrs),
        label: {'for': 1},
        li: {},
        ol: {},
        optgroup: {},
        option: JX.copy({}, form_elem_attrs),
        p: {},
        pre: {},
        q: {},
        select: {},
        span: {},
        strong: {},
        sub: {},
        sup: {},
        table: {},
        tbody: {},
        td: {},
        textarea: {},
        tfoot: {},
        th: {},
        thead: {},
        tr: {},
        ul: {}
      };

      for (var k in spec) {
        JX.copy(spec[k], attrs_any_can_have);
      }

      return spec;
    },
    registerToInterpreter: function(view_interpreter) {
      var spec = this._getHTMLSpec();
      for (var tag in spec) {
        view_interpreter.register(tag, JX.HTMLView);
      }
      return view_interpreter;
    }
  }
});

