Fly.Dom = {};

/**
 * Get the tagName part of the array
 * @param {Array} arr an Array
 * @return tagName
 * @type String
 */
Fly.Dom.getTagName = function(arr)
{
	return arr[0];
};

/**
 * Get the attributes part of the array
 * @param {Array} arr an Array
 * @return A hash of parameter name to value
 * @type Object
 */
Fly.Dom.getAttributes = function(arr) {
	return arr[1];
};


/**
 * Check to see if the argument is an element. We only do a crude test.
 * @param {DOMElement} elem any variable
 * @return true if the variable is detected to be a DOMElement, false otherwise
 * @type boolean
 */
Fly.Dom.isElement = function(elem)
{
	return (isObject(elem) && elem != null && !isUndef(elem.nodeType));
};


/**
 * Use the a property name and value for the element. The name is checked to see if it matches special cases.
 * The default behavior is to add the name and value as an attribute to the element.
 * @param {DOMElement} elem The element to operate on
 * @param {String} name Name of the property
 * @param {Object} value Value of the property
 * @param {Object} assignObj Object to use for assignment operation
 */
Fly.Dom.useProperty = function( elem, name, value, assignObj)
{
	switch (name)
	{
		case "html":
			elem.innerHTML = value;
			break;
		case "className":
			elem.className = value;
			break;
		case "style":
			if (isObject(value))
			{
				Object.extend(elem.style,value);
			}
			else if (isString(value))
			{
				elem.cssText = value;
			}
			break;
		case "=":
			if (assignObj) assignObj[value] = $(elem);
			break;
		case "for":
			elem.htmlFor = value;
			break;
		default:
			if (name.indexOf("on") == 0)
			{
				// kinda of a hack, TODO: fixme
				if (name == 'onchange' && elem.tagName=='INPUT' && document.all) // IE check
	 			{	
	 				name = 'onpropertychange';
	 			}
	 			
				if (isFunction(value))
				{
					Event.observe(elem, name.substring(2),value,false);
				}
				else if (isString(value))
				{
					elem[name] = new Function(value);
				}
				else
				{
					elem.setAttribute(name,value);	
				}
			}
			else
			{
				elem.setAttribute(name,value);	
			}
			
	}
};

/**
 * Used to generate an error text node so that errors are messaged properly and surrounding elements are not affected.
 * An ID is generated to be displayed in the text node and in the Logger console
 * @param {String} msg The error messagen
 */
Fly.Dom.createErrorNode = function(msg)
{
	var errorId = Math.floor(Math.random()*10000);
	if (Logger && Logger.error)
	{
		Logger.error("ERROR " +errorId + ": " + msg);
	}
	return document.createTextNode("!ERROR: " + errorId);
};

/**
 * Create a DOMElement from the specified json.
 * The json should be either an Array, DOMElement, Number, or String
 * For an Array, it assumes the convention for specifying tagName, attributes, and childNodes
 * and creates new DOMElements accordingly. The root DOMElement is then returned.
 * For a DOM Element, it is just returned back
 * For a String or Number, a TextNode is created and returned
 * An error will cause an error message TextNode to be returned, so that operations that are dependent on this
 * function returning a valid DOMElement can continue.
 * @param {Array} json an Array, DOMElement, or String
 * @return The root DOMElement
 * @type DOMElement
 */
Fly.Dom.create = function(json, assignObj) 
{
	var elem = null;
 	if (isArray(json)) {
 		try {
 			var tagName = Fly.Dom.getTagName(json);
 			var attributes = this.getAttributes(json);

	 		
			if (!isNun(attributes))
			{
	 			if (attributes.name && document.all) // IE check
	 			{	
	 				try 
	 				{ 
	 					elem = document.createElement('<'+tagName+' name="'+attributes.name+'">'); 
	 					delete attributes.name;
	 				}
	 				catch (e) {};	
	 			}
	 			if (!elem)
	 			{
	 				elem = document.createElement(tagName);
	 			}
				if (tagName == "input" && attributes.type)
				{
					elem.setAttribute("type",attributes.type);
					delete attributes.type;
				}
				for (var name in attributes)
				{
					Fly.Dom.useProperty(elem,name,attributes[name],assignObj);
				}
			}
 			if (!elem)
 			{
 				elem = document.createElement(tagName);
 			}
			for (var i=2;i<json.length;i++)
			{
				elem.appendChild(Fly.Dom.create(json[i],assignObj));
			}
 		}
 		catch (e)
 		{
 			elem = Fly.Dom.createErrorNode(e+"");
 		}
	}
	else if (isString(json) || isNumber(json)) 
	{
		elem = document.createTextNode(json);
	}
	else if (Fly.Dom.isElement(json))
	{
		elem = json;
	}
	else
	{
		if (isObject(json))
		{
			msg = "Invalid argument to Fly.Dom.create: " + Object.inspect($H(json));
		}
		else
		{
			msg = "Invalid argument to Fly.Dom.create: " + json;
		}
		elem = Fly.Dom.createErrorNode(msg);
	}
	return $(elem);
};

Fly.Dom.textRowDef = function(name, label) 
{
	var def = 
		["tr",,
			["th",{"=":name+"Label"},label],
			["td",,["input",{className:"text", "=":name,name:name}]]
		];
		
	return def;
};

Fly.Dom.selectCountryRowDef = function(name, label)
{
	var def = 
		["tr",,
			["th",{"=":name+"Label"},label],
			["td",,
				["select",{"=":name,name:name},
					["option", { value: "USA" }, "United States"],
					["option", { value: "CAN" }, "Canada"]
				]
			]
		];
		
	return def;
};
