/////////////////////////////////////////////////////////////////////////////////
//
// c) 2010 Panther Panache, LLC.  
// This source code is Confidential and Proprietary information of the company.
//
/////////////////////////////////////////////////////////////////////////////////
package com.panache.xml
{
	import com.panache.debug.MediaServicesAdDebug;
	import com.panache.utilities.PanacheCreativeCoreUtilities;
	
	/**
	 * This class will parse the XML.
	 * 
	 * @see	com.panache.core.PanacheObject					PanacheObject
	 * @see com.panache.xml.parser.IPanacheXMLParser		IPanacheXMLParser
	 */
	public class MediaServicesXMLParser
	{
		//////////////////////////////////////////////////////////////////////////////////////////
		// CONSTANTS

		private static const VERSION_MAJOR:Number		= 1;
		private static const VERSION_MINOR:Number		= 1;
		private static const VERSION_STRING:String		= VERSION_MAJOR + "." + VERSION_MINOR;
		
		private static const DEBUG_SOURCE	: String	= "MediaServicesXMLParser";
		
		//////////////////////////////////////////////////////////////////////////////////////////
		// PROTECTED VARS		

		private var _xml 					: XML;
		private var _xmlNamespace			: Namespace;
		
				
		/**
		 * Creates a PanacheXMLParser object.
		 */
		public function MediaServicesXMLParser( xml:XML )
		{
			MediaServicesAdDebug.reportVersion(DEBUG_SOURCE, VERSION_STRING);
			try
			{
				//_xml = new XML(xmlSrc);	// if param is a string this still works..
				_xml = xml;					// if param is an xml
				_xmlNamespace = _xml.namespace();
			}
			catch (ex:Error)
			{
				MediaServicesAdDebug.reportErrorTrace("Error opening xml", ex, DEBUG_SOURCE);
				_xml = null;
			}			
		}
		
		//////////////////////////////////////////////////////////////////////////////////////////
		// OVERRIDE METHODS
		

		//////////////////////////////////////////////////////////////////////////////////////////
		// PUBLIC METHODS
		
		/**
		 * This checks if the xml is valid.
		 * 
		 * @return <code>true</code> if the xml is valid; <code>false</code> otherwise.
		 */
		public function isValid() : Boolean
		{
			return (_xml != null);
		}
		
		/**
		 * This checks if the node is empty.
		 * 
		 * @param	node	the node to check.
		 * 
		 * @return <code>true</code> if the node is not empty; <code>false</code> otherwise.
		 */
		public function isNodeNotEmpty( node:XMLList ) : Boolean
		{
			return ((node != null) && (node.length() > 0));
		}

		/**
		 * This function get the root node.
		 * 
		 * 
		 * @param	nodeName	the name of the node to get the root node.
		 * 
		 * @return	the root node.
		 * 
		 * @example If we have the following xml:
		 * <listing version="3.0">
		 * &lt;xml&gt;
         *   &lt;dak&gt;100&lt;/dak&gt; 
         *   &lt;bar&gt;200&lt;/bar&gt; 
         * &lt;/xml&gt;
		 * </listing>
		 * If we do getRootNode("dak"), we would get <code>100</code>.
		 * 
		 */
		public function getRootNode( nodeName:String ) : XMLList
		{
              var node:XMLList = null;
              
              try
              {
                    // first look to see if root XML node is named the same as nodeName
                    // if so, return the root node
                    if (_xml.name() == nodeName)
                          return XMLList(_xml);
					                    
                    // then check to see if nodeName is a node of the root      
                    node = _xml[nodeName];
                    if (node != null)
                    {
                          if (node.length() > 0)
                          {
                                // found it as a child  
                          }
                          else
                          {
                                // it is empty and if so, then "dig" for the node
                                node = _xml.descendants(nodeName);
                          }
                          MediaServicesAdDebug.reportTrace("Got node: " + nodeName, DEBUG_SOURCE, "getPanacheNode");    
                    }
                    else
                          node = null;
              }
              catch (ex:Error)
              {
                    MediaServicesAdDebug.reportErrorTrace("Error getting node: " + nodeName, ex, DEBUG_SOURCE, "getPanacheNode");
                    node = null;      
              }
              
              return node;
		}
		
		/**
		 * This function returns the root node with the specified id.
		 * 
		 * 
		 * @param	nodeName	name of the node.
		 * @param	id			id of the node.
		 * 
		 * @return	<code>XMLList</code> that is the root node.
		 * 
		 * @example If we have the following xml:
		 * <listing version="3.0">
		 * &lt;xml&gt;
         *   &lt;dak id="1"&gt;100&lt;/dak&gt; 
         *   &lt;dak id="2"&gt;200&lt;/dak&gt; 
         * &lt;/xml&gt;
		 * </listing>
		 * If we do getRootNodeWithId("dak", "1"), we would get <code>100</code>.
		 * 
		 * 
		 */
		public function getRootNodeWithId( nodeName:String, nodeId:String ) : XMLList
		{
			var node:XMLList;
			
			try
			{
				if(nodeId == null)
				{
					return null;
				}
				else
				{
					// this syntax (..*) allows us to "dig" for our node
					//node = xml..*[nodeName].(@id == nodeId);
					// note the ..* notation does not work when panache is direct child of root
					// use this notation instead
					//node = xml.descendants(nodeName).(@id == nodeId);
					node = _xml[nodeName].(@id == nodeId);
					if (node != null)
					{
						MediaServicesAdDebug.reportTrace("Node found with length=" + node.length(), DEBUG_SOURCE, "getXMLNode");
						if (node.length() == 0)
							//node = xml..*[nodeName].(@id == nodeId);
							node = _xml.descendants(nodeName).(@id == nodeId);
						MediaServicesAdDebug.reportTrace("Got node:\n" + node, DEBUG_SOURCE, "getXMLNode");
						
					}
					
					if (node == null)
					{
						MediaServicesAdDebug.reportErrorTrace("NULL node returned: " + nodeName + " for " + nodeId, null, DEBUG_SOURCE, "getXMLNode");
					}	
				}
			}
			catch (ex:Error)
			{
				MediaServicesAdDebug.reportErrorTrace("Error getting node: " + nodeName + " for " + nodeId, ex, DEBUG_SOURCE, "getXMLNode");
				node = null;	
			}
			
			return node;
		}

		/**
		 * Checks if the node exists.
		 * 
		 * 
		 * @param	parentNode	the parent node.
		 * @param	nodeName	the name of the node.
		 * 
		 * @return	<code>true</code> if the node does exist; <code>false</code> otherwise.
		 * 
		 * @see 	com.panache.adUnits.xml.PanacheXMLParser#getNode()	getNode()
		 * 
		 * @example If we have the following xml:
		 * <listing version="3.0">
		 * &lt;xml&gt;
         *   &lt;dak&gt;100&lt;/dak&gt; 
         *   &lt;dak&gt;200&lt;/dak&gt; 
         * &lt;/xml&gt;
		 * </listing>
		 * If we do nodeExists(new XMLList(xml), "dak"), we would get <code>true</code>.
		 */
		public function nodeExists( parentNode:XMLList, nodeName:String ) : Boolean
		{
			var node:XMLList = getNode(parentNode, nodeName);
			return this.isNodeNotEmpty(node);
		}

		/**
		 * Gets the node with the specified parentNode and nodeName.
		 * 
		 * 
		 * @param	parentNode	the parent of the node.
		 * @param	nodeName	the name of the node.
		 * 
		 * @return	the <code>XMLList</code> which is the node we are looking for. 
		 * 
		 * @example If we have the following xml:
		 * <listing version="3.0">
		 * &lt;xml&gt;
		 *   &lt;dak&gt;
		 *     &lt;koo&gt;kookoo&lt;/koo&gt;
		 *   &lt;/dak&gt; 
         *   &lt;bar&gt;100bars&lt;/bar&gt; 
		 * &lt;/xml&gt;
		 * </listing>
		 * 
		 * If we do getNode(new XMLList(xml), "dak"), we would get 
		 * <listing version="3.0">
		 * &lt;dak&gt;
		 *   &lt;koo&gt;kookoo&lt;/koo&gt;
		 * &lt;/dak&gt;
		 * </listing>
		 * 
		 */
		public function getNode( parentNode:XMLList, nodeName:String ) : XMLList
		{
              var node:XMLList = null;
              
              try
              {
                    // first look to see if root XML node is named the same as nodeName
                    // if so, return the root node
                    if (parentNode.name() == nodeName)
                          return parentNode;
					                    
                    // then check to see if nodeName is a node of the root      
                    node = parentNode[nodeName];
                    if (node != null)
                    {
                          if (node.length() > 0)
                          {
                                // found it as a child  
                          }
                          else
                          {
                                // it is empty and if so, then "dig" for the node
                                node = parentNode.descendants(nodeName);
                          }
                          MediaServicesAdDebug.reportTrace("Got node: " + nodeName, DEBUG_SOURCE, "getPanacheNode");    
                    }
                    else
                          node = null;
              }
              catch (ex:Error)
              {
                    MediaServicesAdDebug.reportErrorTrace("Error getting node: " + nodeName, ex, DEBUG_SOURCE, "getPanacheNode");
                    node = null;      
              }
              
              return node;
		}
		
		
		/**
		 * This function gets the node with the specified nodeName and index.
		 * 
		 * @example If we have the following xml:
		 * <listing version="3.0">
		 * &lt;xml&gt;
         *   &lt;dak&gt;
		 *     &lt;koo&gt;kookoo&lt;/koo&gt;
		 *     &lt;puffs&gt;puffs&lt;/puffs&gt;
		 *   &lt;/dak&gt;  
         *   &lt;bar&gt;100bars&lt;/bar&gt;  
         * &lt;/xml&gt;
		 * </listing>
		 * 
		 * If we do getNodeAt(new XMLList(xml), "dak", 0), we would get: 
		 * <listing version="3.0">
		 * &lt;dak&gt;
		 *   &lt;koo&gt;kookoo&lt;/koo&gt;
		 *   &lt;puffs&gt;puffs&lt;/puffs&gt;
		 * &lt;/dak&gt;
		 * </listing>
		 *  
		 * 
		 * @example And if we have the following xml:
		 * <listing version="3.0">
		 * &lt;xml&gt;
         *   &lt;dak&gt;
		 *     &lt;koo&gt;kookoo&lt;/koo&gt;
		 *     &lt;puffs&gt;puffs&lt;/puffs&gt;
		 *   &lt;/dak&gt;  
         *   &lt;bar&gt;100bars&lt;/bar&gt;  
         *   &lt;dak&gt;
		 *     &lt;koo&gt;kookoo222&lt;/koo&gt;
		 *     &lt;puffs&gt;puffs222&lt;/puffs&gt;
		 *   &lt;/dak&gt;
         * &lt;/xml&gt;
		 * </listing>
		 *  
		 * If we do getNodeAt(new XMLList(xml), "dak", 0), we would get the same result
		 * as Example 1, which is:
		 * <listing version="3.0">
		 * &lt;dak&gt;
		 *   &lt;koo&gt;kookoo&lt;/koo&gt;
		 *   &lt;puffs&gt;puffs&lt;/puffs&gt;
		 * &lt;/dak&gt;
		 * </listing>
		 * 
		 * 
		 * @param	nodeName	the name of the node.
		 * @param	index		the index of the node.
		 * 
		 * @return	the <code>XMLList</code> that match the parameters.
		 */
		public function getNodeAt( parentNode:XMLList, nodeName:String, index:uint ) : XMLList
		{
			MediaServicesAdDebug.reportTrace("Getting node index=" + index, DEBUG_SOURCE, "getNodeAt");
			var nodeItem : XMLList = null;
			
			if( isNodeNotEmpty(parentNode) )
			{
				var items : XMLList = getNode(parentNode, nodeName);
				if ((items != null) && (items.length() > index))
				{
					nodeItem = XMLList(items[index]);
				}	
			}
			
			MediaServicesAdDebug.reportTrace("Found " + nodeName + " index=" + index + " item=" + nodeItem, DEBUG_SOURCE, "getNodeAt");
					
			return nodeItem;
		}
		
		/**
		 * This method returns the node with the specified attribute name and attribute value.
		 * 
		 * @example If we have the following xml:
		 * <listing version="3.0">
	     * &lt;xml greeting="hello"&gt; 
	     *   &lt;dak greeting="hello"&gt;
		 *     &lt;koo&gt;kookoo&lt;/koo&gt;
		 *     &lt;puffs&gt;puffs&lt;/puffs&gt;
		 *   &lt;/dak&gt; 
	     *   &lt;dak greeting="hi"&gt;
		 *     &lt;koo&gt;kookoo&lt;/koo&gt;
         *     &lt;puffs&gt;puffs&lt;/puffs&gt;
		 *   &lt;/dak&gt;							
		 *   &lt;bar&gt;100bars&lt;/bar&gt; 							
	     * &lt;/xml&gt; 
		 * </listing>
		 * 
		 * If we do getNodeWithAttr(new XMLList(xml), "dak", "greeting", "hello"), we would get: 
		 * <listing version="3.0">
		 * &lt;dak greeting="hello"&gt;
		 *   &lt;koo&gt;kookoo&lt;/koo&gt;
		 *   &lt;puffs&gt;puffs&lt;/puffs&gt;
		 * &lt;/dak&gt;
		 * </listing>
		 * 
		 *  
		 * @param	parentNode	the parent node.
		 * @param	nodeName	the name of the node.
		 * @param	attrName	the name of the attribute.
		 * @param	attrValue	the value of the attribute.
		 * 
		 * @return	<code>XMLList</code> the node that match with the attribute name and value.
		 */
		public function getNodeWithAttr(  parentNode:XMLList, 
											nodeName:String, 
											attrName:String, 
										   attrValue:String ) : XMLList
		{
			var node:XMLList = null;
			try
			{									
				node = parentNode[nodeName].(attribute(attrName) == attrValue);	
			}
			catch (ex:Error)		
			{
				MediaServicesAdDebug.reportErrorTrace("Error getting node: " + nodeName + "- " + attrName + "=" + attrValue, ex, DEBUG_SOURCE, "getNodeWithAttr");
				node = null;
			}
			
			return node;			
		}
		
		/**
		 * This method returns the node that is not the specified attribute name.
		 * 
		 * @param	parentNode	the parent node.
		 * @param	nodeName	the name of the node.
		 * @param	attrName	the name of the attribute.
		 * 
		 * @return	<code>XMLList</code> the node that does not match with the attribute name.
		 */		
		public function getNodeWithoutAttr( parentNode:XMLList, 
											  nodeName:String, 
											  attrName:String ) : XMLList
		{
			var node:XMLList = null;
			try
			{
				node = parentNode[nodeName].(attribute(attrName).length() == 0);	
			}
			catch (ex:Error)
			{
				MediaServicesAdDebug.reportErrorTrace("Error getting node: " + nodeName + "- " + attrName, ex, DEBUG_SOURCE, "getNodeWithoutAttr");
				node = null;
			}
			
			return node;
		}

		/**
		 * This method returns the node attributes.
		 * 
		 * @param	node		the name of the node.
		 * 
		 * @return	<code>Object</code> the node attributes.
		 */	
		public function getAttributes( node:XML ) : Object
		{
			var attributes:Object = new Object();
			if (node != null)
			{
				var attrList:XMLList = node.attributes();
				for (var i:int = 0; i < attrList.length(); i++)
				{
					var attrName:String = attrList[i].name();
					var attrValue:String = node.attribute(attrName);
					attributes[attrName] = attrValue;	
				}	
			}
			
			return attributes;
		}
		
		/**
		 * This method returns the node attributes.
		 * 
		 * @param	node		the name of the node.
		 * 
		 * @return	<code>String</code> the node string value.
		 */			
		public function getStringValueFromNode(node:XML, defaultValue:String=null) : String
		{
			var value:String = node.valueOf();
			if ((value != null) && (value.length > 0))	
				return value;		
			else
				return defaultValue;
				
		}
		
		/**
		 * This method returns the node value.
		 * 
		 * @param	node			the name of the node.
		 * @param	type			the type of the object to be returned.
		 * @param	defaultValue	the default value if the node is missing.
		 * 
		 * @return	<code>Object</code> the node string value.
		 */			
		public function getNodeValue( node:XML, type:String, defaultValue:Object = null ) : *
		{
			var answer		: Object = defaultValue;
			var valString	: String;
			
			try
			{
				switch( type.toLowerCase() )
				{
					case "string":
						answer = getStringValueFromNode( node, (defaultValue as String) );
						break;
						
					case "boolean":
						valString 	= getStringValueFromNode( node, String(defaultValue) );
						answer 		= PanacheCreativeCoreUtilities.coerceValueToType(valString, "Boolean", defaultValue);
						break;
						
					case "number":
						valString = getStringValueFromNode( node, null );
						if( (valString != null) && (valString.length>0) )
						{
							if( isNaN( Number(valString) ) )
								answer = defaultValue;
							else	
								answer = Number(valString);
						}
						else
							answer = defaultValue;
						break;
						
					case "hex":
						valString 	= getStringValueFromNode(node, null);
						answer 		= PanacheCreativeCoreUtilities.coerceValueToType(valString, "hex", defaultValue);
						break;	
				}
			}
			catch( ex:Error )
			{
				MediaServicesAdDebug.reportErrorTrace("Error getting node: " + node, ex, DEBUG_SOURCE, "getNodeValue");
			}
			
			return answer;
		}
		
		/**
		 * Returns the value of a child node found within a parentNode.  The child node can be at any level.
		 * 
		 * @param parentNode is an XMLList object representing the parent node; this should not be null.
		 * 
		 * @param nodeName is the name of the child node being sought within the parent node; this should be a valid string.
		 * 
		 * @param type is a String which identifies the data type of the value being sought;  supported types include:
		 * String, Number, Boolean, HEX  (not case sensitive)
		 * 
		 * @defaultValue is a value that is returned if either the child node is not present or the node has no value.
		 */ 
		public function getNodeValueFromChild(parentNode:XMLList, nodeName:String, type:String, defaultValue:Object = null ) : *
		{
			var nodeValue:* = defaultValue;
			var node:XMLList = this.getNode(parentNode, nodeName);
			if (this.isNodeNotEmpty(node))
				nodeValue = this.getNodeValue(this.xmlListToXML(node), type, defaultValue);
			
			
			return nodeValue;
		}
		
		public function getUrlFromChildNode(parentNode:XMLList, nodeName:String, defaultValue:String = null ) : String
		{
			var urlString:String = defaultValue;
			if (nodeExists(parentNode, nodeName))
			{
				// first try and get it from the node
				var childNode:XMLList = getNode(parentNode, nodeName);
				urlString = getUrlFromNode(childNode, defaultValue);
			}
			
			return urlString;
		}
		
		public function getUrlFromNode(node:XMLList, defaultValue:String = null) : String
		{
			var urlString:String = defaultValue;
			if (isNodeNotEmpty(node))
			{
				var testValue:String;
				var nodeXML:XML = this.xmlListToXML(node);
				
				// set the node where the url string should be retrieved
				// by default, use the node that was passed in
				var urlNode:XML = nodeXML;
				
				// if there are <url> nodes inside the base node,
				// replace urlNode with the first url node in the list
				var urlNodes:XMLList = getNode(node, MediaServicesXMLConstants.NODE_URL);
				if (this.isNodeNotEmpty(urlNodes))
				{
					urlNode = urlNodes[0]; 
				}
				
				// get the value from the node; if it is not "empty", the use that as the return value
				testValue = getStringValueFromNode(urlNode, null);
				if (PanacheCreativeCoreUtilities.isStringNotEmpty(testValue))
					urlString = testValue;
				
				MediaServicesAdDebug.reportTrace("URL=[" + urlString + "] for node=" + nodeXML.name());
			}
			
			return urlString;
		}
		
		/**
		 * This method returns all the values in a node.
		 * 
		 * 
		 * @example If we have an xml as follows:
		 * <listing version="3.0">
         * &lt;xml&gt;
		 *   &lt;dak&gt;
		 *     &lt;blah&gt;hi&lt;/blah&gt;
		 *     &lt;blah&gt;hello&lt;/blah&gt;
		 *     &lt;blah&gt;bye&lt;/blah&gt;
		 *     &lt;blah2&gt;aloha&lt;/blah2&gt;
         *   &lt;/dak&gt;
		 *   &lt;koo&gt;
		 *     hi!
		 *   &lt;/koo&gt;
		 * &lt;/xml&gt;
		 * </listing>
		 * 
		 * <p> 
		 * If we do getNodeValues(new XMLList(xml), "dak", "blah"),
		 * we would get: <code>hi, hello, bye.</code>
		 * </p>
		 * 
		 * <p>
		 * If we do getNodeValues(new XMLList(xml), "dak", "*"),
		 * we would get: <code>hi, hello, bye, aloha.</code>
		 * </p>
		 * 
		 * @param		parentNode			the xml list
		 * @param		nodeName			the name of the node
		 * @param		listName			the name of the nodes inside nodeName that you want to get the values of.
		 * 
		 * @return		<code>Array</code>	the list of values, <code>null</code> if there are none.
		 */
		public function getNodeValues( parentNode:XMLList, nodeName:String, listName:String=null ) : Array
		{
			var list:Array = null;
			if( parentNode == null )
			{
				MediaServicesAdDebug.reportErrorTrace("Parent node doesnt exist: ", null, DEBUG_SOURCE, "getValuesFromNode");				
				return list;
			}
			
			var xmlList:XMLList = getNode(parentNode, nodeName);
		// if list name is null we get all the values by setting it to star.
			if( listName == null )
				listName = "*";
			xmlList = xmlList[listName];
		// check if we have any items in the list, if we do then add it to the array
		// else return null
			if( xmlList.length() > 0 )
			{
				list = new Array();
			// loop through the list and get the values and store in the array
				for( var i:uint = 0 ; i < xmlList.length(); i++ )
					list.push( xmlList[i] );
			}
		// return the array
			return list;
		}
				
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// GETTING ATTRIBUTES	
		
		/**
		 * This method returns the attribute from node.
		 * 
		 * @param	node			the name of the node.
		 * @param	type			the type of the object to be returned.
		 * @param	defaultValue	the default value if the node is missing.
		 * 
		 * @return	<code>String</code> the node string value.
		 */			
		public function getAttributeValueFromNode(node:XML, attrName:String, defaultValue:String=null) : String
		{
			var value:String = node.@[attrName];
			if ((value != null) && (value.length > 0))	
				return value;		
			else
				return defaultValue;
		}
		
		/**
		 * This method returns the Number value of the attribute from node.
		 * 
		 * @param	node			the name of the node.
		 * @param	attrName		the attribute name.
		 * @param	defaultValue	the default value if the node is missing.
		 * 
		 * @return	<code>Number</code> the node Number value.
		 */		
		public function getNumericalAttributeValueFromNode(node:XML, attrName:String, defaultValue:Number=undefined) : Number
		{
			var valString:String = getAttributeValueFromNode(node, attrName);
			if ((valString != null) && (valString.length > 0))
			{
				if( isNaN(Number(valString)) )
					return defaultValue;
				else	
					return Number(valString);	
			}	
			else
				return defaultValue;
		}
			
		/**
		 * This method returns the Boolean value of the attribute from node.
		 * 
		 * @param	node			the name of the node.
		 * @param	attrName		the attribute name.
		 * @param	defaultValue	the default value if the node is missing.
		 * 
		 * @return	<code>Boolean</code> the node Boolean value.
		 */					
		public function getBooleanAttributeValueFromNode(node:XML, attrName:String, defaultValue:Boolean=true) : Boolean
		{
			var valString:String = getAttributeValueFromNode(node, attrName);
			// check to see if the node exists, if it does return the value or the default value
				// if the node has value convert it to a Boolean
				// if it does not have a value or has an invalid value , return the default value
				if ((valString != null) && (valString.length > 0))
				{
					if( valString.toLowerCase() == "true" )
					{
						return true;
					}
					if( valString.toLowerCase() == "false" )
					{
						return false;
					}
				}
				return defaultValue;
		}
				
		/**
		 * This method returns the Hex value of the attribute from node.
		 * 
		 * @param	node			the name of the node.
		 * @param	attrName		the attribute name.
		 * @param	defaultValue	the default value if the node is missing.
		 * 
		 * @return	<code>Hex</code> the node Boolean value.
		 */					
		public function getHexAttributeValueFromNode(node:XML, attrName:String, defaultValue:Number=undefined) : Number
		{
			var strValue : String = getAttributeValueFromNode(node, attrName, null);
			return PanacheCreativeCoreUtilities.coerceValueToType(strValue, "hex", defaultValue);
		}
				
		/**
		 * This method returns the attribute value from the node.
		 * 
		 * @param	node			the node to get the attribute from.
		 * @param	attrName		the attribute name.
		 * @param	type			the type you want this return object to be.
		 * @param	defaultValue	the default value if not found.
		 * 
		 * @return	<code>Object</code> the value from the child node.
		 */					
		public function getAttributeValue( 			node:XML, 
												attrName:String,
											    	type:String, 
									    	defaultValue:* = null ) : *
		{
			switch( type.toLowerCase() )
			{
				case "string":
					return getAttributeValueFromNode( node, attrName, defaultValue );
					
				case "number":
					return getNumericalAttributeValueFromNode( node, attrName, defaultValue );
					
				case "boolean":
					return getBooleanAttributeValueFromNode( node, attrName, defaultValue );
					
				case "hex":
					return getHexAttributeValueFromNode( node, attrName, defaultValue );
					
				default:
					return defaultValue;
			} 				
		} 

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// GETTINGS VALUES FROM CHILD NODES
		
		/**
		 * This method returns the value from the child node.
		 * 
		 * @param	parentNode		the node parent
		 * @param	nodeName		the name of the node
		 * @param	type			the type you want this return object to be.
		 * @param	defaultValue	the default value if not found
		 * @param	missingValue	the value if this node name doesnt exist
		 * 
		 * @return	<code>Object</code> the value from the child node.
		 */		
		public function getValueFromChildNode( 	  parentNode:XMLList, 
												 	nodeName:String, 
												     	type:String, 
											 	defaultValue:Object = null,
											 	missingValue:Object = null ) : *
	 	{
	 		var answer:Object = missingValue;
	 		
	 		if( (parentNode != null) &&	(nodeName != null) && (nodeName.length > 0) )
	 		{
		 		var childNode:XMLList = getNode( parentNode, nodeName );
				// Thong Note: TODO
				// check if childNode.length > 1 then only use the first one since
				// it is returning a list of duplicates.
		 		if ( isNodeNotEmpty(childNode) )
		 			answer = this.getNodeValue( XML(childNode), type, defaultValue );	
		 	}
	 		
	 		return answer;
	 	}

		/**
		 * This method returns the attribute value from the child node.
		 * 
		 * @param	parentNode		the node parent
		 * @param	nodeName		the name of the node
		 * @param	attrName		the attribute name
		 * @param	type			the type you want this return object to be.
		 * @param	defaultValue	the default value if not found
		 * 
		 * @return	<code>Object</code> the attribute value from the child node.
		 */
		public function getAttributeValueFromChildNode(   parentNode:XMLList, 
														  	nodeName:String, 
														  	attrName:String, 
														      	type:String, 
												 	  	defaultValue:Object = null ) : *
		{
			var answer : Object = defaultValue;
			
			if( (parentNode != null) &&	(nodeName != null) && (nodeName.length > 0) )
			{
				var childNode : XMLList = getNode(parentNode, nodeName);
				if ( isNodeNotEmpty(childNode) )
					answer = getAttributeValue( XML(childNode), attrName, type, defaultValue );	
			}
				
			return answer;	
		}

		/**
		 * Returns the XMLList from an XML object.
		 * 
		 * @param	xmlObject	the XML to get the XMLList from.
		 * 
		 * @return	<code>XMLList</code> the XMLList from the xmlObject.
		 */
		public function xmlToXMLList( xmlObject : XML ) : XMLList
		{
			var xmlListObject : XMLList = null;
			if (xmlObject != null)
				xmlListObject = new XMLList(xmlObject.toXMLString());
		
			return xmlListObject;		
		}
		
		/**
		 * Returns an XML object from an XMLList.
		 * 
		 * @param 	xmlList 	is an XMLList object.
		 * 						This is frequently the result of calling getNode() which can return null
		 * 						or an empty list if the target node is not present.
		 * 
		 * @return 	a non-null value is the xmlList object cast into XML;
		 *			a return value of <code>null</code> means the node was not present.
		 */
		 public function xmlListToXML(xmlList:XMLList) : XML
		 {
		 	if (isNodeNotEmpty(xmlList))
		 		return XML(xmlList);
		 	else
		 		return null;
		 }
		 
	}
}