/**
 * Extends the native <code>HTMLDocument</code> and <code>document</code> with functionality for 
 * easy cross-browser HTML node creation.
 * @class HTMLDocument
 * @version 0.1
 * @author Henrik Lindqvist &lt;<a href="mailto:henrik.lindqvist@llamalab.com">henrik.lindqvist@llamalab.com</a>&gt;
 */

(function (d, htd) {

/**
 * Create HTML node&rsquo;s.
 * <p>A fast and simple way to create HTML DOM nodes at runtime.</p>
 * <h4>Example:</h4>
 * <pre>
 *   // Since input are self-contained in a single JavaScript object, 
 *   // templates can be remotely loaded as JSON. 
 *   var json = ['A',{href:'http://llamalab.com'},[LlamaLab']];
 *   var llamalab = document.toHTML.apply(document, json);
 *   // Creating a DOM tree.
 *   document.body.appendChild(document.createHTML(
 *     'UL',[
 *       'LI',llamalab,
 *       'LI',['A',{href:'http://slashdot.org'},[Slashdot']],
 *       'LI',[document.getElementById('moveThisLink')],
 *     ]
 *   ));
 * </pre>
 * @function {Node} createHTML
 * @paramset Element Syntax
 * @param {string} name - <code>Element</code> tag name.
 * @param {optional Object} attrs - <code>Object</code> with attributes.
 * @param {optional Array} children - <code>Array</code> with children, with same syntax as this function.
 * @paramset Text (node) Syntax
 * @param {string} text - <code>Text</code> node content.
 * @paramset Node Inclusion Syntax
 * @param {Node} node - <code>Node</code> to include as child.
 * @returns Element, Text (node) or DocumentFragment
 */
var fn = function () {
  var i = 0, n, a, c, e, r, fn = arguments.callee;
  while (n = arguments[i++]) {
    if (typeof n == 'string') {
      if (a = arguments[i]) {
        if (a.constructor == Object) i++;
        else a = null;
        if (c = arguments[i]) {
          if (c.constructor == Array) i++;
          else c = null;
        }
      }
      if (a || c) {
        n = n.toUpperCase();
        try {
          var h = ['<', n, '>'];
          if (a.name) h.splice(2, 0, ' name="',a.name,'"');
          if (a.type) h.splice(2, 0, ' type="',a.type,'"');
          e = this.createElement(h.join(''));
          delete a.name;
          delete a.type;
        }
        catch (err) {
          e = this.createElement(n);
        }
        for (n in a) {
          v = a[n];
          n = n.toLowerCase();
          if (typeof v == 'function') e[n] = v;
          else fn.__setattr(e, n, String(v));
        }
        if (c && (c = fn.apply(this, c))) e.appendChild(c);
      }
      else e = this.createTextNode(n);
    }
    else if (n.nodeType > 0) e = n.parentNode ? n.parentNode.removeChild(n) : n;
    else throw new TypeError('Illegal argument: ' + n);
    if (r) {
      if (r.nodeType != 11) {
        c = r;
        r = this.createDocumentFragment();
        r.appendChild(c);
      }
      r.appendChild(e);
    }
    else r = e;
  }
  return r;
};
if (/MSIE/.test(navigator.userAgent)) {
  fn.__setattr = function (e, n, v) {
    if ('style' == n) e.style.cssText = v;
    else if (/^on[a-z]+$/.test(n)) e[n] = new Function(v);
    else e.setAttribute(arguments.callee.__remap[n]||n, v);
  };
  fn.__setattr.__remap = {
    'acceptcharset': 'acceptCharset',
    'accesskey':     'accessKey',
    'cellpadding':   'cellPadding',
    'cellspacing':   'cellSpacing',
    'checked':       'defaultChecked',
    'selected':      'defaultSelected',
    'class':         'className',
    'colspan':       'colSpan',
    'for':           'htmlFor',
    'frameborder':   'frameBorder',
    'hspace':        'hSpace',
    'longdesc':      'longDesc',
    'marginwidth':   'marginWidth',
    'marginheight':  'marginHeight',
    'noresize':      'noResize',
    'noshade':       'noShade',
    'maxlength':     'maxLength',
    'readonly':      'readOnly',
    'rowspan':       'rowSpan',
    'tabindex':      'tabIndex',
    'valign':        'vAlign',
    'vspace':        'vSpace'
  };
}
else 
  fn.__setattr = function (e, n, v) { e.setAttribute(n, v) };

if (htd) htd.prototype.createHTML = fn;
else d.createHTML = fn;

})(document, window.HTMLDocument);
