package daruma.wfs;

import daruma.xml.handler.MispDefaultHandler;
import daruma.xml.handler.XSAXDOMCreateHandler;
import daruma.xml.Lexicon;
import daruma.xml.URI;
import daruma.xml.util.ElementUtil;
import daruma.xml.XMLTag;

import daruma.util.ISO8601DateFormat;
import daruma.util.Itk;
import daruma.util.LogWriter;

import daruma.wfs.ResponseInfo;

import daruma.storage_manager.StorageManager;
import daruma.storage_manager.StorageException;

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

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

import java.io.PrintWriter;
import java.io.OutputStream;
import java.util.Date;


public class  RegisterFeatureTypeHandler extends MispDefaultHandler
{
	//
	// local class XMLSchemaRegistrationHandler
	//
	//   This class reads XML Schema, and register it to storage.
	//
	//   implementation:
	//     This class inherits XSAXDOMCreateHandler it converts SAX to DOM.
	//     In xEndDocument(), this class gets DOM document from super class
	//     and passes to processDocument().
	//
	private  static class  XMLSchemaRegistrationHandler
						 extends XSAXDOMCreateHandler
	{
		private	StorageManager			storage;
		private	RegisterFeatureTypeHandler	parent;

		public	XMLSchemaRegistrationHandler
				( OutputStream  out ,
				  XMLReader  parser ,
				  boolean  isTopLevelHandler ,
				  StorageManager  storage ,
				  RegisterFeatureTypeHandler  parent )
		{
			super( out , parser , isTopLevelHandler );
			super.setInhibitEndPrefixBeforeEndDocument( true );

			this.storage = storage;
			this.parent  = parent;
		}

		public  void  xEndDocument() throws SAXException
		{
			try
			{
				this.storage.registerSchema
					( super.getDocumentElement() ,
					  super.getPrefixMap() );
			}
			catch( StorageException  e )
			{
				LogWriter.qwrite("DEBUG",  "errorMessage=[",
						 e.getMessage(), "]" );

				this.parent.setError( e.getMessage() );
			}
		}
	}



	//
	// main class RegisterFeatureTypeHandler
	//
	private	StorageManager	storage;

	private	boolean		errorOccured;
	// XXX: List<String>	errorMessages;
	private	String		errorMessage;

	private	Date		startTime;
	private	Date		endTime;


	public	RegisterFeatureTypeHandler
				( OutputStream  out ,
				  XMLReader  parser ,
				  boolean  isTopLevelHandler ,
				  StorageManager  storage )
	{
		super( out , parser , isTopLevelHandler );

		this.storage = storage;
		this.errorOccured = false;
		this.errorMessage = null;
		this.startTime = null;
		this.endTime = null;
	}

	private	void	setError( String  errorMessage )
	{
		this.errorOccured = true;
		this.errorMessage = errorMessage;
	}

	public	void	xStartElement( String uri ,
				       String localName ,
				       String qName ,
				       Attributes  attrs ) throws SAXException
	{
		assert super.getCurrentLevel() == 1
			|| super.getCurrentLevel() == 2;

		XMLTag	t = new XMLTag( uri , localName );

		if ( super.getCurrentLevel() == 1 )
		{
			if ( ! t.equals
			       ( new XMLTag( URI.MISP ,
					     "RegisterFeatureType" ) ) )
			{
				SAXParseException
					e = new SAXParseException
						( "unknown top level tag \""
						  + t.getLocalName()
						  + "\"." ,
						  super.getLocator() );

				this.throwError( e );
			}

			try
			{
				this.storage.startTransaction();
				this.startTime = this.storage.getCurrentTime();
			}
			catch( StorageException  e )
			{
				this.throwError( new SAXParseException
						 ( e.getMessage() ,
						   super.getLocator() ) );
			}

			return;
		}


		//
		// XXX: check errorOccured here,
		//      previous schema might cause error
		//
		if ( t.getLocalName().equals( "schema" ) )
		{
			if ( ! t.getURI().equals( URI.XML_SCHEMA ) )
			{
				this.throwError
				 ( new SAXParseException
				   ( "top level \"" + t.getLocalName() + "\" "
				     + "should be in namespace "
				     + URI.XML_SCHEMA ,
				     super.getLocator() ) );
			}


			//
			// class XMLSchemaRegistrationHandler is defined
			// at top of this file.
			//
			super.setContentHandlerDelegator
				( new XMLSchemaRegistrationHandler
				  ( super.getOutputStream() ,
				    super.getParser() ,
				    false ,
				    this.storage ,
				    this ) ,
				  uri , localName , qName , attrs );

			return;
		}
		else
		{
			SAXParseException
				e = new SAXParseException
					( "unknown second level tag \""
					  + t.getLocalName() + "\"." ,
					  super.getLocator() );

			this.throwError( e );
		}
	}

