package daruma.storage_manager;

import daruma.util.LogWriter;

import daruma.storage_manager.StorageException;
import daruma.storage_manager.BulkInsertBuffer;
import daruma.storage_manager.ElementInfo;
import daruma.storage_manager.type_definition.ElementName;
import daruma.storage_manager.type_definition.TypeName;
import daruma.storage_manager.type_definition.TypeDefinition;
import daruma.storage_manager.type_definition.TypedInstance;
import daruma.storage_manager.type_definition.TypedInstanceSet;
import daruma.storage_manager.type_definition.ColumnNameFactory;

import daruma.storage_manager.schema.XMLSchemaSet;

import daruma.auth.PermissionManager;
import daruma.auth.PermissionType;
import daruma.auth.PermissionDirective;


// XXX: PredicateDescription should be moved to other package?
import daruma.wfs.filter.PredicateDescription;

import daruma.geometry.CoordinateSystem;
import daruma.geometry.CoordinateSystemTransformation;
import daruma.geometry.CoordinateSystemTransformationDictionary;
import daruma.geometry.TransformationContext;
import daruma.geometry.DrmEnvelope;

import daruma.xml.UniversalName;
import daruma.xml.SimpleXPath;
import daruma.xml.util.PrefixMap;
import daruma.util.Pair;

import org.w3c.dom.Element;

import java.util.Date;

import java.util.List;
import java.util.Map;

public abstract class StorageManager
{
    /* !!! [06/08/16 03:26 I.Noda] !!! 
     * Separator 定義は ColumnNameFactory に集約
     */
    //private	static	final	String	SHORT_XPATH_SEPARATOR = "/";
    public static final String	SHORT_XPATH_SEPARATOR = 
	ColumnNameFactory.ColNameSep ;

	//
	//  set read only mode
	//
	public abstract void setReadOnly( boolean readOnly )
	    throws StorageException;

	//
	//  reset
	//
	public abstract void reset() throws StorageException;


	//
	// transaction
	//
	public abstract void	startTransaction() throws StorageException;
	public abstract void	commit() throws StorageException;
	public abstract void	rollback() throws StorageException;
		    

	//
	// schema
	//
	public abstract void		registerSchema
					  ( Element  schema ,
					    PrefixMap  prefixMap )
						throws StorageException;
	/* <<< [06/09/07 16:53 I.Noda] <<< 
	 * スキーマの取得は、単なるスキーマ文字列ではなく、
	 * DOM Element などの解釈を行ったものを返す。
	 * また、関係する(同じ名前空間をターゲットとするものおよび
	 * import される) スキーマも同時に検索し返す。
	 */
	//public abstract List<String>	getSchemasOfElement
	//				( ElementName  elementName )
	//					throws StorageException;
	//public abstract List<String> getSchemasByNS(String namespaceURI)
	//    throws StorageException ;
	/* === [06/09/07 16:53 I.Noda] === */
	public abstract XMLSchemaSet	getSchemasOfElement
					( ElementName  elementName )
	    throws StorageException;
	public abstract XMLSchemaSet	getSchemasOfElement
					( ElementName  elementName,
					  XMLSchemaSet schemaSet )
	    throws StorageException;

	public abstract XMLSchemaSet getSchemasByNS(String namespaceURI)
	    throws StorageException ;


	public abstract XMLSchemaSet getSchemasByNS(String namespaceURI,
						    XMLSchemaSet schemaSet)
	    throws StorageException ;
	/* >>> [06/09/07 16:53 I.Noda] >>> */
    
	//
	// type
	//
	public abstract void		registerTypeDefinition
					  ( TypeName  typeName ,
					    TypeDefinition  definition ,
					    String  schemaID ,
					    long  internalSchemaID ,
					    boolean  cacheUpdateOnly )
						throws StorageException;

	public abstract TypeDefinition	getTypeDefinition( TypeName  typeName )
						throws StorageException;



	//
	// element
	//
	public abstract void		registerElementDefinition
					  ( ElementName  elementName ,
					    TypeName  typeName ,
					    ElementInfo  elementInfo ,
					    long  internalSchemaID ,
					    boolean  cacheUpdateOnly )
						throws StorageException;
	public abstract TypeName	getElementTypeName
					  ( ElementName  elementName )
						throws StorageException;
	public abstract ElementInfo	getElementInfo
					  ( ElementName  elementName )
						throws StorageException;

	public abstract	List<ElementName>	getElementList()
						throws StorageException;

	public abstract	int	insertElement( ElementName  elementName ,
					       TypedInstance  obj,
					       long transactionSN)
						      throws StorageException;
	public abstract	void	bulkInsertElement( BulkInsertBuffer buf,
						   long transactionSN)
						      throws StorageException;

	public abstract	TypedInstanceSet	getTypedInstanceSet
						 ( ElementName elementName ,
						   /* Query */
						   String sqlWhereBlock,
						   String sqlSortBlock,
						   TransformationContext trans,
						   long offsetCount,
						   long limitCount)
						      throws StorageException;

