package daruma.wfs.filter;

import daruma.wfs.GetFeatureHandler;
import daruma.wfs.filter.PredicateDescription;
import daruma.wfs.filter.FilterParser;

import daruma.xml.SAXExceptionObserver;
import daruma.xml.handler.XSAXDOMCreateHandler;
import daruma.xml.util.XMLParseErrorException;

import daruma.storage_manager.StorageManager;
import daruma.storage_manager.type_definition.TypeDefinition;
import daruma.storage_manager.type_definition.ElementName;
import daruma.storage_manager.type_definition.TypeName;

import daruma.geometry.TransformationContext;

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

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

import java.io.OutputStream;

public class FilterHandler extends XSAXDOMCreateHandler
{
    private	ElementName		elementName;
    private	TypeDefinition		type;
    private	TransformationContext	trans;
    private	StorageManager		storage;
    private	SAXExceptionObserver	errorReceiver;

    private	PredicateDescription	predicate;

    public	FilterHandler( OutputStream  out ,
			       XMLReader  parser ,
			       boolean  isTopLevelHandler ,
			       ElementName  elementName ,
			       TypeDefinition  type ,
			       TransformationContext  trans ,
			       StorageManager  storage ,
			       SAXExceptionObserver  errorReceiver )
    {
	super( out , parser , isTopLevelHandler );

	this.elementName   = elementName;
	this.type          = type;
	this.trans         = trans;
	this.storage       = storage;
	this.errorReceiver = errorReceiver;
	this.predicate     = null;
    }

    /* !!! [06/10/16 15:34 I.Noda] !!! */
    //------------------------------------------------------------
    /**
     * DOM を作成するためのインターフェース。
     * handler が delegate されるとちゃんとした DOM を構成できない
     * 問題を回避するためのメソッド。
     * 本来なら XSAXDOMCreateHanlder あたりで解決されるべき。
     */
    public void xStartElement( String uri ,
			       String localName ,
			       String qName ,
			       Attributes  attrs ) throws SAXException
    {
	if(this.getCurrentNode() != null) {
	    /* !!! [06/10/16 15:34 I.Noda] !!! 
	     * parent handler (GetFeature) 用の DOM を作成するために 
	     * そのためのwrapper を呼ぶ。
	     * ただし、初回（このタグのトップレベルが作成された場合）は
	     * すでに親に登録されているのでスキップする。
	     * そのために、null と比較している。
	     * 非常に darty hack なので、うまい解決方法が必要だが、
	     * 現状の XSAX では無理。
	     */
	    /* !!! [06/10/18 11:02 I.Noda] !!! 
	     * quick hack
	     */
	    //((GetFeatureHandler)(this.getParentHandler()))
	    //	.xStartElementWrapper(uri,localName,qName,attrs);
	}

	/* !!! [06/10/16 15:34 I.Noda] !!! 
	 * 自分自身の DOM を作成するために super を呼ぶ。
	 */
	super.xStartElement(uri,localName,qName,attrs);

    }

    /* !!! [06/10/16 15:34 I.Noda] !!! */
    //------------------------------------------------------------
    /**
     * DOM を作成するためのインターフェース。
     * handler が delegate されるとちゃんとした DOM を構成できない
     * 問題を回避するためのメソッド。
     * 本来なら XSAXDOMCreateHanlder あたりで解決されるべき。
     */
    public void  xCharacters( char[]  str , int  offset ,  int  length )
	throws SAXException
    {
	/* !!! [06/10/16 15:34 I.Noda] !!! 
	 * parent handler (GetFeature) 用の DOM を作成するために 
	 * そのためのwrapper を呼ぶ。
	 */
	/* !!! [06/10/18 11:02 I.Noda] !!! 
	 * quick hack
	 */
	//((GetFeatureHandler)(this.getParentHandler()))
	//    .xCharacters(str,offset,length);
	//((XSAXDOMCreateHandler)(this.getParentHandler()))
	//    .xCharacters(str,offset,length);
	/* !!! [06/10/16 15:34 I.Noda] !!! 
	 * 自分自身の DOM を作成するために super を呼ぶ。
	 */
	super.xCharacters(str,offset,length);
    }

    //------------------------------------------------------------
    public PredicateDescription getPredicate()
    {
	return( this.predicate );
    }

    public String getSQLExpression()
    {
	if ( this.predicate == null )
	{
	    return( null );
	}

	return( this.predicate.getSQLExpression() );
    }

    public void xEndDocument() throws SAXException
    {
	Element	filterElement = super.getDocumentElement();

	try
	{
		this.predicate = FilterParser.parseFilter
					      ( filterElement ,
						new TypeName( this.elementName ),
						this.type ,
						this.trans ,
						this.storage ,
						this.getPrefixMap() );
	}
	catch( XMLParseErrorException e )
	{
		SAXParseException	se = new SAXParseException
						 ( e.getMessage() ,
						   super.getLocator(), e );
		/* !!! [06/10/16 15:34 I.Noda] !!! 
		 * 何故か不明だが、SAXParseException では、
		 * あたえられた Exception のスタックトレースを
		 * コピーしてくれない。
		 * そこで、手動でコピー。
		 */
		se.setStackTrace(e.getStackTrace());

		this.errorReceiver.notifyError( se );

		throw se;
	}
    }
    
    //--------------------------------------------------
    /**
     * 精密な条件チェック (2pass 目)
     */
    public boolean detailedCheck(Node feature) 
    	throws XMLParseErrorException
    {
	return this.predicate.detailedCheck(feature);
    }
}
