/*
 * 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;

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.util.BlancoDbUtil;
import blanco.db.common.valueobject.BlancoDbSetting;

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

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

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

    private BlancoDbSetting fDbSetting = null;

    public BlancoDbUtilClassDotNet(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が生成したソースコードで利用されます。");
            listDesc
                    .add("このクラスは blancoDbが生成したソースコードから利用されます。直接呼び出すことは推奨されません。");
            listDesc.add("");
            listDesc.add("@since 2006.06.30");
            listDesc.add("@author blanco Framework");
        }

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

            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例外オブジェクトに変換してスローします。");
            listDesc.add("");
            listDesc
                    .add("SQL例外のなかで、blanco Frameworkの例外オブジェクトに変換すべきものについてIntegrityConstraintException, DeadlockException, TimeoutExceptionに変換の上 throw します。");
            listDesc.add("変換すべき先が無い場合には、そのまま元のオブジェクトを返却します。");

            cgMethod.getParameterList().add(
                    fCgFactory.createParameter("ex",
                            "System.Data.SqlClient.SqlException",
                            "ADO.NETから返却された例外オブジェクト。"));
            cgMethod.setReturn(fCgFactory.createReturn(
                    "System.Data.SqlClient.SqlException",
                    "もとのSQL例外オブジェクト。ここまで到達した場合には、変換の必要が無かったことを示します。"));

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

            listLine.add("if (ex.Number == 2627) {");
            listLine
                    .add("IntegrityConstraintException exBlanco = new IntegrityConstraintException(\"データベース制約違反により変更が失敗しました。\" + ex.ToString() + \"、Number=\" + ex.Number, ex);");
            listLine.add("throw exBlanco;");
            listLine.add("} else if (ex.Number == 1205) {");
            listLine
                    .add("// デッドロック発生をSQLServerが検知した際に発生する例外。デフォルトでは、デッドロック検知は5秒おき。");
            listLine
                    .add("DeadlockException exBlanco = new DeadlockException(\"データベースデッドロックによりデータベース操作が失敗しました。\" + ex.ToString() + \"、Number=\" + ex.Number, ex);");
            listLine.add("throw exBlanco;");
            listLine.add("} else if (ex.Number == 1222) {");
            listLine
                    .add("// ロック待ちがロックタイムアウトの時間を越えて発生した場合のタイムアウト。デフォルトはタイムアウトなし。");
            listLine
                    .add("TimeoutException exBlanco = new TimeoutException(\"データベースロック待ちのタイムアウトによりデータベース操作が失敗しました。\" + ex.ToString() + \"、Number=\" + ex.Number, ex);");
            listLine.add("throw exBlanco;");
            listLine.add("} else if (ex.Number == -2) {");
            listLine
                    .add("// コマンドのタイムアウト。SqlCommand.CommandTimeoutにて設定。デフォルトは30秒。");
            listLine
                    .add("TimeoutException exBlanco = new TimeoutException(\"コマンドタイムアウトによりデータベース操作が失敗しました。\" + ex.ToString() + \"、Number=\" + ex.Number, ex);");
            listLine.add("throw exBlanco;");
            listLine.add("}");
            listLine.add("return ex;");
        }

        return fCgSourceFile;
    }
}
