/*
 * blanco Framework
 * Copyright (C) 2004-2005 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.expander.query.caller;

import java.util.Iterator;

import blanco.db.definition.QueryCallerDotNet;
import blanco.db.mapping.BlancoDbMappingUtilDotNet;
import blanco.db.util.BlancoDbObjectStorageDotNet;
import blanco.db.util.BlancoDbQueryParserUtilDotNet;
import blanco.ig.expander.IgType;
import blanco.ig.expander.IgValue;
import blanco.ig.expander.implementor.Implementor;
import blanco.ig.expander.method.MethodExpander;

/**
 * @author tosiki iga
 */
public class PrepareCallMethod2DotNet extends MethodExpander {
    BlancoDbObjectStorageDotNet storage = null;

    private QueryCallerDotNet _caller = null;

    private IgValue queryArgument = new IgValue(new IgType("string"), "query");

    public PrepareCallMethod2DotNet(final BlancoDbObjectStorageDotNet storage,
            final QueryCallerDotNet caller) {
        super("PrepareCall");
        this.storage = storage;
        _caller = caller;

        addUsingType(new IgType("System.Data.SqlDbType"));
    }

    public void setupSignature() {
        // 引数を追加してみる。
        addArgument(queryArgument);
        getJavaDoc().addLine("クエリのプリコンパイルを実施します。");
        getJavaDoc().addLine("動的に内容が変化するようなSQLを実行する必要がある場合にのみ、こちらのメソッドを利用します。");
        getJavaDoc()
                .addLine(
                        "※SQL文そのものをパラメータとして与えることができて自由度が高い一方、SQLインジェクションと呼ばれるセキュリティホールが発生する危険がある点に注意した上で利用してください。");
        getJavaDoc().addLine("内部的には SqlCommandオブジェクトを新規作成します。");
        getJavaDoc().addParameter("query", "利用したいクエリ(SQL文)");
    }

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

        if (storage.getSetting().isLogging()) {
            implementor.addLine("if (fLog.isDebugEnabled()) {");
            implementor.addLine("fLog.debug(\"" + getName()
                    + ": query = \" + query);");
            implementor.addLine("}");
            implementor.addLine("");
        }

        implementor.addLine("Close();");

        implementor.addLine("fStatement = new SqlCommand();");
        implementor.addLine("fStatement.Connection = fConnection;");
        implementor.addLine("fStatement.Transaction = fTransaction;");
        implementor.addLine("fStatement.CommandText = query;");

        // ポイント: fStatement.CommandType = CommandType.StoredProcedure
        // を指定すると希望する動作にはなりません。

        final BlancoDbQueryParserUtilDotNet query = new BlancoDbQueryParserUtilDotNet(
                _caller.getQuery());

        final Iterator ite = _caller.getOutParameterIterator();
        for (int index = 1; ite.hasNext(); index++) {
            // 現状、とりあえず与えられた順序で登場と仮定が加わっています。
            final IgValue val = (IgValue) ite.next();

            implementor.addLine("");
            implementor.addLine("// SQL出力パラメータ[" + val.getName() + "]を設定します。");
            final String stmtLine = "SqlParameter sqlOutParameter"
                    + index
                    + " = new SqlParameter(\"@"
                    + val.getName()
                    + "\", "
                    + BlancoDbMappingUtilDotNet.convertJavaTypeToJdbcType(val
                            .getType().getFullName()) + ");";
            implementor.addLine(stmtLine);
            implementor.addLine("sqlOutParameter" + index
                    + ".Direction = ParameterDirection.Output;");

            if (val.getType().getName().equals("string")) {
                implementor.addLine("// string型は期待するサイズを8000とします。");
                implementor
                        .addLine("sqlOutParameter" + index + ".Size = 8000;");
            }

            implementor.addLine("fStatement.Parameters.Add(sqlOutParameter"
                    + index + ");");
        }
    }
}