package daruma.storage_manager.type_definition.types;

import daruma.storage_manager.type_definition.TypeDefinition;
import daruma.storage_manager.type_definition.TypedInstance;
import daruma.storage_manager.type_definition.TypeException;
import daruma.storage_manager.type_definition.ColumnNameFactory;
import daruma.storage_manager.type_definition.ElementName;
import daruma.storage_manager.StorageManager;
import daruma.storage_manager.StorageException;
import daruma.geometry.TransformationContext;
import daruma.sql.SQLDataType;
import daruma.sql.SQLDataTypeConstant;
import daruma.sql.TableColumnDefinition;
import daruma.sql.TableColumn;
import daruma.xml.UniversalName;
import daruma.xml.SimpleXPath;
import daruma.xml.util.ElementUtil;
import daruma.xml.util.XMLFormatConverter;
import daruma.xml.util.XMLParseErrorException;
import daruma.util.Pair;
import daruma.util.LogWriter;

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

import javax.xml.transform.TransformerException;
import java.util.List;
import java.util.ArrayList;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;


public class AnyXMLTypeDefinition extends TypeDefinition
{
	public	AnyXMLTypeDefinition()
	{
		super( true , false );
	}

	@Override
	public SQLDataType	getSingleSQLDataType()
	{
		return( SQLDataTypeConstant.BLOB );
	}

	@Override
	public	Pair<TypedInstance, Integer>
				createInstance( Element  element ,
						ElementName  topLevelElement ,
						SimpleXPath  path ,
						StorageManager  storage ,
						int  elementIndex )
							throws TypeException
	{
		//
		// debug print
		//
		LogWriter.qwrite("DEBUG",  
				 this.getClass().getName(), 
				 ": createInstance()" );
		LogWriter.qwrite("DEBUG",  
				 "elementIndex = ", elementIndex );

		Element	data;
		try
		{
			data = ElementUtil.getSingleChildElement( element );
		}
		catch( XMLParseErrorException  e )
		{
			throw new TypeException( e );
		}

		/* <<< [06/08/17 15:14 I.Noda] <<< 
		 * debug の LogWriter への集約
		 */
		//ElementUtil.debugPrint( data , System.err );
		/* === [06/08/17 15:14 I.Noda] === */
		LogWriter.qwrite("DEBUG",
				 "in createInstance():", data) ;
		/* >>> [06/08/17 15:14 I.Noda] >>> */

		ByteArrayOutputStream	buf = new ByteArrayOutputStream();

		try
		{
			XMLFormatConverter.print( data , buf );
		}
		catch( TransformerException  e )
		{
			e.printStackTrace();

			throw new TypeException( "Can't convert XML to text" ,
						 e );
		}

		String	columnName;
		if ( path == null )
		{
		    /* !!! [06/08/16 03:26 I.Noda] !!! 
		     * TopLevelEmenentColumnNameFactory から
		     * ColumnNameFactory へ変更。
		     */
			columnName = 
			    ColumnNameFactory.getTopLevelElementColumnName();
		}
		else
		{
			SimpleXPath	newPath = new SimpleXPath( path );

			newPath.add( new UniversalName
				     ( element.getNamespaceURI() ,
				       element.getLocalName() ) );

			try
			{
				columnName
				 = storage.getShortXPathStringForDB( newPath );
			}
			catch( StorageException  e )
			{
				throw new TypeException( e );
			}
		}

		TableColumn	column;
		column = new TableColumn( new TableColumnDefinition
					  ( columnName ,
					    this.getSingleSQLDataType() ) ,
					  buf.toString() );

		List<TableColumn>  columnList = new ArrayList<TableColumn>();
		columnList.add( column );

		return( new Pair<TypedInstance, Integer>
			( new TypedInstance( columnList , this ) ,
			  elementIndex + 1 ) );
	}

	@Override
	public	int	convertToXMLElement( Element  element ,
					     Document  doc ,
					     StorageManager  storage ,
					     TransformationContext  trans ,
					     List<TableColumn>  columns ,
					     int  index ,
					     long  id ) throws TypeException
	{
		if ( index >= columns.size() )
		{
			throw new TypeException
			  ( "internal error in " + this.getClass().getName()
			    + ": unexpected instantiation" );
		}

		String	value = columns.get( index ).getValue();

		ByteArrayInputStream
			buf = new ByteArrayInputStream( value.getBytes() );

		try
		{
			XMLFormatConverter.readNode( buf , element );
		}
		catch( TransformerException  e )
		{
			e.printStackTrace();

			throw new TypeException( "Can't convert text to XML" ,
						 e );
		}

		return( index + 1 );
	}
}
