package daruma.wfs;

import daruma.xml.handler.MispDefaultHandler;
import daruma.xml.util.ErrorDocumentBuilder;
import daruma.xml.util.FatalErrorDocument;
import daruma.xml.util.XMLFormatConverter;
import daruma.xml.util.ElementUtil;
import daruma.xml.Lexicon;
import daruma.xml.NameSpace;

import daruma.storage_manager.type_definition.ElementName;
import daruma.xml.URI;
import daruma.util.LogWriter;

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

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

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

import javax.xml.transform.TransformerException;
import javax.xml.parsers.ParserConfigurationException;

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

import daruma.util.PropertyReader;
import daruma.util.Itk;

import daruma.global_switch.ImplementationSwitches;

public class GetCapabilitiesHandler extends MispDefaultHandler
{
	private	StorageManager	storage;

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

		this.storage = storage;
	}


	public  void  xEndDocument() throws SAXException
	{
		List<ElementName>	featureTypeNameList;

		PrintWriter	out = super.getPrintWriter();

		try
		{
			featureTypeNameList = storage.getElementList();
		}
		catch( StorageException  e )
		{
			try
			{
				XMLFormatConverter.print
					( ErrorDocumentBuilder.create
					  ( "error: " + e.getMessage() ,
					    super.getLocator() ) ,
					  super.getOutputStream() );
			}
			catch( ParserConfigurationException  pe )
			{
				pe.printStackTrace();

				out.print( new FatalErrorDocument
						( pe.getMessage() ,
						  super.getLocator() )
					   .getString() );
			}
			catch( TransformerException  te )
			{
				te.printStackTrace();

				out.print( new FatalErrorDocument
						( te.getMessage() ,
						  super.getLocator() )
					   .getString() );
			}

			out.flush();

			return;
		}

		boolean readOnly = (! PropertyReader.getProperty
				      ( "daruma.run_mode" , "normal")
				      .equals( "normal" ));

		/* <<< [06/08/20 00:39 I.Noda] <<< 
		 * constructResponseInfo が完成すれば、
		 * 後半部分 (=== 以下)は省略すべし。
		 */
		constructResponseInfo(featureTypeNameList, readOnly) ;
		/* === [06/08/20 00:39 I.Noda] === */
		/* !!! [06/08/20 22:50 I.Noda] !!! 
		 * DOM による Response 出力への切り替えへの布石。
		 */
		if(! Itk.useDOMResponse) {

		    out.println( "<GetCapabilitiesResponse"
				 + " xmlns=\"" + URI.MISP + "\">" );
		    out.println( "" );
		    out.println( "  <WFS_Capabilities>" );
		    out.println( "" );
		    out.println( "    <Capabilities>" );
		    out.println( "      <GetCapabilities/>" );
		    out.println( "      <DescribeFeatureType/>" );

		    if ( ! readOnly )
		    {
			out.println( "      <Transaction/>" );
		    }

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

		    if ( ! readOnly )
		    {
			out.println( "      <RegisterFeatureType/>" );

			if ( ImplementationSwitches.instance()
			     .getEnableGeometryConversion() )
			{
			    out.println( "      <RegisterCoordinateSystemTransformation/>" );
			}
		    }

		    out.println( "    </Capabilities>" );
		    out.println( "" );
		    out.println( "    <FeatureTypeList>" );
		    out.println( "      <Operations>" );

		    if ( ! readOnly )
		    {
			out.println( "        <Insert/>" );
			out.println( "        <Update/>" );
			out.println( "        <Delete/>" );
		    }
		    out.println( "        <Query/>" );
		    out.println( "      </Operations>" );
		    out.println( "" );

		    for ( ElementName  e : featureTypeNameList )
		    {
			out.println( "      <FeatureType>" );

			out.println( "        "
				     + "<Name xmlns:ns=\"" + e.getNamespace()
				     + "\">"
				     + "ns:" + e.getLocalName()
				     + "</Name>" );

			out.println( "      </FeatureType>" );
		    }
		    out.println( "    </FeatureTypeList>" );
		    out.println( "" );
		    out.println( "  </WFS_Capabilities>" );
		    out.println( "" );
		    out.println( "</GetCapabilitiesResponse>" );
		    out.flush();
		}
		/* >>> [06/08/20 00:39 I.Noda] >>> */
	}
    //------------------------------------------------------------
    /* !!! [06/08/20 00:39 I.Noda] !!! 
     * construct ResponseInfo
     */
    private void constructResponseInfo(List<ElementName> featureTypeNameList ,
				       boolean readOnly)
	throws SAXException
    {
	try {
	    ResponseInfo responseInfo = this.getResponse() ;
	    Document doc = responseInfo.document ;
	    Element response = 
		ElementUtil.genElementSimple
		(Lexicon.MispGetCapabilitiesResponse,
		 null, doc, responseInfo.leaf, true) ;
	    responseInfo.setResponseToLeaf(response) ;

	    Date ctime = this.storage.getCurrentTime(); 
	    Date btime= ctime ;
	    Date etime = btime ;

	    responseInfo.addResponseStatusToLeaf
		(this.storage.getMostRecentTransactionURI(),
		 btime, etime) ;

	    Element wfsCapabilities = 
		ElementUtil.genElementSimple(Lexicon.MispWfsCapabilities, 
					     null,
					     doc, response, true) ;
	    Element capabilities = 
		ElementUtil.genElementSimple(Lexicon.MispCapabilities, null,
					     doc, wfsCapabilities, true) ;

	    ElementUtil.genElementSimple(Lexicon.MispGetCapabilities,null,
					 doc, capabilities, true) ;
	    ElementUtil.genElementSimple(Lexicon.MispDescribeFeatureType, 
					 null,
					 doc, capabilities, true) ;
	    if ( ! readOnly )
	    {
		ElementUtil.genElementSimple(Lexicon.MispTransaction, null,
					     doc, capabilities, true) ;
	    }
	    ElementUtil.genElementSimple(Lexicon.MispGetFeature, null,
					 doc, capabilities, true) ;
	    if ( ! readOnly )
	    {
		ElementUtil.genElementSimple(Lexicon.MispRegisterFeatureType, 
					     null,
					     doc, capabilities, true) ;
		if ( ImplementationSwitches.instance()
		     .getEnableGeometryConversion() )
		{
		    ElementUtil.genElementSimple(Lexicon.MispRegisterCoordinateSystemTransformation, 
						 null,
						 doc, capabilities, true) ;
		}
	    }

	    if ( ImplementationSwitches.instance()
		 .getEnableGeometryConversion() )
	    {
		ElementUtil.genElementSimple
			    ( Lexicon.MispGetCoordinateSystemTransformation, 
			      null, doc, capabilities, true);
	    }


	    Element featureTypeList = 
		ElementUtil.genElementSimple(Lexicon.MispFeatureTypeList, 
					     null,
					     doc, wfsCapabilities, true) ;
	    Element operations = 
		ElementUtil.genElementSimple(Lexicon.MispOperations, null,
					     doc, featureTypeList, true) ;

	    if ( ! readOnly )
	    {
		ElementUtil.genElementSimple(Lexicon.MispInsert, null,
					     doc, operations, true) ;
		ElementUtil.genElementSimple(Lexicon.MispUpdate, null,
					     doc, operations, true) ;
		ElementUtil.genElementSimple(Lexicon.MispDelete, null,
					     doc, operations, true) ;
		ElementUtil.genElementSimple(Lexicon.MispQuery, null,
					     doc, operations, true) ;
	    }	
	    for ( ElementName  element : featureTypeNameList ) {
		String prefix = "ns" ;
		String nsURI = element.getNamespace() ;
		String localname = element.getLocalName() ;
		String qname = NameSpace.genQName(prefix, localname) ;

		Element featureType = 
		    ElementUtil.genElementSimple(Lexicon.MispFeatureType, 
						 null,
						 doc, featureTypeList, true) ;
		Element name =
		    ElementUtil.genElementSimple(Lexicon.MispName, qname,
						 doc, featureType, true) ;
		NameSpace.addNsDeclToIfNeeded(name, prefix, nsURI) ;

		// Element transactionID =
		    ElementUtil.genElementSimple
		    (Lexicon.MispMostRecentTransactionID,
		     this.storage.getMostRecentTransactionURIFor(nsURI,
								localname),
		     doc, featureType, true) ;
	    }
	} catch( StorageException  ex ) {
	    ex.printStackTrace() ;
	    throw new SAXException(ex) ;
	}
    }
}
