/*
 * blancoDb Enterprise Edition Copyright (C) 2004-2005 Tosiki Iga
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 */
package blanco.db.mapping;

import java.io.ByteArrayInputStream;
import java.io.CharArrayReader;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;

public final class BlancoDbMappingUtil {
    /**
     * Java型名をきっかけに、ResultSetに対するゲッターメソッド名を取得します。
     * 
     * @author tosiki iga
     * @since 2005.05.03
     * @param javaTypeName
     *            Java上の型名
     * @return
     */
    public static final String getResultSetGetterMethodName(String javaTypeName) {
        String setAccessorName = "";
        if (javaTypeName.equals("int")) {
            setAccessorName = "getInt";
        } else if (javaTypeName.equals("byte")) {
            setAccessorName = "getByte";
        } else if (javaTypeName.equals("short")) {
            setAccessorName = "getShort";
        } else if (javaTypeName.equals("long")) {
            setAccessorName = "getLong";
        } else if (javaTypeName.equals("boolean")) {
            setAccessorName = "getBoolean";
        } else if (javaTypeName.equals("float")) {
            setAccessorName = "getFloat";
        } else if (javaTypeName.equals("double")) {
            setAccessorName = "getDouble";
        } else if (javaTypeName.equals("String")) {
            setAccessorName = "getString";
        } else if (javaTypeName.equals("Date")) {
            setAccessorName = "getTimestamp";
        } else if (javaTypeName.equals("BigDecimal")) {
            setAccessorName = "getBigDecimal";
        } else if (javaTypeName.equals("Integer")) {
            setAccessorName = "getInt";
        } else if (javaTypeName.equals("Byte")) {
            setAccessorName = "getByte";
        } else if (javaTypeName.equals("Short")) {
            setAccessorName = "getShort";
        } else if (javaTypeName.equals("Long")) {
            setAccessorName = "getLong";
        } else if (javaTypeName.equals("Boolean")) {
            setAccessorName = "getBoolean";
        } else if (javaTypeName.equals("Float")) {
            setAccessorName = "getFloat";
        } else if (javaTypeName.equals("Double")) {
            setAccessorName = "getDouble";
        } else if (javaTypeName.equals("InputStream")) {
            setAccessorName = "getBinaryStream";
        } else if (javaTypeName.equals("Reader")) {
            setAccessorName = "getCharacterStream";
        }
        return setAccessorName;
    }

    /**
     * Java型名をきっかけに、PreparedStatementに対するセッターメソッド名を取得します。
     * 
     * @author tosiki iga
     * @since 2005.05.03
     * @param javaTypeName
     *            Java上の型名
     * @return
     */
    public static final String getPreparedStatementSetterMethodName(
            String javaTypeName) {
        String setAccessorName = "";
        if (javaTypeName.equals("int")) {
            setAccessorName = "setInt";
        } else if (javaTypeName.equals("byte")) {
            setAccessorName = "setByte";
        } else if (javaTypeName.equals("short")) {
            setAccessorName = "setShort";
        } else if (javaTypeName.equals("long")) {
            setAccessorName = "setLong";
        } else if (javaTypeName.equals("boolean")) {
            setAccessorName = "setBoolean";
        } else if (javaTypeName.equals("float")) {
            setAccessorName = "setFloat";
        } else if (javaTypeName.equals("double")) {
            setAccessorName = "setDouble";
        } else if (javaTypeName.equals("String")) {
            setAccessorName = "setString";
        } else if (javaTypeName.equals("Date")) {
            setAccessorName = "setTimestamp";
        } else if (javaTypeName.equals("BigDecimal")) {
            setAccessorName = "setBigDecimal";
        } else if (javaTypeName.equals("Integer")) {
            setAccessorName = "setInt";
        } else if (javaTypeName.equals("Short")) {
            setAccessorName = "setShort";
        } else if (javaTypeName.equals("Byte")) {
            setAccessorName = "setByte";
        } else if (javaTypeName.equals("Long")) {
            setAccessorName = "setLong";
        } else if (javaTypeName.equals("Boolean")) {
            setAccessorName = "setBoolean";
        } else if (javaTypeName.equals("Float")) {
            setAccessorName = "setFloat";
        } else if (javaTypeName.equals("Double")) {
            setAccessorName = "setDouble";
        } else if (javaTypeName.equals("InputStream")) {
            setAccessorName = "setBinaryStream";
        } else if (javaTypeName.equals("Reader")) {
            setAccessorName = "setCharacterStream";
        }
        return setAccessorName;
    }

