package org.codehaus.xfire.util.jdom;

import java.util.Iterator;
import java.util.List;

import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;

import org.jdom.Attribute;
import org.jdom.CDATA;
import org.jdom.Comment;
import org.jdom.Content;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.EntityRef;
import org.jdom.Namespace;
import org.jdom.Text;

public class StaxSerializer
{
    public void writeDocument(Document doc, XMLStreamWriter writer)
        throws XMLStreamException
    {
        writer.writeStartDocument("1.0");        

        for (Iterator itr = doc.getContent().iterator(); itr.hasNext();)
        {
            Content content = (Content) itr.next();
            
            if (content instanceof Element)
                writeElement((Element) content, writer);
        }
        
        writer.writeEndDocument();
    }

    public void writeElement(Element e, XMLStreamWriter writer)
        throws XMLStreamException
    {
        // need to check if the namespace is declared before we write the
        // start element because that will put the namespace in the context.
        String elPrefix = e.getNamespacePrefix();
        String elUri = e.getNamespaceURI();

        String boundPrefix = writer.getPrefix(elUri);
        boolean writeElementNS = false;
        if ( boundPrefix == null || !elPrefix.equals(boundPrefix) )
        {   
            writeElementNS = true;
        }
        
        writer.writeStartElement(elPrefix, e.getName(), elUri);

        List namespaces = e.getAdditionalNamespaces();
        for (Iterator itr = namespaces.iterator(); itr.hasNext();)
        {
            Namespace ns = (Namespace) itr.next();

            String prefix = ns.getPrefix();
            String uri = ns.getURI();
            
            writer.writeNamespace(prefix, uri);
            
            if (elUri.equals(uri) && elPrefix.equals(prefix))
            {
                writeElementNS = false;
            }
        }

        if (writeElementNS)
        {
            if ( elPrefix == null || elPrefix.length() ==  0 )
            {
                writer.writeDefaultNamespace(elUri);
            }
            else
            {
                writer.writeNamespace(elPrefix, elUri);
            }
        }
        
        for (Iterator itr = e.getAttributes().iterator(); itr.hasNext();)
        {
            Attribute attr = (Attribute) itr.next();
            String attPrefix= attr.getNamespacePrefix();
            String attUri = attr.getNamespaceURI();
            
            if (attUri == null)
            {
                writer.writeAttribute(attr.getName(), attr.getValue());
            }
            else
            {
                writer.writeAttribute(attPrefix, attUri, attr.getName(), attr.getValue());
                
                if (!isDeclared(writer, attPrefix, attUri))
                {
                    writer.writeNamespace(attPrefix, attUri);
                }
            }
        }

        for (Iterator itr = e.getContent().iterator(); itr.hasNext();)
        {
            Content n = (Content) itr.next();
            if (n instanceof Text)
            {
                writer.writeCharacters(((Text) n).getText());
            }
            else if (n instanceof Element)
            {
                writeElement((Element) n, writer);
            }
            else if (n instanceof Comment)
            {
                writer.writeComment(n.getValue());
            }
            else if (n instanceof CDATA)
            {
                writer.writeCData(n.getValue());
            }
            else if (n instanceof EntityRef)
            {
                EntityRef ref = (EntityRef) n;
                //writer.writeEntityRef(ref.)
            }
        }

        writer.writeEndElement();
    }

    /**
     * @param writer
     * @param prefix
     * @param uri
     * @throws XMLStreamException
     */
    private boolean isDeclared(XMLStreamWriter writer, String prefix, String uri)
        throws XMLStreamException
    {
        String decPrefix = writer.getPrefix(uri);
        return (decPrefix != null && decPrefix.equals(prefix));
    }
}

@@ -36,145 +36,8 @@
 m;%0A%0A
-import java.util.Iterator;%0Aimport java.util.List;%0A%0Aimport javax.xml.stream.XMLStreamException;%0Aimport javax.xml.stream.XMLStreamWriter;%0A%0A
 impo
@@ -59,16 +59,16 @@
 ribute;%0A
+
 import o
@@ -260,16 +260,152 @@
 .Text;%0A%0A
+import javax.xml.stream.XMLStreamException;%0Aimport javax.xml.stream.XMLStreamWriter;%0Aimport java.util.Iterator;%0Aimport java.util.List;%0A%0A
 public c
@@ -575,24 +575,16 @@
 (%221.0%22);
-        
 %0A%0A      
@@ -708,37 +708,25 @@
 itr.next();%0A
-            
 %0A
+
             
@@ -820,33 +820,25 @@
 ;%0A        %7D%0A
-        
 %0A
+
         writ
@@ -1388,19 +1388,16 @@
        %7B
-   
 %0A       
@@ -1430,33 +1430,25 @@
 ;%0A        %7D%0A
-        
 %0A
+
         writ
@@ -1762,37 +1762,25 @@
 s.getURI();%0A
-            
 %0A
+
             
@@ -1815,29 +1815,17 @@
 , uri);%0A
-            
 %0A
+
         
@@ -1961,310 +1961,8 @@
  %7D%0A%0A
-        if (writeElementNS)%0A        %7B%0A            if ( elPrefix == null %7C%7C elPrefix.length() ==  0 )%0A            %7B%0A                writer.writeDefaultNamespace(elUri);%0A            %7D%0A            else%0A            %7B%0A                writer.writeNamespace(elPrefix, elUri);%0A            %7D%0A        %7D%0A        %0A
     
@@ -2203,29 +2203,17 @@
 eURI();%0A
-            
 %0A
+
         
@@ -2462,25 +2462,9 @@
 ));%0A
-                
 %0A
+
     
@@ -2529,32 +2529,214 @@
               %7B%0A
+                    if( elUri.equals( attUri ) && elPrefix.equals( attPrefix ) )%0A                    %7B%0A                        if( writeElementNS )%0A                        %7B%0A        
                 
@@ -2761,16 +2761,17 @@
 mespace(
+ 
 attPrefi
@@ -2779,16 +2779,17 @@
 , attUri
+ 
 );%0A     
@@ -2791,33 +2791,564 @@
                 
-%7D
+            writeElementNS = false;%0A                        %7D%0A                    %7D%0A                    else%0A                    %7B%0A                        writer.writeNamespace( attPrefix, attUri );%0A                    %7D%0A                %7D%0A            %7D%0A        %7D%0A%0A        if (writeElementNS)%0A        %7B%0A            if ( elPrefix == null %7C%7C elPrefix.length() ==  0 )%0A            %7B%0A                writer.writeDefaultNamespace(elUri);%0A            %7D%0A            else%0A            %7B%0A                writer.writeNamespace(elPrefix, elUri);
 %0A            %7D%0A 

Handle situation where you have an element and namespaced attributes on that element and the namespace had not yet been declared