/*
 * blanco Framework
 * Copyright (C) 2004-2006 IGA Tosiki
 * 
 * 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.util.odp;

import java.sql.ResultSetMetaData;
import java.sql.Types;

import blanco.commons.util.BlancoNameUtil;
import blanco.dbmetadata.BlancoDbMetaDataUtil;
import blanco.dbmetadata.valueobject.BlancoDbMetaDataColumnStructure;

/**
 * blancoDbの型マッピングに関するメソッドを集めたクラス。
 * 
 * @author ToshikiIga
 */
public final class BlancoDbMappingUtilOdpDotNet {
    /**
     * 列構造体からJava言語におけるフルクラス名を取得します。
     * 
     * この処理は、プログラミング言語ごとに異なるものです。 Typesを Java言語の何の型にマッピングするのか、という重要な処理にあたります。
     * 
     * @param columnStructure
     * @return
     */
    public static final String getFullClassName(
            final BlancoDbMetaDataColumnStructure columnStructure) {
        // final boolean isNoNulls = (columnStructure.getNullable() ==
        // ResultSetMetaData.columnNoNulls);
        switch (columnStructure.getDataType()) {
        case Types.BIT:
        case Types.BOOLEAN:
            return "bool";
        case Types.TINYINT:
            return "byte";
        case Types.SMALLINT:
            return "short";
        case Types.INTEGER:
            return "int";
        case Types.BIGINT:
            return "long";
        case Types.REAL:
            return "float";
        case Types.FLOAT:
        case Types.DOUBLE:
            return "double";
        case Types.NUMERIC:
        case Types.DECIMAL:
            return "decimal";
        case Types.CHAR:
        case Types.VARCHAR:
            return "string";
        case Types.DATE:
            // 仮で TIMESTAMPと同じ動きをさせています。
        case Types.TIME:
            // 仮で TIMESTAMPと同じ動きをさせています。
        case Types.TIMESTAMP:
            return "System.DateTime";
        case Types.BINARY:
        case Types.VARBINARY:
        case Types.LONGVARBINARY:
        case Types.BLOB:
            return "byte[]";
        case Types.LONGVARCHAR:
        case Types.CLOB:
            return "string";
        case Types.JAVA_OBJECT:
        case Types.DISTINCT:
        case Types.STRUCT:
        case Types.ARRAY:
        case Types.NULL:
        case Types.OTHER:
        case Types.REF:
        case Types.DATALINK:
        default:
            throw new IllegalArgumentException("BlancoDbTableMeta2Xml: 列パラメータ["
                    + columnStructure.getName()
                    + "]("
                    + BlancoDbMetaDataUtil
                            .convertJdbcDataTypeToString(columnStructure
                                    .getDataType())
                    + ")のバインド: 処理できないSQL型("
                    + columnStructure.getDataType()
                    + "/"
                    + BlancoDbMetaDataUtil
                            .convertJdbcDataTypeToString(columnStructure
                                    .getDataType()) + ")が指定されました。");
        }
    }

    /**
     * 列構造体からJava言語におけるクラス名を取得します。
     * 
     * @param columnStructure
     * @return
     */
    public static final String getClassName(
            final BlancoDbMetaDataColumnStructure columnStructure) {
        return BlancoNameUtil.trimJavaPackage(BlancoDbMappingUtilOdpDotNet
                .getFullClassName(columnStructure));
    }

