package daruma.storage_manager;

import java.util.HashMap;
import java.util.Map;

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

import daruma.storage_manager.type_definition.types.IntegerTypeDefinition;
import daruma.storage_manager.type_definition.types.FloatTypeDefinition;
import daruma.storage_manager.type_definition.types.DoubleTypeDefinition;
import daruma.storage_manager.type_definition.types.BooleanTypeDefinition;
import daruma.storage_manager.type_definition.types.StringTypeDefinition;
import daruma.storage_manager.type_definition.types.DateTimeTypeDefinition;
import daruma.storage_manager.type_definition.types.GeometryPropertyTypeDefinition;
import daruma.storage_manager.type_definition.types.SequenceTypeDefinition;
import daruma.storage_manager.type_definition.types.AnyXMLTypeDefinition;

import daruma.util.LogWriter;

import daruma.xml.URI;


public class TypeDictionary
{
	private	Map<TypeName, TypeDefinition>	typeMap;

	public	TypeDictionary()
	{
		this.typeMap = new HashMap<TypeName, TypeDefinition>();

		this.registerBuiltinType();
	}

	private	void	registerBuiltinType()
	{
		this.registerType( new TypeName( URI.XML_SCHEMA ,
						 "string" ) ,
				   new StringTypeDefinition() );
		this.registerType( new TypeName( URI.XML_SCHEMA ,
						 "integer" ) ,
				   new IntegerTypeDefinition() );
		this.registerType( new TypeName( URI.XML_SCHEMA ,
						 "double" ) ,
				   new DoubleTypeDefinition() );
		this.registerType( new TypeName( URI.XML_SCHEMA ,
						 "float" ) ,
				   new FloatTypeDefinition() );
		this.registerType( new TypeName( URI.XML_SCHEMA ,
						 "decimal" ) ,
				   new FloatTypeDefinition() );
		this.registerType( new TypeName( URI.XML_SCHEMA ,
						 "boolean" ) ,
				   new BooleanTypeDefinition() );
		this.registerType( new TypeName( URI.XML_SCHEMA ,
						 "dateTime" ) ,
				   new DateTimeTypeDefinition() );

		this.registerType( new TypeName( URI.GML ,
						 "TimePositionType" ) ,
				   new DateTimeTypeDefinition() );

		this.registerType( new TypeName( URI.GML ,
						 "AbstractFeatureType" ) ,
				   new SequenceTypeDefinition() );

		this.registerType( new TypeName( URI.GML ,
						 "FeaturePropertyType" ) ,
				   new AnyXMLTypeDefinition() );

		this.registerType( new TypeName( URI.GML ,
						 "GeometryPropertyType" ) ,
				   new GeometryPropertyTypeDefinition() );
		// XXX: obsoleted, should be [GeometryPropertyType]
		this.registerType( new TypeName( URI.GML ,
						 "geometryPropertyType" ) ,
				   new GeometryPropertyTypeDefinition() );

		//
		// XXX: aliases, loosely checking
		//
		this.registerType( new TypeName( URI.XML_SCHEMA ,
						 "byte" ) ,
				   new IntegerTypeDefinition() );
		this.registerType( new TypeName( URI.XML_SCHEMA ,
						 "int" ) ,
				   new IntegerTypeDefinition() );
		this.registerType( new TypeName( URI.XML_SCHEMA ,
						 "short" ) ,
				   new IntegerTypeDefinition() );
		this.registerType( new TypeName( URI.XML_SCHEMA ,
						 "long" ) ,
				   new IntegerTypeDefinition() );

		this.registerType( new TypeName( URI.XML_SCHEMA ,
						 "negativeInteger" ) ,
				   new IntegerTypeDefinition() );
		this.registerType( new TypeName( URI.XML_SCHEMA ,
						 "positiveInteger" ) ,
				   new IntegerTypeDefinition() );
		this.registerType( new TypeName( URI.XML_SCHEMA ,
						 "nonNegativeInteger" ) ,
				   new IntegerTypeDefinition() );
		this.registerType( new TypeName( URI.XML_SCHEMA ,
						 "nonPositiveInteger" ) ,
				   new IntegerTypeDefinition() );

		this.registerType( new TypeName( URI.XML_SCHEMA ,
						 "unsignedByte" ) ,
				   new IntegerTypeDefinition() );
		this.registerType( new TypeName( URI.XML_SCHEMA ,
						 "unsignedShort" ) ,
				   new IntegerTypeDefinition() );
		this.registerType( new TypeName( URI.XML_SCHEMA ,
						 "unsignedInt" ) ,
				   new IntegerTypeDefinition() );
		this.registerType( new TypeName( URI.XML_SCHEMA ,
						 "unsignedLong" ) ,
				   new IntegerTypeDefinition() );

		this.registerType( new TypeName( URI.XML_SCHEMA ,
						 "anyURI" ) ,
				   new StringTypeDefinition() );
		this.registerType( new TypeName( URI.XML_SCHEMA ,
						 "base64Binary" ) ,
				   new StringTypeDefinition() );
		this.registerType( new TypeName( URI.XML_SCHEMA ,
						 "language" ) ,
				   new StringTypeDefinition() );

		this.registerType( new TypeName( URI.GML ,
						 "PointPropertyType" ) ,
				   new GeometryPropertyTypeDefinition() );

		this.registerType( new TypeName( URI.GML ,
						 "CurvePropertyType" ) ,
				   new GeometryPropertyTypeDefinition() );
		// XXX: deprecated gml 2 type, use CurvePropertyType instead
		this.registerType( new TypeName( URI.GML ,
						 "LineStringPropertyType" ) ,
				   new GeometryPropertyTypeDefinition() );

		this.registerType( new TypeName( URI.GML ,
						 "SurfacePropertyType" ) ,
				   new GeometryPropertyTypeDefinition() );
		// XXX: deprecated gml 2 type, use SurfacePropertyType instead
		this.registerType( new TypeName( URI.GML ,
						 "PolygonPropertyType" ) ,
				   new GeometryPropertyTypeDefinition() );

		this.registerType( new TypeName( URI.GML ,
						 "MultiPointPropertyType" ) ,
				   new GeometryPropertyTypeDefinition() );

		this.registerType( new TypeName( URI.GML ,
						 "MultiCurvePropertyType" ) ,
				   new GeometryPropertyTypeDefinition() );
		// XXX: deprecated gml 2 type, use MultiCurvePropertyType instead
		this.registerType( new TypeName( URI.GML ,
						 "MultiLineStringPropertyType" ) ,
				   new GeometryPropertyTypeDefinition() );

		this.registerType( new TypeName( URI.GML ,
						 "MultiSurfacePropertyType" ) ,
				   new GeometryPropertyTypeDefinition() );
		// XXX: deprecated gml 2 type, use MultiSurfacePropertyType instead
		this.registerType( new TypeName( URI.GML ,
						 "MultiPolygonPropertyType" ) ,
				   new GeometryPropertyTypeDefinition() );


		this.registerType( new TypeName( URI.MISP ,
						 "anyXML" ) ,
				   new AnyXMLTypeDefinition() );


		//
		// ... other embeded types
		// decimal, NCName
		// XXX: not implemented yet
	}


	/**
	 * register mapping of TypeName and TypeDefinition to dictionary
	 */
	public	void	registerType( TypeName  typeName ,
				      TypeDefinition  typeDefinition )
	{
		LogWriter.qwrite("DEBUG",  "TypeDictionary.registerType: ",
				 "[", typeName, "]: [", typeDefinition, "]" );

		this.typeMap.put( typeName , typeDefinition );
	}


	/**
	 * search TypeDefinition from dictionary
	 *
	 * if definition was not found, this method returns null.
	 */
	public	TypeDefinition	getType( TypeName  typeName )
	{
		return( this.typeMap.get( typeName ) );
	}


	public	void	debugPrint()
	{
		LogWriter.qwrite("DEBUG",  "TypeDictionary: size = ",
				 this.typeMap.size() );

		for ( Map.Entry<TypeName, TypeDefinition>  e
			      : this.typeMap.entrySet() )
		{
			LogWriter.qwrite("DEBUG",  "[", e.getKey(), "]: [",
					 e.getValue().getClass(), "]" );
		}
	}
}
