package daruma.sql;

import java.lang.StringBuilder;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.ParseException;
import java.util.Date;
import java.util.List;

import daruma.geometry.DrmGeometry;
import daruma.sql.TableColumn;
import daruma.sql.DatabaseConnection;
import daruma.storage_manager.DBMSStorageManager;
import daruma.storage_manager.type_definition.ColumnNameFactory;
import daruma.util.ISO8601DateFormat;
import daruma.util.LogWriter;

public class TableRecord
{
	private	List<TableColumn>	columns;

	public	TableRecord( List<TableColumn>  columns )
	{
		this.columns = columns;
	}

	public	void	executeInsert( DatabaseConnection  db ,
				       String  tableName,
				       long transactionSN)
					  throws DatabaseConnectionException
	{
		long	id = db.getMaxLongValueFromTable
				( tableName , "_id_" );
		id ++;

		StringBuilder	s = new StringBuilder();

		s.append( "INSERT INTO `" + tableName + "` (" );

		/* !!! [06/08/17 17:28 I.Noda] !!!
		 * system column を入れる。
		 */
		s.append( DBMSStorageManager.ColName_SystemTransactionID ) ;
		s.append( "," + DBMSStorageManager.ColName_SystemCreateTime) ;
		s.append( "," + DBMSStorageManager.ColName_SystemUpdateTime) ;

		for ( TableColumn  c  :  this.columns )
		{
			if ( c.isEmptyColumn() )
			{
				continue;
			}

			s.append( "," );
			s.append( "`" );
			s.append( c.getDefinition().getColumnName() );
			s.append( "`" );
		}

		s.append( ") VALUES (" );

		/* !!! [06/08/17 17:28 I.Noda] !!!
		 * system column を入れる。
		 */
		s.append(Long.toString(transactionSN)) ;
		s.append("," + "NULL") ;
		s.append("," + "NULL") ;

		int	wildcardCount = 0;
		for ( TableColumn  c  :  this.columns )
		{
			if ( c.isEmptyColumn() )
			{
				continue;
			}

			s.append( "," );

			Class	javaClass = c.getDefinition()
					      .getSQLDataType()
					      .getJavaClass();

			if ( DrmGeometry.class.isAssignableFrom( javaClass ) )
			{
				s.append( "GeomFromText('" );
				s.append( c.getValue() );
				s.append( "')" );
			}
			else if ( Date.class.isAssignableFrom( javaClass ) )
			{
				ISO8601DateFormat
					f = new ISO8601DateFormat();

				Date	dateTime;

				try
				{
					dateTime = f.parse( c.getValue() );

					// XXX: should not drop
					//      nanoseconds information
				}
				catch( ParseException  e )
				{
					throw new DatabaseConnectionException
									( e ) ;
				}

				s.append( "\"" );
				s.append( SQLTimeFormatConverter
					    .convertDateToString( dateTime ) );
				s.append( "\"" );
			}
			else
			{
				wildcardCount ++;
				s.append( "?" );
			}
		}

		s.append( ")" );

		LogWriter.qwrite("DEBUG",  "#", s );


		if ( wildcardCount == 0 )
		{
			db.executeUpdate( s.toString() );

			return;
		}


		PreparedStatement	st = null;

		try
		{
			st = db.prepareStatement( s.toString() );
		}
		catch( DatabaseConnectionException  e )
		{
			throw e;
		}

		try
		{
			int	wildcard_index = 1;

			for ( int  i = 0  ;  i < this.columns.size()  ;  ++ i )
			{
				TableColumn	col = this.columns.get(i);

				if ( col.isEmptyColumn() )
				{
					continue;
				}


				Class	c = col.getDefinition()
					     .getSQLDataType().getJavaClass();

				if ( c.equals( String.class ) )
				{
					st.setString( wildcard_index ,
						      col.getValue() );

					wildcard_index ++;
				}
				else if ( c.equals( Boolean.class ) )
				{
					boolean	value = Boolean
							.parseBoolean
							  ( col.getValue() );

					st.setBoolean( wildcard_index ,
						       value );

					wildcard_index ++;
				}
				else if ( c.equals( Double.class ) )
				{
					double	value = Double
							.parseDouble
							  ( col.getValue() );

					st.setDouble( wildcard_index ,
						      value );

					wildcard_index ++;
				}
				else if ( c.equals( Float.class ) )
				{
					float	value = Float
							.parseFloat
							  ( col.getValue() );

					st.setFloat( wildcard_index ,
						     value );

					wildcard_index ++;
				}
				else if ( Date.class.isAssignableFrom( c ) )
				{
				}
				else if ( DrmGeometry.class
					  .isAssignableFrom( c ) )
				{
				}
				else // XXX
				{
					st.setString( wildcard_index ,
						      col.getValue() );

					wildcard_index ++;
				}
			}

			st.executeUpdate();

			st.close();
		}
		catch( SQLException  e )
		{
			throw new DatabaseConnectionException( e.getMessage() ,
							       e );
		}

		executeInsertToSubTable( db , id );
	}

	private	void	executeInsertToSubTable( DatabaseConnection  db ,
						 long  parentID )
					  throws DatabaseConnectionException
	{
		for ( TableColumn  c  :  this.columns )
		{
			if ( c.isEmptyColumn() )
			{
				continue;
			}

			if ( c.getDefinition().isExternalTable() )
			{
				String	tableName = c.getValue();

				LogWriter.qwrite("DEBUG",  "tableName = [",
						 tableName, "]" );

				long	id = db.getMaxLongValueFromTable
					( tableName , "_id_" );
				id ++;

				for ( String  v : c.getSubValues() )
				{
					LogWriter.qwrite("DEBUG", "value = [",
							 v, "]" );

					String sql
					    = "INSERT INTO `"
					    + c.getValue()
					    + "` (`_id_`,`_parent_id_`, `"
					    + (ColumnNameFactory
					       .getTopLevelElementColumnName())
					    + "`) VALUES ("
					    + id + ","
					    + parentID
					    + ",?)";

					PreparedStatement	st = null;

					try
					{
						st = db.prepareStatement
								    ( sql );
					}
					catch( DatabaseConnectionException  e )
					{
						throw e;
					}

					LogWriter.qwrite("DEBUG",  "#", sql );

					try
					{
						st.setString( 1 , v );

						st.executeUpdate();

						st.close();
					}
					catch( SQLException  e )
					{
						throw
						new DatabaseConnectionException
						    ( e.getMessage() , e );
					}
				}
			}
		}
	}
}
