/*
 * 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.expander.query;

import blanco.db.definition.QueryIterator;
import blanco.db.util.BlancoDbObjectStorage;
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 PrepareStatementMethod2 extends MethodExpander {
    private BlancoDbObjectStorage storage = null;

    private Value queryArgument = new Value(String.class, "query");

    private QueryIterator _iterator = null;

    public PrepareStatementMethod2(final BlancoDbObjectStorage storage,
            final QueryIterator iterator) {
        super("prepareStatement");
        this.storage = storage;
        _iterator = iterator;
    }

    public void setupSignature() {
        // 引数を追加してみる。
        addArgument(queryArgument);

        getJavaDoc().addException(new Type("java.sql.SQLException"),
                "SQL例外が発生した場合。");
        addException(new Type("java.sql.SQLException"));

        getJavaDoc().addLine("与えられたSQL文をもちいてプリコンパイルを実施(動的SQL)します。");
        getJavaDoc().addLine("");
        getJavaDoc().addLine(
                "動的に内容が変化するようなSQLを実行する必要がある場合にのみ、こちらのメソッドを利用します。<br>");
        getJavaDoc()
                .addLine(
                        "そうではない場合には、このメソッドの利用は避けて prepareStatement()メソッド (引数なし)を呼び出してください。<br>");
        getJavaDoc()
                .addLine(
                        "なぜなら、このメソッドではSQL文そのものをパラメータとして与えることができて自由度が高い一方、SQLインジェクションと呼ばれるセキュリティホールが発生する可能性を引き起こしてしまうからです。<br>");
        getJavaDoc().addLine("内部的にConnection.prepareStatementを呼び出します。<br>");

        if (_iterator == null) {
        } else if (_iterator.getScrollInterface().equals("forward_only")
                && _iterator.isEnableUpdatableInterface() == false) {
        } else {
            getJavaDoc().addLine("スクロール属性: " + _iterator.getScrollInterface());
            if (_iterator.isEnableUpdatableInterface()) {
                getJavaDoc().addLine("更新可能属性: 有効");
            }
        }

        getJavaDoc().addParameter("query",
                "プリコンパイルを実施させたいSQL文。動的SQLの場合には、この引数には加工された後の実行可能な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.addStatement("close()");

        if (_iterator == null) {
            implementor
                    .addStatement("fStatement = fConnection.prepareStatement(query)");
        } else if (_iterator.getScrollInterface().equals("forward_only")
                && _iterator.isEnableUpdatableInterface() == false) {
            // パラメータのバリエーションが単純な場合には、単純にprepareStatementを呼び出し。
            implementor
                    .addStatement("fStatement = fConnection.prepareStatement(query)");
        } else {
            String resultSetType = "ResultSet.TYPE_FORWARD_ONLY";
            String resultSetConcurrency = "ResultSet.CONCUR_READ_ONLY";
            if (_iterator.getScrollInterface().equals("insensitive")) {
                resultSetType = "ResultSet.TYPE_SCROLL_INSENSITIVE";
            } else if (_iterator.getScrollInterface().equals("sensitive")) {
                resultSetType = "ResultSet.TYPE_SCROLL_SENSITIVE";
            }
            if (_iterator.isEnableUpdatableInterface()) {
                resultSetConcurrency = "ResultSet.CONCUR_UPDATABLE";
            }
            implementor
                    .addStatement("fStatement = fConnection.prepareStatement(query, "
                            + resultSetType + ", " + resultSetConcurrency + ")");
        }

        if (storage.getSetting().getStatementTimeout() >= 0) {
            implementor.addLine("// ステートメントタイムアウト値についてデフォルト値をセットします。");
            implementor.addLine("fStatement.setQueryTimeout("
                    + storage.getSetting().getStatementTimeout() + ");");
        }
    }
}