	/* !!! [06/08/22 18:56 I.Noda] !!! */
	public abstract	long	getCountOfTypedInstanceSet
						  ( ElementName  elementName ,
						    /* Query */
						    String  sqlWhereBlock,
						    long limitCount)
						      throws StorageException;
	/* !!! [06/08/22 18:56 I.Noda] !!! */
	public abstract DrmEnvelope 
	    getEnvelopeOfTypedInstanceSet(ElementName elementName,
					  String propertyColName,
					  String sqlWhereBlock,
					  long limitCount)
	    throws StorageException;

	public abstract	int	deleteElement
				    ( ElementName  elementName ,
				      PredicateDescription  predicate ,
				      long transactionSN,
				      boolean  virtualDelete )
						      throws StorageException;

	public	abstract int	restoreElement
				    ( ElementName  elementName ,
				      PredicateDescription  predicate,
				      long transactionSN)
						      throws StorageException;

	public	abstract int	updateElement
				    ( ElementName  elementName ,
				      List< Pair<SimpleXPath,
						 TypedInstance> > updateValues ,
				      PredicateDescription  predicate ,
				      long transactionSN,
				      boolean  virtualUpdate )
						      throws StorageException;

	// XXX
	public abstract List<String>	getSubTableValues( String  tableName ,
							   long  parentID )
						      throws StorageException;

	//
	// universal name
	//
	public abstract	void	registerUniversalNameIfNotRegistrated
					  ( UniversalName  universalName )
						      throws StorageException;
	public abstract	String	getUniversalNameID( UniversalName  name )
						      throws StorageException;


	//
	// time
	//
	public	abstract Date	getCurrentTime() throws StorageException;

    /* !!! [06/08/17 17:28 I.Noda] !!! */
    // 
    // Transaction ID
    //
    public abstract long registerTransactionURI(String uri) 
	throws StorageException ;

    public abstract long getTransactionSerialNumber(String uri)
	throws StorageException ;

    public abstract String getMostRecentTransactionURI()
	throws StorageException ;

    /* !!! [06/08/22 02:35 I.Noda] !!! */
    public abstract String getMostRecentTransactionURIFor(String nsURI,
							  String localname)
	throws StorageException ;
    public abstract String getMostRecentTransactionURIFor(UniversalName uname)
	throws StorageException ;

	//
	// utility
	//
    /* !!! [06/08/16 03:26 I.Noda] !!! 
     * この XPath はあくまで db 用の名前なので、
     * それが明示されるメソッド名に変更
     */
    //public	String	getShortXPathString( SimpleXPath  path )
	public	String	getShortXPathStringForDB( SimpleXPath  path )
						     throws StorageException
	{
		StringBuilder	buf = new StringBuilder();

		for ( UniversalName  name  :  path.getList() )
		{
			try
			{
				if ( buf.length() != 0 )
				{
					buf.append
					    ( this.SHORT_XPATH_SEPARATOR );
				}

				String	id = this.getUniversalNameID( name );

				if ( id == null )
				{
					throw new StorageException
						( "Can't convert path ["
						  + path.toString() + "]" );
				}

				buf.append( id );
			}
			catch( StorageException  e )
			{
				throw e;
			}
		}

		if ( path.isAttribute() )
		{
			try
			{
				if ( buf.length() != 0 )
				{
					buf.append
					    ( this.SHORT_XPATH_SEPARATOR );
				}

				buf.append( ColumnNameFactory
					    .ColNameAttributePrefix );

				String	id = this.getUniversalNameID
						  ( path.getAttributeName() );

				if ( id == null )
				{
					throw new StorageException
						( "Can't convert path ["
						  + path.toString() + "]" );
				}

				buf.append( id );
			}
			catch( StorageException  e )
			{
				throw e;
			}
		}

		return( buf.toString() );
	}

	public	TypeDefinition	getElementTypeDefinition
					  ( ElementName  elementName )
						throws StorageException
	{
		TypeName	typeName;

		try
		{
			typeName = this.getElementTypeName( elementName );
		}
		catch( StorageException e )
		{
			throw new StorageException( "type of element \""
						   + elementName.getLocalName()
						   + "\" in namespace \""
						   + elementName.getNamespace()
						   + "\" not found" , e );
		}

		try
		{
			return( this.getTypeDefinition( typeName ) );
		}
		catch( StorageException e )
		{
			throw new StorageException
				( "type definition of type \""
				  + typeName.getLocalName()
				  + "\" in namespace \""
				  + typeName.getNamespace()
				  + "\" not found" , e );
		}
	}


	//
	// coordinate translation
	//
	public abstract void registerCoordinateSystemTransformation
				( CoordinateSystemTransformation trans )
	    throws StorageException;

	public abstract CoordinateSystemTransformationDictionary
				getCoordTransDictionary()
	    throws StorageException;


	//
	// auth
	//
	public abstract PermissionManager restorePermissionManager( PermissionType defaultPermission )
	    throws StorageException;

	public abstract void addPermissionRule( PermissionDirective directive )
	    throws StorageException;
}
