/*
 * blancoDb
 * Copyright (C) 2004-2006 Yasuo Nakanishi
 * 
 * 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;

import java.util.List;

import blanco.cg.BlancoCgObjectFactory;
import blanco.cg.valueobject.BlancoCgClass;
import blanco.cg.valueobject.BlancoCgMethod;
import blanco.cg.valueobject.BlancoCgSourceFile;
import blanco.db.common.stringgroup.BlancoDbDriverNameStringGroup;
import blanco.db.common.stringgroup.BlancoDbLoggingModeStringGroup;
import blanco.db.common.util.BlancoDbUtil;
import blanco.db.common.valueobject.BlancoDbSetting;
import blanco.db.expander.query.BlancoPerfomanceCommonUtil;

/**
 * blancoDbが共通的に利用するユーティリティクラス。
 * 
 * このクラスが生成するクラスはblancoDbが生成したソースコードで利用されます
 * 
 * @since 2006.03.02
 * @author IGA Tosiki
 */
public class BlancoDbUtilClassJava {
    /**
     * このクラス自身のクラス名
     */
    public static final String CLASS_NAME = "BlancoDbUtil";

    /**
     * blancoCg オブジェクトファクトリ。
     */
    private BlancoCgObjectFactory fCgFactory = null;

    /**
     * このクラスが含まれるソースコード。
     */
    private BlancoCgSourceFile fCgSourceFile = null;

    private BlancoDbSetting fDbSetting = null;

    public BlancoDbUtilClassJava(final BlancoCgObjectFactory cgFactory,
            final String argPackage, final BlancoDbSetting argDbSetting) {
        fCgFactory = cgFactory;
        fCgSourceFile = fCgFactory.createSourceFile(argPackage,
                "This code is generated by blanco Framework.");

        this.fDbSetting = argDbSetting;
    }