    /**
     * 適当な値でpreparedStatementにセットを行います。 <br>
     * TODO: 適当な値というのが、0でよいのかどうかは再考の必要あり。1の可能性が高いです。
     * 
     * @throws SQLException
     */
    public static final void processPreparedStatementWithSomeValue(
            String javaTypeName, PreparedStatement stmt, int columnId)
            throws SQLException {
        if (javaTypeName.equals("int")) {
            stmt.setInt(columnId, 0);
        } else if (javaTypeName.equals("byte")) {
            stmt.setByte(columnId, (byte) 0x00);
        } else if (javaTypeName.equals("short")) {
            stmt.setShort(columnId, (short) 0);
        } else if (javaTypeName.equals("long")) {
            stmt.setLong(columnId, 0);
        } else if (javaTypeName.equals("boolean")) {
            stmt.setBoolean(columnId, false);
        } else if (javaTypeName.equals("float")) {
            stmt.setFloat(columnId, 0);
        } else if (javaTypeName.equals("double")) {
            stmt.setDouble(columnId, 0);
        } else if (javaTypeName.equals("String")) {
            stmt.setString(columnId, "");
        } else if (javaTypeName.equals("Date")) {
            stmt.setTimestamp(columnId, new Timestamp(0));
        } else if (javaTypeName.equals("BigDecimal")) {
            // BigDecimal(int)は J2SE 1.5から導入されたメソッドです。
            // "0"と明示的に文字列として指定しています。
            stmt.setBigDecimal(columnId, new BigDecimal("0"));
        } else if (javaTypeName.equals("Integer")) {
            stmt.setInt(columnId, 0);
        } else if (javaTypeName.equals("Byte")) {
            stmt.setByte(columnId, (byte) 0x00);
        } else if (javaTypeName.equals("Short")) {
            stmt.setShort(columnId, (short) 0);
        } else if (javaTypeName.equals("Long")) {
            stmt.setLong(columnId, 0);
        } else if (javaTypeName.equals("Boolean")) {
            stmt.setBoolean(columnId, false);
        } else if (javaTypeName.equals("Float")) {
            stmt.setFloat(columnId, 0);
        } else if (javaTypeName.equals("Double")) {
            stmt.setDouble(columnId, 0);
        } else if (javaTypeName.equals("InputStream")) {
            byte[] dummy = "0".getBytes();
            stmt.setBinaryStream(columnId, new ByteArrayInputStream(dummy),
                    dummy.length);
        } else if (javaTypeName.equals("Reader")) {
            char[] dummy = new char[1];
            dummy[0] = '0';
            stmt.setCharacterStream(columnId, new CharArrayReader(dummy),
                    dummy.length);
        } else {
            System.out.println("該当するセッターが見つかりませんでした。");
        }
    }

    public static final String getResultSetUpdateMethodName(String javaTypeName) {
        String setAccessorName = "";
        if (javaTypeName.equals("int")) {
            setAccessorName = "updateInt";
        } else if (javaTypeName.equals("byte")) {
            setAccessorName = "updateByte";
        } else if (javaTypeName.equals("short")) {
            setAccessorName = "updateShort";
        } else if (javaTypeName.equals("long")) {
            setAccessorName = "updateLong";
        } else if (javaTypeName.equals("boolean")) {
            setAccessorName = "updateBoolean";
        } else if (javaTypeName.equals("float")) {
            setAccessorName = "updateFloat";
        } else if (javaTypeName.equals("double")) {
            setAccessorName = "updateDouble";
        } else if (javaTypeName.equals("String")) {
            setAccessorName = "updateString";
        } else if (javaTypeName.equals("Date")) {
            setAccessorName = "updateTimestamp";
        } else if (javaTypeName.equals("BigDecimal")) {
            setAccessorName = "updateBigDecimal";
        } else if (javaTypeName.equals("Integer")) {
            setAccessorName = "updateInt";
        } else if (javaTypeName.equals("Byte")) {
            setAccessorName = "updateByte";
        } else if (javaTypeName.equals("Short")) {
            setAccessorName = "updateShort";
        } else if (javaTypeName.equals("Long")) {
            setAccessorName = "updateLong";
        } else if (javaTypeName.equals("Boolean")) {
            setAccessorName = "updateBoolean";
        } else if (javaTypeName.equals("Float")) {
            setAccessorName = "updateFloat";
        } else if (javaTypeName.equals("Double")) {
            setAccessorName = "updateDouble";
        } else if (javaTypeName.equals("InputStream")) {
            setAccessorName = "updateBinaryStream";
        } else if (javaTypeName.equals("Reader")) {
            setAccessorName = "updateCharacterStream";
        }
        return setAccessorName;
    }

