package daruma.xml.handler;

import daruma.xml.handler.MispDefaultHandler;
import daruma.xml.util.DOMDocumentFactory;
import daruma.xml.util.ElementUtil;
import daruma.xml.util.PrefixMap;
import daruma.xml.URI;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.Text;

import org.xml.sax.XMLReader;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;

import java.io.OutputStream;

public class XSAXDOMCreateHandler 
    extends MispDefaultHandler
    //    extends XSAXDefaultHandler
{
	private	Document	document = null;
	private	boolean		externalDocument = false;

	private	Element		topLevelElement = null;
	private	Node		currentNode = null;
	private	PrefixMap	temporalPrefixHolder = new PrefixMap();

	public	XSAXDOMCreateHandler( OutputStream  out ,  XMLReader  parser ,
				      boolean  isTopLevelHandler )
	{
		this( out , parser , isTopLevelHandler , (Document)null );
	}

	public	XSAXDOMCreateHandler( OutputStream  out ,  XMLReader  parser ,
				      boolean  isTopLevelHandler ,
				      Document  document )
	{
		super( out , parser , isTopLevelHandler );
		this.document = document;
		this.topLevelElement = null;
		this.currentNode = null;
	}

	public void reset()
	{
		this.document = null ;
		this.topLevelElement = null;
		this.currentNode = null ;
	}

	/**
	 * returns a DOM Document created by SAX handling.
	 *
	 * before parsing or error has occured, this method returns null
	 */
	public	Document getDOMDocument()
	{
		return( this.document );
	}

	public	Element	getDocumentElement()
	{
		return( this.topLevelElement );
	}

	public	Node	getCurrentNode() 
	{
		return( this.currentNode ) ;
	}

	//
	// SAX callbacks
	//
	protected  void  xStartDocument() throws SAXException
	{
		if ( this.document == null )
		{
			this.externalDocument = false;

			try
			{
			    this.document = DOMDocumentFactory.create();
			}
			catch( ParserConfigurationException e )
			{
				throw new SAXException( e );
			}
		}
		else
		{
			this.externalDocument = true;
		}
	}


	protected  void  xStartElement( String uri ,
					String localName ,
					String qName ,
					Attributes  attrs ) throws SAXException
	{
		Element	e = this.document.createElementNS( uri , qName );

		for ( int  i = 0  ;  i < attrs.getLength()  ;  ++ i )
		{
			e.setAttributeNS( attrs.getURI( i ) ,
					  attrs.getQName( i ) ,
					  attrs.getValue( i ) );
		}


		if ( this.currentNode == null )
		{
			ElementUtil.addPrefixMappingToElement
				    ( e , super.getPrefixMap() );

			this.topLevelElement = e;

			if ( ! this.externalDocument )
			{
			    this.document.appendChild( this.topLevelElement );
			}
		}
		else
		{
			this.currentNode.appendChild( e );
		}

		ElementUtil.addPrefixMappingToElement
				( e , this.temporalPrefixHolder );
		this.temporalPrefixHolder = new PrefixMap();

		this.currentNode = e;
	}


	protected  void  xEndElement( String uri ,
				      String localName ,
				      String qName ) throws SAXException
	{
		this.currentNode = this.currentNode.getParentNode();
	}


	public  void  xCharacters( char[]  str ,  int  offset ,  int  length )
							   throws SAXException
	{
		Text	text = this.document.createTextNode
				( new String( str , offset , length ) );

		assert this.currentNode != null;

		this.currentNode.appendChild( text );
	}

	protected  void  xIgnorableWhitespace( char[]  str ,
					       int  offset ,  int  length )
	{
		if ( this.currentNode == null )
		{
			return;
		}

		Text	text = this.document.createTextNode
				( new String( str , offset , length ) );

		this.currentNode.appendChild( text );
	}

	protected  void  xStartPrefixMapping( String  prefix ,  String  uri )
							throws SAXException
	{
		this.temporalPrefixHolder.put( prefix , uri );
	}
}