    public BlancoCgSourceFile expand() {
        final BlancoCgClass cgClass = fCgFactory.createClass(CLASS_NAME, null);
        fCgSourceFile.getClassList().add(cgClass);

        {
            final List<String> listDesc = cgClass.getLangDoc()
                    .getDescriptionList();

            listDesc.add("blancoDbが共通的に利用するユーティリティクラス。");
            listDesc.add("");
            listDesc.add("このクラスはblancoDbが生成したソースコードで利用されます <br>");
            listDesc
                    .add("このクラスは blancoDbが生成したソースコードから利用されます。直接呼び出すことは推奨されません。");
            listDesc.add("");
            listDesc.add("@since 2006.03.02");
            listDesc.add("@author blanco Framework");
        }

        {
            boolean fIsSQLServer = false;
            final boolean IS_DEBUG = false;

            fCgSourceFile.getImportList().add(
                    BlancoDbUtil.getRuntimePackage(fDbSetting)
                            + ".exception.IntegrityConstraintException");
            fCgSourceFile.getImportList().add(
                    BlancoDbUtil.getRuntimePackage(fDbSetting)
                            + ".exception.DeadlockException");
            fCgSourceFile.getImportList().add(
                    BlancoDbUtil.getRuntimePackage(fDbSetting)
                            + ".exception.TimeoutException");
            fCgSourceFile.getImportList().add("java.sql.SQLException");

            switch (fDbSetting.getDriverName()) {
            case BlancoDbDriverNameStringGroup.SQLSERVER_2000:
            case BlancoDbDriverNameStringGroup.SQLSERVER_2005:
                fIsSQLServer = true;
                if (IS_DEBUG) {
                    System.out.println("TRACE: SQL Serverです。");
                }
                break;
            default:
                if (IS_DEBUG) {
                    System.out.println("TRACE: 非SQL Serverです。ドライバ値("
                            + fDbSetting.getDriverName() + "]");
                }
                break;
            }

            final BlancoCgMethod cgMethod = fCgFactory.createMethod(
                    "convertToBlancoException", null);
            cgClass.getMethodList().add(cgMethod);

            cgMethod.setStatic(true);

            final List<String> listDesc = cgMethod.getLangDoc()
                    .getDescriptionList();

            listDesc.add("SQL例外をblanco Framework例外オブジェクトに変換します。<br>");
            listDesc.add("");

            if (fIsSQLServer) {
                listDesc
                        .add("※Microsoft SQL Server 2000/2005用の判定を追加して生成されています。<br>");
            }
            listDesc
                    .add("SQL例外のなかで、blanco Frameworkの例外オブジェクトに変換すべきものについて変換します。<br>");
            listDesc.add("変換すべき先が無い場合には、そのまま元のオブジェクトを返却します。");

            cgMethod.getParameterList().add(
                    fCgFactory.createParameter("ex", "java.sql.SQLException",
                            "JDBCから返却された例外オブジェクト。"));
            cgMethod
                    .setReturn(fCgFactory
                            .createReturn(
                                    "java.sql.SQLException",
                                    "変換後のSQL例外オブジェクト。SQLExceptionまたはその継承クラスである IntegrityConstraintException, DeadlockException, TimeoutExceptionが戻ります。"));

            final List<String> listLine = cgMethod.getLineList();

            listLine.add("if (ex.getSQLState() != null) {");
            listLine.add("if (ex.getSQLState().startsWith(\"23\")) {");
            listLine
                    .add("final IntegrityConstraintException exBlanco = new IntegrityConstraintException(\"データベース制約違反により変更が失敗しました。\" + ex.toString(), ex.getSQLState(), ex.getErrorCode());");
            listLine.add("exBlanco.initCause(ex);");
            listLine.add("return exBlanco;");
            listLine.add("} else if (ex.getSQLState().equals(\"40001\")) {");
            listLine
                    .add("final DeadlockException exBlanco = new DeadlockException(\"データベースデッドロックにより変更が失敗しました。\" + ex.toString(), ex.getSQLState(), ex.getErrorCode());");
            listLine.add("exBlanco.initCause(ex);");
            listLine.add("return exBlanco;");
            listLine.add("} else if (ex.getSQLState().equals(\"HYT00\")) {");
            listLine
                    .add("final TimeoutException exBlanco = new TimeoutException(\"データベースタイムアウトにより変更が失敗しました。\" + ex.toString(), ex.getSQLState(), ex.getErrorCode());");
            listLine.add("exBlanco.initCause(ex);");
            listLine.add("return exBlanco;");

            if (fIsSQLServer) {
                // ロックタイムアウト固有の判定。
                // この処理は SQL Server 2000/2005においてのみ有効です。
                // SQL Server 2000/2005の場合にのみ、LockTimeoutExceptionが発生されます。
                fCgSourceFile.getImportList().add(
                        BlancoDbUtil.getRuntimePackage(fDbSetting)
                                + ".exception.LockTimeoutException");
                listLine
                        .add("} else if (ex.getSQLState().equals(\"HY000\") && ex.getErrorCode() == 1222) {");
                listLine.add("// SQL Server固有のロックタイムアウト例外コードの判定を行います。");
                listLine
                        .add("final LockTimeoutException exBlanco = new LockTimeoutException(\"データベースロックタイムアウトにより変更が失敗しました。\" + ex.toString(), ex.getSQLState(), ex.getErrorCode());");
                listLine.add("exBlanco.initCause(ex);");
                listLine.add("return exBlanco;");
            }
            listLine.add("}");
            listLine.add("}");
            listLine.add("return ex;");
        }

        {
            final BlancoCgMethod cgMethod = fCgFactory.createMethod(
                    "convertTimestampToDate", "JDBCのTimestampをDate型に変換します。");
            cgClass.getMethodList().add(cgMethod);

            cgMethod.setStatic(true);
            cgMethod.setFinal(true);
            cgMethod.getLangDoc().getDescriptionList().add(
                    "java.sql.Timestamp型からjava.util.Date型へと変換します。<br>");
            cgMethod.getLangDoc().getDescriptionList().add(
                    "このメソッドは blancoDbが生成したソースコードから利用されます。直接呼び出すことは推奨されません。");

            cgMethod.getParameterList().add(
                    fCgFactory.createParameter("argTimestamp",
                            "java.sql.Timestamp", "JDBCのTimestamp型を与えます。"));
            cgMethod.setReturn(fCgFactory.createReturn("java.util.Date",
                    "変換後のjava.util.Date型を戻します。"));

            final List<String> listLine = cgMethod.getLineList();

            listLine.add("if (argTimestamp == null) {");
            listLine.add("return null;");
            listLine.add("}");
            listLine.add("return new Date(argTimestamp.getTime());");
        }

        if (fDbSetting.getLogging()) {
            switch (fDbSetting.getLoggingMode()) {
            case BlancoDbLoggingModeStringGroup.PERFORMANCE:
            case BlancoDbLoggingModeStringGroup.SQLID:
                BlancoPerfomanceCommonUtil.addPerfomanceFieldMethod(fCgFactory,
                        fCgSourceFile, cgClass);
                break;
            }
        }

        return fCgSourceFile;
    }
}
