/**
* $N - a HTML dom node builder with a similar API to the scriptaculous Builder.node function
*      with the following improvements:
*      - Uses DocumentFragment for speed and flexibility.
*      - It always returns prototype extended Elements (even in IE).
*      - It will not encode HTML strings in the middle of an array of children nodes/strings and will execute any script blocks
*           that are passed in as strings inside the children array (as prototype's Element.update function does).
*      - If you have a null item in your children array it will neither write the word "null" or throw an exception, the item will just be skipped.
*      - In my testing, it is slightly faster than Builder.node.
*      - Its function name is shorter than Builder.node, and I got tired of typing it.
*      
*      - Please note that it requires prototype.js 1.6
*
*      If you are currently using Builder.node, you should be able to just drop this in and search and replace
*      Builder.node with $N, or alias Builder.node to $N
*
*   @author Ian Taylor
*   version 1.0, June 2008
*   version 1.1, September 2008 -- Modified to use DocumentFragmentMaker instead of hacky string replacement.
*   A part of the Fluidity Project - http://www.fluidity-project.org/ licensed under the Apache 2.0 license.
*/
var $N = function (tagName, attributes, children)
{
	if(arguments.length == 2 && (Object.isString(attributes) || Object.isArray(attributes) || Object.isElement(attributes) || Object.isNumber(attributes)))
    {
        children = attributes;
        attributes = {};
    }
	if (!attributes)
	{
		attributes = {};
	}
	if(children != null && Object.isNumber(children))
	{
		children = children.toString();
	}
	var elemTag
	if(tagName.indexOf("#") != -1 || tagName.indexOf(".")!=-1)
	{
		elemTag = tagName.match(/^\s*(\*|[\w\-]+)(\b|$)?/);
		if(elemTag)
		{
			elemTag = elemTag[0];
		}
	    var id = tagName.match(/^#([\w\-\*]+)(\b|$)/);
	    var className = tagName.match(/^\.([\w\-\*]+)(\b|$)/);
	    
	    if (!elemTag)
	    {
	    	elemTag = "div";
	    }
	    if (id)
	    {
	    	//TODO: fix the regexes to clean this up.
	    	attributes.id = id[0].replace("#", "");
	    }
	    if (className)
	    {
	    	//TODO: multiple classNames.
	    	attributes.className = className[0].replace(".", "");
	    }    
	}
	else
	{
		elemTag = tagName;
	}
	
	
    var elem = new Element(elemTag, attributes);

    if (children)
    {
        if (!Object.isArray(children))
        {
          children = [children];
        }
        if (children.length > 0)
        {
          elem.appendChild(DocumentFragmentMaker(children));
        }
    }

    return elem;
}

var DocumentFragmentMaker = function (children)
{
    var frag = document.createDocumentFragment();

    var matchRegex = /[<>]/;

    var addHtmlTextToFrag = function (f, text)
    {
       text= text.replace(/&apos;/g, "'").replace(/&#39;/g, "'");
       var tempElem = new Element("div").update(text);
         $A(tempElem.childNodes).each( function (node) {
               f.appendChild(node);
          });
    }

    if (children) 
    {
        if (Object.isArray(children)) 
        {
            children.compact().each(function(item, i)
            {
                if (item.tagName) 
                {
                    frag.appendChild(item);
                }
                else 
                {
                    addHtmlTextToFrag(frag, item);
                }
            });
        }
        else 
        {
            if (Object.isString(children)) 
            {
                addHtmlTextToFrag(frag, children);
            }
            if (Object.isElement(children)) 
            {
                frag.appendChild(children);
            }
        }
    }
    return frag;
}