    /**
     * プリミティブでしかもNULLをサポートすべきものかどうかを判断。
     * 
     * @param columnStructure
     * @return
     */
    public static boolean getPrimitiveAndNullable(
            final BlancoDbMetaDataColumnStructure columnStructure) {
        final boolean isNoNulls = !(columnStructure.getNullable() == ResultSetMetaData.columnNullable);

        switch (columnStructure.getDataType()) {
        case Types.BIT:
        case Types.BOOLEAN:
            if (isNoNulls) {
                return false;
            } else {
                return true;
            }
        case Types.TINYINT:
            if (isNoNulls) {
                return false;
            } else {
                return true;
            }
        case Types.SMALLINT:
            if (isNoNulls) {
                return false;
            } else {
                return true;
            }
        case Types.INTEGER:
            if (isNoNulls) {
                return false;
            } else {
                return true;
            }
        case Types.BIGINT:
            if (isNoNulls) {
                return false;
            } else {
                return true;
            }
        case Types.REAL:
            if (isNoNulls) {
                return false;
            } else {
                return true;
            }
        case Types.FLOAT:
        case Types.DOUBLE:
            if (isNoNulls) {
                return false;
            } else {
                return true;
            }
        case Types.NUMERIC:
        case Types.DECIMAL:
            return false;
        case Types.CHAR:
        case Types.VARCHAR:
            return false;
        case Types.DATE:
            // 仮で TIMESTAMPと同じ動きをさせています。
        case Types.TIME:
            // 仮で TIMESTAMPと同じ動きをさせています。
        case Types.TIMESTAMP:
            return false;
        case Types.BINARY:
        case Types.VARBINARY:
        case Types.LONGVARBINARY:
        case Types.BLOB:
            return false;
        case Types.LONGVARCHAR:
        case Types.CLOB:
            return false;
        case Types.JAVA_OBJECT:
        case Types.DISTINCT:
        case Types.STRUCT:
        case Types.ARRAY:
        case Types.NULL:
        case Types.OTHER:
        case Types.REF:
        case Types.DATALINK:
        default:
            return false;
        }
    }

    /**
     * 列情報をもとに、ResultSetに対するゲッターメソッド名を取得します。
     * 
     * @param columnStructure
     * @return
     */
    public static final String getGetterMethodNameForResultSet(
            final BlancoDbMetaDataColumnStructure columnStructure) {
        return "Get" + getGetterSetterBaseMethodName(columnStructure);
    }

    /**
     * ゲッターセッターメソッド名のベース名称を取得します。
     * 
     * @param columnStructure
     * @return
     */
    private static final String getGetterSetterBaseMethodName(
            final BlancoDbMetaDataColumnStructure columnStructure) {
        switch (columnStructure.getDataType()) {
        case Types.BIT:
        case Types.BOOLEAN:
            return "Boolean";
        case Types.TINYINT:
            return "Byte";
        case Types.SMALLINT:
            return "Int16";
        case Types.INTEGER:
            return "Int32";
        case Types.BIGINT:
            return "Int64";
        case Types.REAL:
            return "Float";
        case Types.FLOAT:
        case Types.DOUBLE:
            return "Double";
        case Types.NUMERIC:
        case Types.DECIMAL:
            return "Decimal";
        case Types.CHAR:
        case Types.VARCHAR:
            return "String";
        case Types.DATE:
            // 仮で TIMESTAMPと同じ動きをさせています。
        case Types.TIME:
            // 仮で TIMESTAMPと同じ動きをさせています。
        case Types.TIMESTAMP:
            return "DateTime";
        case Types.BINARY:
        case Types.VARBINARY:
        case Types.LONGVARBINARY:
        case Types.BLOB:
            return "BinaryStream";
        case Types.LONGVARCHAR:
        case Types.CLOB:
            return "String";
        case Types.JAVA_OBJECT:
        case Types.DISTINCT:
        case Types.STRUCT:
        case Types.ARRAY:
        case Types.NULL:
        case Types.OTHER:
        case Types.REF:
        case Types.DATALINK:
        default:
            throw new IllegalArgumentException("ゲッターおよびセッターを取得する処理で、型["
                    + columnStructure.getDataType()
                    + "/"
                    + BlancoDbMetaDataUtil
                            .convertJdbcDataTypeToString(columnStructure
                                    .getDataType()) + "]に対応するメソッド名の解析に失敗しました。");
        }
    }

