package profileEngine;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.JDBCType;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.ListIterator;

public class ColumnList extends LinkedList<ColumnElement>
{

	private static final long serialVersionUID = 1L;
	private ColumnElement columnElement;
	private DatabaseMetaData databaseMetaData;

	public ColumnList
	(
		String databaseProduct, 
		Connection connection, 
		String databaseName, 
		String schemaName,
		String tableName, 
		Metadata metadata, 
		Calendar dateStatisticsCollected
	)
	{
		ListIterator<ColumnElement> iterator;
		int columnProfileId;
		ResultSet tableColumns = null;
		int dataTypeCode;
		String dataTypeName = "";
		int maxLengthColumnName;
		int maxLengthDataTypeName;
		
		try 
		{
			databaseMetaData = connection.getMetaData();
		} 
		catch (SQLException e1) 
		{
			e1.printStackTrace();
		}

		try 
		{
			tableColumns = databaseMetaData.getColumns(databaseName, schemaName, tableName, null);
//			tableColumns = databaseMetaData.getColumns(null, schemaName, tableName, null);
		} 
		catch (SQLException e1) 
		{
			e1.printStackTrace();
		}
		
//		new MetaDataColumns(tableColumns);

		try 
		{
			while(tableColumns.next())
			{
				columnElement = new ColumnElement();
				columnElement.setColumnId(tableColumns.getInt("ORDINAL_POSITION"));
				columnElement.setColumnName(tableColumns.getString("COLUMN_NAME"));
				columnElement.setDataLength(tableColumns.getInt("COLUMN_SIZE"));
				if (tableColumns.getString("IS_NULLABLE").equals("NO"))
					columnElement.setNullable("N");
				else
					columnElement.setNullable("Y");

				dataTypeCode = tableColumns.getInt("DATA_TYPE");

				dataTypeName = JDBCType.valueOf(dataTypeCode).getName();

				columnElement.setDataType(dataTypeName);

				this.add(columnElement);
			}
		} 
		catch (SQLException e1) 
		{
			e1.printStackTrace();
		}

		try 
		{
			tableColumns.close();
		} 
		catch (SQLException e) 
		{
			e.printStackTrace();
		}
		
		if (this.isEmpty())
		{
			System.out.println("No columns to profile. Check database name, schema name and table name for the specified connection.");
			System.exit(1);
		}
	
		for (iterator = this.listIterator(); iterator.hasNext();)
		{
			columnElement = (ColumnElement) iterator.next();
			
			columnProfileId = metadata.insertColumnProfile
			(
				dateStatisticsCollected, 
				columnElement.getColumnName(), 
				columnElement.getDataType(), 
				columnElement.getDataLength(), 
				columnElement.getNullable()
			);
			
			columnElement.setColumnProfileId(columnProfileId);
		}
	
		// Print column definitions for this tables
		System.out.println("");
		System.out.println("Table: " + databaseName + "." + schemaName + "." + tableName);
		
		maxLengthColumnName = 6;      // Start with minimum length as length of title "Column"
		maxLengthDataTypeName = 9;      // Start with minimum length as length of title "Data Type"
		
		for (iterator = this.listIterator(); iterator.hasNext();)
		{
			columnElement = (ColumnElement) iterator.next();
			
			if (columnElement.getColumnName().length() > maxLengthColumnName)
				maxLengthColumnName = columnElement.getColumnName().length();
			if (columnElement.getDataType().length() > maxLengthDataTypeName)
				maxLengthDataTypeName = columnElement.getDataType().length();
		}
	
		System.out.println
		(
			pad("Column", maxLengthColumnName) + "|" +
		    pad("Data Type", maxLengthDataTypeName) + "|" +
			"Nullable" + "|" +
		    "Data Length"
		);

		for (iterator = this.listIterator(); iterator.hasNext();)
		{
			columnElement = (ColumnElement) iterator.next();

			System.out.println
			(
				pad(columnElement.getColumnName(), maxLengthColumnName) + "|" +
			    pad(columnElement.getDataType().toLowerCase(), maxLengthDataTypeName) + "|" +
				"   " + columnElement.getNullable() + "    |" +
				columnElement.getDataLength()
			);
		}
		System.out.println("");
	}

	private String pad(String s, int length)
	{
		StringBuffer padding;
		int i;
		
		padding = new StringBuffer();
		for (i = 0; i < length - s.length(); i++)
			padding.append(" ");
		
		return s + padding.toString();
	}
}
