package hiro.yoshioka.sdh;

import hiro.yoshioka.util.SQLDataType;
import hiro.yoshioka.util.StringUtil;

import java.io.Serializable;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ResultSetMetaCopy implements ResultSetMetaData, Serializable {
	private static final long serialVersionUID = -7158554439203850987L;
	int columnCount;
	int[] columnDisplaySize;
	String[] columnName;
	SQLDataType[] columnType;
	String[] columnTypeName;
	int[] precision;
	int[] scale;
	String[] schemaName;
	String[] tableName;

	static public class MetaInfo {
		public int columnDisplaySize;
		public String columnName;
		public int columnType;
		public String columnTypeName;
		public int precision;
		public int scale;
		public String schemaName;
		public String tableName;
	}

	@Override
	public String toString() {
		if (columnCount > 0) {
			return String.format("RsmC columnCount[%d] schema[%s] table[%s]",
					columnName[0], schemaName[0], tableName[0]);
		} else {
			return String.format("RsmC columnCount[%d]", columnCount);
		}
	}

	public ResultSetMetaCopy(List<MetaInfo> metaList) {
		if (metaList == null || metaList.size() <= 0) {
			throw new IllegalArgumentException(
					"metaList must have any element.");
		}
		try {
			columnCount = metaList.size();
			columnDisplaySize = new int[columnCount];
			columnName = new String[columnCount];
			columnType = new SQLDataType[columnCount];
			columnTypeName = new String[columnCount];
			precision = new int[columnCount];
			scale = new int[columnCount];
			schemaName = new String[columnCount];
			tableName = new String[columnCount];
			for (int i = 1; i <= columnCount; i++) {
				MetaInfo meta = metaList.get(i - 1);
				columnDisplaySize[i - 1] = meta.columnDisplaySize;
				columnName[i - 1] = meta.columnName;
				columnType[i - 1] = SQLDataType.parse(meta.columnType);
				columnTypeName[i - 1] = meta.columnTypeName;
				try {
					precision[i - 1] = meta.precision;
				} catch (Throwable e) {
					precision[i - 1] = 0;
				}
				try {
					scale[i - 1] = meta.scale;
				} catch (Throwable e) {
					scale[i - 1] = 0;
				}
				try {
					schemaName[i - 1] = meta.schemaName;
					tableName[i - 1] = meta.tableName;
				} catch (Throwable e) {
					Logger.getLogger(getClass().getName()).info(
							columnName[i - 1]
									+ " cant get SchemaName/TableName ");
				}
			}
		} catch (Throwable e) {
			Logger.getLogger(getClass().getName()).log(Level.SEVERE, "", e);
		}
	}

	public ResultSetMetaCopy(ResultSetMetaData meta) {
		try {
			columnCount = meta.getColumnCount();
			columnDisplaySize = new int[columnCount];
			columnName = new String[columnCount];
			columnType = new SQLDataType[columnCount];
			columnTypeName = new String[columnCount];
			precision = new int[columnCount];
			scale = new int[columnCount];
			schemaName = new String[columnCount];
			tableName = new String[columnCount];
			for (int i = 1; i <= columnCount; i++) {
				columnDisplaySize[i - 1] = meta.getColumnDisplaySize(i);
				columnName[i - 1] = meta.getColumnName(i);
				columnType[i - 1] = SQLDataType.parse(meta.getColumnType(i));
				columnTypeName[i - 1] = meta.getColumnTypeName(i);
				try {
					precision[i - 1] = meta.getPrecision(i);
				} catch (Throwable e) {
					precision[i - 1] = 0;
				}
				try {
					scale[i - 1] = meta.getScale(i);
				} catch (Throwable e) {
					scale[i - 1] = 0;
				}
				try {
					schemaName[i - 1] = meta.getSchemaName(i);
					tableName[i - 1] = meta.getTableName(i);
				} catch (Throwable e) {
					Logger.getLogger(getClass().getName()).info(
							columnName[i - 1]
									+ " cant get SchemaName/TableName ");
				}
			}
		} catch (Throwable e) {
			Logger.getLogger(getClass().getName()).log(Level.SEVERE, "", e);
		}
	}

	public void resetTableName(String name) {
		for (int i = 0; i < tableName.length; i++) {
			if (StringUtil.isEmpty(tableName[i])) {
				tableName[i] = name;
			}
		}
	}

	public String getCatalogName(int column) throws SQLException {
		return null;
	}

	public String getColumnClassName(int column) throws SQLException {
		return null;
	}

	public int getColumnCount() throws SQLException {
		return columnCount;
	}

	public int getColumnDisplaySize(int column) throws SQLException {
		return columnDisplaySize[column - 1];
	}

	public String getColumnLabel(int column) throws SQLException {
		return null;
	}

	public String getColumnName(int column) throws SQLException {
		return columnName[column - 1];
	}

	public SQLDataType getColumnTypeOf(int columnIdx) {
		if (columnIdx <= 0) {
			return null;
		}
		return columnType[columnIdx - 1];
	}

	public int getColumnType(int column) throws SQLException {
		return columnType[column - 1].getType();
	}

	public String getColumnTypeName(int column) throws SQLException {
		return columnTypeName[column - 1];
	}

	public int getPrecision(int column) throws SQLException {
		return precision[column - 1];
	}

	public int getScale(int column) throws SQLException {
		return scale[column - 1];
	}

	public String getSchemaName(int column) throws SQLException {
		return schemaName[column - 1];
	}

	public String getTableName(int column) throws SQLException {
		return tableName[column - 1];
	}

	public boolean isAutoIncrement(int column) throws SQLException {
		return false;
	}

	public boolean isCaseSensitive(int column) throws SQLException {
		return false;
	}

	public boolean isCurrency(int column) throws SQLException {
		return false;
	}

	public boolean isDefinitelyWritable(int column) throws SQLException {
		return false;
	}

	public int isNullable(int column) throws SQLException {
		return 0;
	}

	public boolean isReadOnly(int column) throws SQLException {
		return false;
	}

	public boolean isSearchable(int column) throws SQLException {
		return false;
	}

	public boolean isSigned(int column) throws SQLException {
		return false;
	}

	public boolean isWritable(int column) throws SQLException {
		return false;
	}

	public boolean isWrapperFor(Class<?> arg0) throws SQLException {
		return false;
	}

	public <T> T unwrap(Class<T> arg0) throws SQLException {
		return null;
	}

	public String getBlobOrBinary() {
		StringBuilder buf = new StringBuilder();
		for (int i = 1; i <= columnCount; i++) {
			if (isBlob(i) || isBinaly(i)) {
				if (buf.length() > 0) {
					buf.append(",");
				}
				buf.append(columnName[i - 1]);
			}
		}
		return buf.toString();
	}

	public boolean hasBlobOrBinary() {
		for (int i = 1; i <= columnCount; i++) {
			if (isBlob(i) || isBinaly(i)) {
				return true;
			}
		}
		return false;
	}

	public boolean isBlob(int i) {
		if (i <= 0) {
			return false;
		}
		return columnType[i - 1].isBlob();
	}

	public boolean isColumnTypeOf(int index, Collection<SQLDataType> collections) {
		if (index <= 0) {
			return false;
		}
		for (SQLDataType dType : collections) {
			if (dType.equals(getColumnTypeOf(index))) {
				return true;
			}
		}
		return false;
	}

	public boolean isBinaly(int i) {
		if (i <= 0) {
			return false;
		}
		return columnType[i - 1].isBinary();
	}

	public boolean needsQuote(int index) {
		if (isTypeString(index) || isTypeTimes(index)) {
			return true;
		}
		return false;
	}

	public boolean isTypeTimes(int index) {
		if (index <= 0) {
			return false;
		}
		return columnType[index - 1].isDateOrDateTimeOrTime();
	}

	public boolean isTypeString(int index) {
		if (index <= 0) {
			return false;
		}
		return columnType[index - 1].isString();
	}

	public int[] getColumnDisplaySize() {
		return columnDisplaySize;
	}

	public void setColumnDisplaySize(int[] columnDisplaySize) {
		this.columnDisplaySize = columnDisplaySize;
	}

	public String[] getColumnName() {
		return columnName;
	}

	public void setColumnName(String[] columnName) {
		this.columnName = columnName;
	}

	public SQLDataType[] getColumnType() {
		return columnType;
	}

	public void setColumnType(SQLDataType[] columnType) {
		this.columnType = columnType;
	}

	public String[] getColumnTypeName() {
		return columnTypeName;
	}

	public void setColumnTypeName(String[] columnTypeName) {
		this.columnTypeName = columnTypeName;
	}

	public int[] getPrecision() {
		return precision;
	}

	public void setPrecision(int[] precision) {
		this.precision = precision;
	}

	public int[] getScale() {
		return scale;
	}

	public void setScale(int[] scale) {
		this.scale = scale;
	}

	public String[] getSchemaName() {
		return schemaName;
	}

	public void setSchemaName(String[] schemaName) {
		this.schemaName = schemaName;
	}

	public String[] getTableName() {
		return tableName;
	}

	public void setTableName(String[] tableName) {
		this.tableName = tableName;
	}

	public void setColumnCount(int columnCount) {
		this.columnCount = columnCount;
	}

}
