/*
 * blancoDb Enterprise Edition
 * 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.invoker;

import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Iterator;

import blanco.db.collector.TypeFinder;
import blanco.db.conf.BlancoDbSetting;
import blanco.db.definition.QueryInvoker;
import blanco.db.expander.implementor.BlancoDbImplementor;
import blanco.db.mapping.BlancoDbMappingUtil;
import blanco.db.properties.GenerationProperties;
import blanco.db.util.BlancoDbObjectStorage;
import blanco.db.util.BlancoDbQueryParserUtil;
import blanco.ig.expander.Type;
import blanco.ig.expander.Value;
import blanco.ig.expander.method.MethodExpander;

/**
 * @author Tosiki Iga
 */
public class SetInvokerInputParameterMethod extends MethodExpander {
    private Value _statement = null;

    private BlancoDbSetting _setting = null;

    private QueryInvoker _invoker = null;

    private GenerationProperties _properties = null;

    public SetInvokerInputParameterMethod(QueryInvoker invoker) {
        super("setInputParameter");

        _invoker = invoker;

        BlancoDbObjectStorage storage = BlancoDbObjectStorage.getInstance();
        _setting = storage.getSetting();
        _properties = storage.getGenerationProperties();
    }

    public void setupSignature() {
        addException(SQLException.class);

        Iterator i = _invoker.getParameterIterator();
        while (i.hasNext()) {
            Value value = (Value) i.next();
            addArgument(value);
            if (value.getType().getName().equals("InputStream")
                    || value.getType().getName().equals("Reader")) {
                addArgument(new Value(new Type(int.class), value.getName()
                        + "StreamLength"));
            }
        }

        if (_properties.isGenerateJavaDoc()) {
            getJavaDoc().addLine("クエリに与える入力パラメータをセットします。");

            i = _invoker.getParameterIterator();
            boolean isFirst = true;
            while (i.hasNext()) {
                if (isFirst) {
                    isFirst = false;
                    //getJavaDoc().addLine("");
                }
                Value parameter = (Value) i.next();
                String name = parameter.getName();
                getJavaDoc().addParameter(name, "'" + name + "'列の値");
            }
        }
    }

    public void implement() {
        BlancoDbImplementor i = new BlancoDbImplementor(getData());

        // statementが未確保であるばあい、強制的にprepareStatementを呼び出します。
        i.addLine("if (_statement == null) {");
        i.addStatement("prepareStatement()");
        i.addLine("}");

        _statement = getField("Statement");

        BlancoDbQueryParserUtil query = new BlancoDbQueryParserUtil(_invoker
                .getQuery());
        TypeFinder finder = new TypeFinder(_invoker.getParameterIterator());
        String parameter = "";

        Iterator ite = _invoker.getParameterIterator();
        while (ite.hasNext()) {
            // TODO: SQL文からパラメータを発見しなくてはなりません。
            // 現状、とりあえず与えられた順序で登場と仮定が加わっています。
            Value val = (Value) ite.next();

            int[] listCol = query.getSqlInputParameters(val.getName());
            if (listCol == null) {
                System.out.println("[" + _invoker.getName() + "]の SQL入力パラメータ["
                        + val.getName() + "]が結びついていません.");
                continue;
            }
            for (int iteSame = 0; iteSame < listCol.length; iteSame++) {
                int index = listCol[iteSame];
                if (BlancoDbMappingUtil.isMapWrapperClassNecessity(val
                        .getType().getName())) {
                    i.openIf(val.getName() + " == null");
                    i.addStatement("_statement.setNull("
                            + index
                            + ", "
                            + BlancoDbMappingUtil.convertJavaTypeToJdbcType(val
                                    .getType().getFullName()) + ")");
                    i.addElse();
                }

                String type = BlancoDbMappingUtil
                        .getPreparedStatementSetterMethodName(val.getType()
                                .getName());
                if (val.getType().getName().equals("Date")) {
                    i.addUsingType(new Type(Timestamp.class));
                }

                String stmtLine = "_statement."
                        + type
                        + "("
                        + index
                        + ", "
                        + BlancoDbMappingUtil.mapWrapperClassIntoPrimitive(val
                                .getName(), val.getType().getName());
                if (val.getType().getName().equals("InputStream")
                        || val.getType().getName().equals("Reader")) {
                    stmtLine += ", " + val.getName() + "StreamLength";
                }
                stmtLine += ")";
                i.addStatement(stmtLine);

                if (BlancoDbMappingUtil.isMapWrapperClassNecessity(val
                        .getType().getName())) {
                    i.closeIf();
                }

            }
        }

        if (_setting.isEnabledLogging()) {
            i.outLog(_statement);
        }
    }
}