    /**
     * ラッパークラス対応が必要かどうかを判定します。
     * 
     * @param javaTypeName
     *            短いJava言語上の名称 例：Integer
     * @return
     */
    public static final boolean isMapWrapperClassNecessity(String javaTypeName) {
        if (javaTypeName.equals("Integer") || javaTypeName.equals("Byte")
                || javaTypeName.equals("Short") || javaTypeName.equals("Long")
                || javaTypeName.equals("Float")
                || javaTypeName.equals("Double")
                || javaTypeName.equals("Boolean")
                || javaTypeName.equals("Date")) {
            return true;
        }
        return false;
    }

    /**
     * 必要な場合のみ、プリミティブ型に対してラッパークラスをラッピングします。
     * 
     * @param String
     *            originalLine オリジナル行
     * @param String
     *            javaTypeName Java言語上の型
     * @return
     */
    public static final String mapWrapperClassForPrimitive(String originalLine,
            String javaTypeName) {
        String converter1 = "";
        String converter2 = "";
        if (javaTypeName.equals("Date")) {
            // Dateの場合には ResultSetからはTimestampが渡ってきます。
            converter1 = "BlancoDbUtil.convertTimestampToDate(";
            converter2 = ")";
        } else if (javaTypeName.equals("Byte")) {
            converter1 = "new Byte(";
            converter2 = ")";
        } else if (javaTypeName.equals("Short")) {
            converter1 = "new Short(";
            converter2 = ")";
        } else if (javaTypeName.equals("Integer")) {
            converter1 = "new Integer(";
            converter2 = ")";
        } else if (javaTypeName.equals("Long")) {
            converter1 = "new Long(";
            converter2 = ")";
        } else if (javaTypeName.equals("Boolean")) {
            converter1 = "new Boolean(";
            converter2 = ")";
        } else if (javaTypeName.equals("Double")) {
            converter1 = "new Double(";
            converter2 = ")";
        } else if (javaTypeName.equals("Float")) {
            converter1 = "new Float(";
            converter2 = ")";
        }
        return converter1 + originalLine + converter2;
    }

    /**
     * ラッパークラスをプリミティブに変換します。
     * 
     * @param originalLine
     * @param javaTypeName
     * @return
     */
    public static final String mapWrapperClassIntoPrimitive(
            String originalLine, String javaTypeName) {
        String converter1 = "";
        String converter2 = "";
        if (javaTypeName.equals("Date")) {
            converter1 = "new Timestamp(";
            converter2 = ".getTime())";
        } else if (javaTypeName.equals("Byte")) {
            converter1 = "";
            converter2 = ".byteValue()";
        } else if (javaTypeName.equals("Short")) {
            converter1 = "";
            converter2 = ".shortValue()";
        } else if (javaTypeName.equals("Integer")) {
            converter1 = "";
            converter2 = ".intValue()";
        } else if (javaTypeName.equals("Long")) {
            converter1 = "";
            converter2 = ".longValue()";
        } else if (javaTypeName.equals("Boolean")) {
            converter1 = "";
            converter2 = ".booleanValue()";
        } else if (javaTypeName.equals("Double")) {
            converter1 = "";
            converter2 = ".doubleValue()";
        } else if (javaTypeName.equals("Float")) {
            converter1 = "";
            converter2 = ".floatValue()";
        }
        return converter1 + originalLine + converter2;
    }