	public  void  xEndElement( String uri ,
				   String localName ,
				   String qName ) throws SAXException
	{
		try
		{
			this.storage.registerTransactionURI
					( Itk.genUriRandom() );

			this.storage.commit();

			super.setMostRecentTransactionURI
			      ( this.storage.getMostRecentTransactionURI() );

			this.endTime = this.storage.getCurrentTime();
		}
		catch( StorageException  e )
		{
			// XXX
			throw new SAXException( e );
		}


		/* !!! [06/08/20 22:50 I.Noda] !!! 
		 * DOM による Response 出力への切り替えへの布石。
		 */
		if(! Itk.useDOMResponse) {
		    this.printOutput();
		}
		
		this.constructResponseInfo() ;
	}

	private void printOutput()
	{
		PrintWriter	out = super.getPrintWriter();

		String	status;

		if ( this.errorOccured )
		{
			status = "FAILURE";
		}
		else
		{
			status = "SUCCESS";
		}


		out.println( "<RegisterFeatureTypeResponse"
			     + " xmlns=\"" + URI.MISP + "\">" );

		out.println( "  <ElapsedTime xmlns:gml=\"" + URI.GML + "\">" );

		if ( this.startTime == null )
		{
			out.println( "    "
				     + "<gml:beginPosition "
				     + " indeterminatePositon=\"unknown\"/>" );
		}
		else
		{
			out.println( "    <gml:beginPosition>"
				     + new ISO8601DateFormat()
						.format(this.startTime)
				     + "</gml:beginPosition>" );
		}

		if ( this.endTime == null )
		{
			out.println( "    "
				     + "<gml:endPosition"
				     + " indeterminatePositon=\"unknown\"/>" );
		}
		else
		{
			out.println( "    <gml:endPosition>"
				     + new ISO8601DateFormat()
				     .format(this.endTime)
				     + "</gml:endPosition>" );
		}

		out.println( "  </ElapsedTime>" );

		out.println( "  <Status>" + status + "</Status>" );

		if ( this.errorMessage != null )
		{
			out.println( "  <Error>" );
			out.println( "    <Message>" + this.errorMessage
				       + "</Message>" );
			out.println( "  </Error>" );
		}

		out.println( "</RegisterFeatureTypeResponse>" );
		out.flush();
		
	}

    //------------------------------------------------------------
    /* !!! [06/08/19 03:27 I.Noda] !!! 
     * construct ResponseInfo
     */
    private void constructResponseInfo() {
	ResponseInfo responseInfo = this.getResponse() ;
	Element response = 
	    ElementUtil.genElementSimple
	    (Lexicon.MispRegisterFeatureTypeResponse,
	     null, responseInfo.document, responseInfo.leaf, true) ;
	responseInfo.setResponseToLeaf(response) ;

	responseInfo.addResponseStatusToLeaf
	    (this.getMostRecentTransactionURI(),
	     this.startTime, this.endTime) ;

	// Element status =
	    ElementUtil.genElementSimple
	    (Lexicon.MispStatus,
	     (this.errorOccured ?
	      Lexicon.MispStatus_Failure.localname :
	      Lexicon.MispStatus_Success.localname),
	     responseInfo.document, response, true) ;

	if(this.errorMessage != null) {
	    Element error =
		ElementUtil.genElementSimple
		(Lexicon.MispError, null,
		 responseInfo.document, response, true) ;
	    // Element message =
		ElementUtil.genElementSimple
		(Lexicon.MispErrorMessage, this.errorMessage,
		 responseInfo.document, error, true) ;
	}
    }
     

    //------------------------------------------------------------
	private	void	throwError( SAXParseException  e ) throws SAXException
	{
		this.setError( e.getMessage() );

		this.printOutput();

		throw e;
	}
}
