/*
 * blancoDb
 * Copyright (C) 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.util.method;

import blanco.db.collector.BlancoDbDatabaseConnection;
import blanco.db.util.BlancoDbObjectStorage;
import blanco.ig.expander.Scope;
import blanco.ig.expander.Type;
import blanco.ig.expander.Value;
import blanco.ig.expander.implementor.Implementor;
import blanco.ig.expander.method.MethodExpander;

/**
 * @author tosiki iga
 */
public class ConvertToBlancoExceptionMethod extends MethodExpander {
    private static final boolean IS_DEBUG = false;

    /**
     * 生成対象がSQL Server であるかどうかを判断するフラグ。
     */
    private boolean fIsSQLServer = false;

    protected Scope getScope() {
        return Scope.PUBLIC;
    }

    protected boolean isStatic() {
        return true;
    }

    public ConvertToBlancoExceptionMethod(final BlancoDbObjectStorage storage) {
        super("convertToBlancoException");

        // ランタイムパッケージの変化に対応。
        String runtimePackage = storage.getSetting().getRootNameSpace();
        if (storage.getSetting().getRuntimePackage() != null) {
            runtimePackage = storage.getSetting().getRuntimePackage();
        }

        final Type integrityConstraintException = new Type(runtimePackage
                + ".exception.IntegrityConstraintException");
        addUsingType(integrityConstraintException);

        final Type deadlockException = new Type(runtimePackage
                + ".exception.DeadlockException");
        addUsingType(deadlockException);

        final Type timeoutException = new Type(runtimePackage
                + ".exception.TimeoutException");
        addUsingType(timeoutException);

        addUsingType(new Type("java.sql.SQLException"));

        if (BlancoDbDatabaseConnection.DRIVERNAME_SQLSERVER_2000.equals(storage
                .getSetting().getDriverName())
                || BlancoDbDatabaseConnection.DRIVERNAME_SQLSERVER_2005
                        .equals(storage.getSetting().getDriverName())) {
            fIsSQLServer = true;
            if (IS_DEBUG) {
                System.out.println("TRACE: SQL Serverです。");
            }
        } else {
            if (IS_DEBUG) {
                System.out.println("TRACE: 非SQL Serverです。ドライバ名["
                        + storage.getSetting().getDriverName() + "]");
            }
        }
    }

    public void setupSignature() {
        getJavaDoc().addLine("SQL例外をblanco Framework例外オブジェクトに変換します。<br>");
        getJavaDoc().addLine("");
        if (fIsSQLServer) {
            getJavaDoc().addLine(
                    "※Microsoft SQL Server 2000/2005用の判定を追加して生成されています。<br>");
        }
        getJavaDoc().addLine(
                "SQL例外のなかで、blanco Frameworkの例外オブジェクトに変換すべきものについて変換します。<br>");
        getJavaDoc().addLine("変換すべき先が無い場合には、そのまま元のオブジェクトを返却します。");
        getJavaDoc().addParameter("ex", "JDBCから返却された例外オブジェクト。");
        addArgument(new Value(new Type("java.sql.SQLException"), "ex"));
        getJavaDoc()
                .addReturn(
                        "変換後のSQL例外オブジェクト。SQLExceptionまたはその継承クラスである IntegrityConstraintException, DeadlockException, TimeoutExceptionが戻ります。");
        setReturnType(new Type("java.sql.SQLException"));
    }

    public void implement() {
        final Implementor implementor = new Implementor(getData());

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

        if (fIsSQLServer) {
            implementor
                    .addLine("} else if (ex.getSQLState().equals(\"HY000\") && ex.getErrorCode() == 1222) {");
            implementor.addLine("// SQL Server固有の例外コードの判定を行います。");
            implementor
                    .addLine("final TimeoutException exBlanco = new TimeoutException(\"データベースタイムアウトにより変更が失敗しました。\" + ex.toString(), ex.getSQLState(), ex.getErrorCode());");
            implementor.addLine("exBlanco.initCause(ex);");
            implementor.addLine("return exBlanco;");
        }
        implementor.addLine("}");
        implementor.addLine("}");
        implementor.addLine("return ex;");
    }
}