/*!
 * XMLHelper class
 * @version 1.0
 * @author M.F.Endenburg
 * @copyright (c) Denbel Systems, 2008
 */

// load namespace
Denbel.load( 'util.XmlHelper' );

( function(){
    /**
     * Denbel.util.XmlHelper static class
     */
    Denbel.util.XmlHelper =
    {
        /**
         * NodeType conversion table
         * @var Array
         */
        nodeTypeToString: new Array
        (
            'unknown',
            'element',
            'attribute',
            'text',
            'cdata',
            'entity_ref',
            'entity',
            'process',
            'comment',
            'document',
            'doctype',
            'docfrag',
            'notation'
        ),
        
        /**
         * Converts an XML string to an XMLDocument object
         * @param string input
         * @param string type
         * @return XMLDocument
         */
        stringToXml: function( string, type )
        {
            if( !type )
            {
                type = 'text/xml';
            }
            
            if( !string || string == '' )
            {
                YAHOO.log( 'Empty string given to convert to XML!', 'error' );
                return null;
            }
            
            var doc = null;

            if( window.ActiveXObject )
            {
                doc = new ActiveXObject( 'MSXML2.DOMDocument' );
                doc.async = false;
                doc.loadXML( string );
            }
            else
            {
	            if( type == 'application/xhtml+xml' )
	            {
	                string = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">' + string;
	            }
	            
                var parser = new DOMParser();
                doc = parser.parseFromString( string, type );
            }
            
            if( doc.documentElement.tagName.toLowerCase() == 'parsererror' )
            {
                throw Error( 'Unable to parse string' );
            }
            
            return doc;
        },
        
        /**
	     * Creates a new XML document instance
	     * @param string version XML version
	     * @param string encoding of XML document
	     * @return DOM object
	     */
        createXmlDocument: function( version, encoding )
        {
            if( !version )
            {
                version = '1.0';
            }
            
            if( !encoding )
            {
                encoding = 'utf-8';
            }
            
            var rootTagName = null;
            
            if( document.implementation && document.implementation.createDocument )
            {
                // This is the W3C standard way to do it 
                return document.implementation.createDocument( null, null, null );
            }
            else // This is the IE way to do it
            {
                // Create an empty document as an ActiveX object
                // If there is no root element, this is all we have to do
                var doc = new ActiveXObject( 'MSXML2.DOMDocument' );
                doc.async = false;
                
                // If there is a root tag, initialize the document
                if( rootTagName )
                {
                    // Look for a namespace prefix
                    var prefix = '';
                    var tagname = rootTagName;
                    var p = rootTagName.indexOf( ':' );
                    
                    if( p != -1 )
                    {
                        prefix = rootTagName.substring( 0, p );
                        tagname = rootTagName.substring( p + 1 );
                    }
                    
                    // If we have a namespace, we must have a namespace prefix
                    // If we don't have a namespace, we discard any prefix
                    if( namespaceURL )
                    {
                        if( !prefix )
                        {
                            prefix = 'a0'; // What Firefox uses
                        }
                    }
                    else
                    {
                       prefix = '';
                    }
    
                    // Create the root element (with optional namespace) as a string of text
                    var text = '<' + ( prefix ? ( prefix + ':' ) : '' ) +  tagname + ( namespaceURL ? ( ' xmlns:' + prefix + '="' + namespaceURL + '"' ) : '' ) + '/>';
                    
                    // And parse that text into the empty document
                    doc.loadXML( text );
                }
                
                return doc;
            }
        },
        
        /**
         * Converts a DOM document to string
         * @param XMLDocument
         * @param string mime type
         * @return string
         */
        xmlToString: function( dom, type )
        {
            if( !dom )
            {
                return null;
            }
            
            if( !type )
            {
                type = 'text/xml';
            }
            
            var s = null;
            
            if( Denbel.util.BrowserDetect.browser == 'Explorer' )
            {
                s = dom.xml;
            }
            else
            {
                try
                {
	                switch( type )
	                {
	                    case 'text/xml':
	                        var xml = new XMLSerializer();
	                        s = xml.serializeToString( dom );
	                        break;
	                    
	                    default:
	                        YAHOO.log( 'Unrecognized XML type to convert to string', 'error' );
	                        break;
	                }
                }
                catch( e )
                {
                    YAHOO.log( e, 'error' );
                    s = null;
                }
            }
            
            return s;
        },
        
        /**
         * Returns the next child 
         * @param XMLElement start
         * @param Array with element type strings as described in the Denbel.util.XmlHelper.nodeTypeToString Array
         * @return XMLElement
         */
        getNextChildElementType: function( start, type )
        {
            if( !start || !type || !YAHOO.lang.isArray( type ) )
            {
                return null;
            }
            
            var children = start.childNodes;
            var el = null;
            
            if( !children )
            {
                return null;
            }
            
            for( var i = 0; i < children.length; i++ )
            {
                if( Denbel.util.inArray( Denbel.util.XmlHelper.nodeTypeToString[children[i].nodeType], type ) )
                {
                    el = children[i];
                    break;
                }
            }
            
            return el;
        },
        
        /**
         * Returns the next child XMLElement of the given XMLElement
         * @param XMLElement start
         * @return XMLElement
         */
        getNextChildElement: function( start )
        {
            return Denbel.util.XmlHelper.getNextChildElementType( start, new Array( 'element' ) );
        },
        
        /**
         * Returns the next child element of the given start element by tag name
         * @param XMLElement start
         * @param string tagName
         * @return XMLElement
         */
        getNextChildElementByTagName: function( start, tagName )
        {
            if( !start || !tagName )
            {
                return null;
            }
            
            var node = null;
            
            for( var i = 0; i < start.childNodes.length; i++ )
            {
                if( start.childNodes[i].tagName == tagName )
                {
                    node = start.childNodes[i];
                    break;
                }
            }
            
            return node;
        },
        
        /**
         * Returns the textual value of the given element if any.
         * This is an alias of the getNextChildTextValue function.
         * @param XMLElement element
         * @return string
         */
        getElementValue: function( element )
        {
            var node = Denbel.util.XmlHelper.getNextChildElementType( element, new Array( 'text', 'cdata' ) );
            
            if( node )
            {
                return node.nodeValue;
            }
            
            return '';
        },
        
        /**
         * Returns the next child TextNode or CDATASection of the given XMLElement
         * @deprecated
         * @param XMLElement start
         * @return string
         */
        getNextChildTextValue: function( start )
        {
            YAHOO.log( 'Using deprecated function getNextChildTextValue', 'warn', 'Denbel.util.XmlHelper' );
            return Denbel.util.XmlHelper.getElementValue( start );
        }
    };
} )();
 