    public final static String convertJdbcTypeToString(int jdbcType) {
        final String TYPES_BASE = "java.sql.Types.";
        switch (jdbcType) {
        case Types.BIT:
            return TYPES_BASE + "BIT";
        case Types.TINYINT:
            return TYPES_BASE + "TINYINT";
        case Types.SMALLINT:
            return TYPES_BASE + "SMALLINT";
        case Types.INTEGER:
            return TYPES_BASE + "INTEGER";
        case Types.BIGINT:
            return TYPES_BASE + "BIGINT";
        case Types.FLOAT:
            return TYPES_BASE + "FLOAT";
        case Types.REAL:
            return TYPES_BASE + "REAL";
        case Types.DOUBLE:
            return TYPES_BASE + "DOUBLE";
        case Types.NUMERIC:
            return TYPES_BASE + "NUMERIC";
        case Types.DECIMAL:
            return TYPES_BASE + "DECIMAL";
        case Types.CHAR:
            return TYPES_BASE + "CHAR";
        case Types.VARCHAR:
            return TYPES_BASE + "VARCHAR";
        case Types.LONGVARCHAR:
            return TYPES_BASE + "LONGVARCHAR";
        case Types.DATE:
            return TYPES_BASE + "DATE";
        case Types.TIME:
            return TYPES_BASE + "TIME";
        case Types.TIMESTAMP:
            return TYPES_BASE + "TIMESTAMP";
        case Types.BINARY:
            return TYPES_BASE + "BINARY";
        case Types.VARBINARY:
            return TYPES_BASE + "VARBINARY";
        case Types.LONGVARBINARY:
            return TYPES_BASE + "LONGVARBINARY";
        case Types.NULL:
            return TYPES_BASE + "NULL";
        case Types.OTHER:
            return TYPES_BASE + "OTHER";
        case Types.JAVA_OBJECT:
            return TYPES_BASE + "JAVA_OBJECT";
        case Types.DISTINCT:
            return TYPES_BASE + "DISTINCT";
        case Types.STRUCT:
            return TYPES_BASE + "STRUCT";
        case Types.ARRAY:
            return TYPES_BASE + "ARRAY";
        case Types.BLOB:
            return TYPES_BASE + "BLOB";
        case Types.CLOB:
            return TYPES_BASE + "CLOB";
        case Types.REF:
            return TYPES_BASE + "REF";
        case Types.DATALINK:
            // since 1.4
            return TYPES_BASE + "DATALINK";
        case Types.BOOLEAN:
            // since 1.4
            return TYPES_BASE + "BOOLEAN";
        default:
            // 判定不能
            System.out.println("JDBCタイプ[" + jdbcType + "]は未サポートです.");
            return "java.sql.Types.OTHER";
        }
    }

    public final static String convertJavaTypeToJdbcType(String javaFullType) {
        final String TYPES_BASE = "java.sql.Types.";
        if (javaFullType.equals("java.lang.Boolean")) {
            return TYPES_BASE + "BIT";
            //return TYPES_BASE + "BOOLEAN";
        } else if (javaFullType.equals("java.lang.Byte")) {
            return TYPES_BASE + "TINYINT";
        } else if (javaFullType.equals("java.lang.Short")) {
            return TYPES_BASE + "SMALLINT";
        } else if (javaFullType.equals("java.lang.Integer")) {
            return TYPES_BASE + "INTEGER";
        } else if (javaFullType.equals("java.lang.Long")) {
            return TYPES_BASE + "BIGINT";
        } else if (javaFullType.equals("java.lang.Float")) {
            return TYPES_BASE + "REAL";
        } else if (javaFullType.equals("java.lang.Double")) {
            return TYPES_BASE + "DOUBLE";
        } else if (javaFullType.equals("java.math.BigDecimal")) {
            return TYPES_BASE + "DECIMAL";
        } else if (javaFullType.equals("java.lang.String")) {
            return TYPES_BASE + "VARCHAR";
        } else if (javaFullType.equals("java.io.Reader")) {
            return TYPES_BASE + "LONGVARCHAR";
        } else if (javaFullType.equals("java.util.Date")) {
            return TYPES_BASE + "TIMESTAMP";
        } else if (javaFullType.equals("java.io.InputStream")) {
            return TYPES_BASE + "VARBINARY";
        } else {
            System.out.println("JDBCタイプ[" + javaFullType + "]は未サポートです.");
            return "java.sql.Types.OTHER";
        }
    }
}
