// graft() function
// Originally by Sean M. Burke from interglacial.com
// Closure support added by Maciek Adwent

function graft (parent, t, doc) {


    // Usage: graft( somenode, ['Element/HTML Tag Name',{attribute:attributevalue,attribute:attributevalue] )
	// Exampe: graft( somenode, ['table',{border:0,cellpadding:0,cellspacing:0}] )

	/* Nested Usage: 
		var[var.length] = ['Element',['Element', {attribute:'attribute_value', attribute:'attribute_value'}, 
							['Element', {attribute:'attribute_value', attribute:'attribute_value', 'Text Show'],
							['Element', {attribute:'attribute_value', attribute:'attribute_value', 'Text Show'],
						]];
		graft(document.getElementById("Element ID Where Its Gonna Be Grafted"),variable to be grafted);	

		This nested example puts a 2 Options in a select drop down.
		The select drop down added to the table cell
		The table cell is put inside of a table row
		The length specifies an addition to the current row
		The row is then added to the tbody
		The tbody is added to the table
		The table is grafted to the Element with the ID of "meeting_rooms_req"
		
		Nested Example: 
		tr[tr.length] = ['td',['select', {name:'meeting_requirements[day_'+(i+1)+'][room_setup]', size:'1'}, 
							['option', {type:'text', value:'Classroom', size:'1', name:'meeting_requirements[day_'+(i+1)+'][room_setup]'}, 'Classroom'],
							['option', {type:'text', value:'Theater U-Shape', size:'1', name:'meeting_requirements[day_'+(i+1)+'][room_setup]'}, 'Theater U-Shape'],
						]];
		tbody[tbody.length]=tr;
		tbl[tbl.length]=tbody;
		graft(document.getElementById("meeting_rooms_req"),tbl);	

	*/

    // Usage: graft( somenode, [ "I like ", ['em',
    //               { 'class':"stuff" },"stuff"], " oboy!"] )

    doc = (doc || parent.ownerDocument || document);
    var e;

    if(t == undefined) {
        throw complaining( "Can't graft an undefined value");
    } else if(t.constructor == String) {
        e = doc.createTextNode( t );
    } else if(t.length == 0) {
        e = doc.createElement( "span" );
        e.setAttribute( "class", "fromEmptyLOL" );
    } else {
        for(var i = 0; i < t.length; i++) {
            if( i == 0 && t[i].constructor == String ) {
                var snared;
                snared = t[i].match( /^([a-z][a-z0-9]*)\.([^\s\.]+)$/i );
                if( snared ) {
                    e = doc.createElement(   snared[1] );
                    e.setAttribute( 'class', snared[2] );
                    continue;
                }
                snared = t[i].match( /^([a-z][a-z0-9]*)$/i );
                if( snared ) {
                    e = doc.createElement( snared[1] );  // but no class
                    continue;
                }

                // Otherwise:
                e = doc.createElement( "span" );
                e.setAttribute( "class", "namelessFromLOL" );
            }

            if( t[i] == undefined ) {
                throw complaining("Can't graft an undefined value in a list!");
            } else if(  t[i].constructor == String ||
                                    t[i].constructor == Array ) {
                graft( e, t[i], doc );
            } else if(  t[i].constructor == Number ) {
                graft( e, t[i].toString(), doc );
            } else if(  t[i].constructor == Object ) {
                // hash's properties => element's attributes
                for(var k in t[i]) {
                    // support for attaching closures to DOM objects
                    if(typeof(t[i][k])=='function'){
                        e[k] = t[i][k];
                    } else {
                        e.setAttribute( k, t[i][k] );
                    }
                }
            } else {
                throw complaining( "Object " + t[i] +
                    " is inscrutable as an graft arglet." );
            }
        }
    }

    parent.appendChild( e );
    return e; // return the topmost created node
}

function complaining (s) { alert(s); return new Error(s); }