    /**
     * OracleDbType.に続く部分を戻します。
     * 
     * OdpDotNet版独自のメソッドです。
     * 
     * @param columnStructure
     * @return
     */
    public static final String getDotNetSqlDbType(
            final BlancoDbMetaDataColumnStructure columnStructure) {
        switch (columnStructure.getDataType()) {
        case Types.BIT:
        case Types.BOOLEAN:
            return "Bit";
        case Types.TINYINT:
            return "TinyInt";
        case Types.SMALLINT:
            return "Int16";
        case Types.INTEGER:
            return "Int32";
        case Types.BIGINT:
            return "Int64";
        case Types.REAL:
            return "Real";
        case Types.FLOAT:
            return "Float";
        case Types.DOUBLE:
            return "Double";
        case Types.NUMERIC:
        case Types.DECIMAL:
            return "Decimal";
        case Types.CHAR:
            return "Char";
        case Types.VARCHAR:
            return "Varchar2";
        case Types.DATE:
        case Types.TIME:
        case Types.TIMESTAMP:
            return "TimeStamp";
        case Types.BINARY:
        case Types.VARBINARY:
        case Types.LONGVARBINARY:
        case Types.BLOB:
            return "Image";
        case Types.LONGVARCHAR:
        case Types.CLOB:
            return "VarChar";
        case Types.JAVA_OBJECT:
        case Types.DISTINCT:
        case Types.STRUCT:
        case Types.ARRAY:
        case Types.NULL:
        case Types.OTHER:
        case Types.REF:
        case Types.DATALINK:
        default:
            throw new IllegalArgumentException("SQLデータ型への変換をおこなう処理で、型["
                    + columnStructure.getDataType()
                    + "/"
                    + BlancoDbMetaDataUtil
                            .convertJdbcDataTypeToString(columnStructure
                                    .getDataType()) + "]に対応するメソッド名の解析に失敗しました。");
        }
    }

    /**
     * 出力パラメータに対応する ODP.NET タイプを返します。
     * 
     * SQL 定義書の出力パラメータに指定した .NET の型から ODP.NET タイプを推測します。 OdpDotNet版独自のメソッドです。
     * 
     * @param columnStructure
     * @return
     */
    public static final String getOracleType(
            final BlancoDbMetaDataColumnStructure columnStructure) {
        switch (columnStructure.getDataType()) {
        case Types.NUMERIC:
        case Types.DECIMAL:
            return "OracleDecimal";
        case Types.CHAR:
        case Types.VARCHAR:
            return "OracleString";
        case Types.DATE:
            // 仮で TIMESTAMPと同じ動きをさせています。
        case Types.TIME:
            // 仮で TIMESTAMPと同じ動きをさせています。
        case Types.TIMESTAMP:
            return "OracleTimeStamp";
        case Types.BINARY:
        case Types.VARBINARY:
        case Types.LONGVARBINARY:
        case Types.BLOB:
            // return "byte[]";
        case Types.LONGVARCHAR:
        case Types.CLOB:
            // return "string";
        case Types.BIT:
        case Types.BOOLEAN:
            // return "bool";
        case Types.TINYINT:
            // return "byte";
        case Types.SMALLINT:
            // return "short";
        case Types.INTEGER:
            // return "int";
        case Types.BIGINT:
            // return "long";
        case Types.REAL:
            // return "float";
        case Types.FLOAT:
        case Types.DOUBLE:
            // return "double";

        case Types.JAVA_OBJECT:
        case Types.DISTINCT:
        case Types.STRUCT:
        case Types.ARRAY:
        case Types.NULL:
        case Types.OTHER:
        case Types.REF:
        case Types.DATALINK:
        default:
            throw new IllegalArgumentException("パラメータ["
                    + columnStructure.getName()
                    + "]("
                    + BlancoDbMetaDataUtil
                            .convertJdbcDataTypeToString(columnStructure
                                    .getDataType())
                    + ")のバインド: 処理できないOracle型("
                    + columnStructure.getDataType()
                    + "/"
                    + BlancoDbMetaDataUtil
                            .convertJdbcDataTypeToString(columnStructure
                                    .getDataType()) + ")が指定されました。");
        }
    }

}
