/*
 * blancoDb
 * Copyright (C) 2004-2005 Yasuo Nakanishi
 * 
 * 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.iterator;

import java.util.Iterator;

import blanco.commons.util.BlancoNameAdjuster;
import blanco.db.definition.QueryField;
import blanco.db.definition.QueryIterator;
import blanco.db.expander.query.Finalize;
import blanco.db.expander.query.GetQueryMethod;
import blanco.db.expander.query.GetStatementMethod;
import blanco.db.expander.query.PrepareStatementMethod;
import blanco.db.expander.query.PrepareStatementMethod2;
import blanco.db.expander.query.QueryConstructor;
import blanco.db.expander.query.field.ConnectionField;
import blanco.db.expander.query.field.LogField;
import blanco.db.expander.query.field.ResultSetField;
import blanco.db.expander.query.field.StatementField;
import blanco.db.util.BlancoDbObjectStorage;
import blanco.ig.expander.ClassExpander;
import blanco.ig.expander.Type;

/**
 * @author Yasuo Nakanishi
 */
public class QueryIteratorClass extends ClassExpander {
    private BlancoDbObjectStorage storage = null;

    private QueryIterator _iterator = null;

    public QueryIteratorClass(final BlancoDbObjectStorage storage,
            final Type type, final QueryIterator iterator) {
        super(type);
        _iterator = iterator;
        this.storage = storage;

        getJavaDoc().addLine(type.getName() + "クラス (QueryIterator)。");
        getJavaDoc().addLine("");
        getJavaDoc().addLine("検索型SQL文をラッピングして各種アクセサを提供します。<br>");
        if (iterator.isSingle()) {
            getJavaDoc().addLine("シングル属性: 有効 (期待する処理件数は1件)<br>");
        }
        if (iterator.getScrollInterface() != null) {
            getJavaDoc().addLine(
                    "スクロール属性: " + iterator.getScrollInterface() + "<br>");
        }
        if (iterator.isEnableUpdatableInterface()) {
            getJavaDoc().addLine("更新可能属性: 有効<br>");
        }
    }

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

        // addImport(new Type(runtimePackage
        // + ".exception.IntegrityConstraintException"));

        // BlancoDbUtilは常にインポートします。
        addImport(new Type(runtimePackage + ".util.BlancoDbUtil"));

        addField(new ConnectionField());
        addField(new StatementField("java.sql.PreparedStatement"));
        addField(new ResultSetField());

        if (storage.getSetting().isLogging()) {
            addImport(new Type("org.apache.commons.logging.LogFactory"));
            addField(new LogField(getName()));
        }

        final Type _type = new Type(storage.getSetting().getRootNameSpace()
                + ".query", BlancoNameAdjuster.toClassName(_iterator.getName())
                + "Iterator");

        addMethod(new QueryConstructor(_type));

        addMethod(new GetQueryMethod(_iterator.getQuery()));

        addMethod(new PrepareStatementMethod(storage));
        addMethod(new PrepareStatementMethod2(storage, _iterator));
        // パラメータがある場合にのみ bindメソッドを生成します。
        Iterator iParameter = _iterator.getInParameterIterator();
        if (iParameter.hasNext()) {
            addMethod(new SetInputParameterMethod(storage, _iterator));
        }

        addMethod(new ExecuteQueryMethod(storage, _iterator));

        addMethod(new NextMethod(storage, _iterator));

        // カーソル属性がtrueの際には previousメソッドなどの
        // スクロールカーソル関連メソッドを追加生成
        // 前提: カーソル属性がtrueの場合にはシングル属性はfalse
        if (_iterator.getScrollInterface().equals("forward_only") == false) {
            addMethod(new PreviousMethod(storage, _iterator));
            addMethod(new FirstMethod(storage, _iterator));
            addMethod(new LastMethod(storage, _iterator));

            addMethod(new AbsoluteMethod(storage, _iterator));
            addMethod(new RelativeMethod(storage, _iterator));
        }

        final Type rowObjectType = new Type(storage.getSetting()
                .getRootNameSpace()
                + ".row", BlancoNameAdjuster.toClassName(_iterator.getName())
                + "Row");

        addMethod(new GetRowMethod(storage, rowObjectType, _iterator));

        addMethod(new GetStatementMethod(storage, false));

        addMethod(new GetResultSetMethod(storage));

        if (_iterator.isSingle()) {
            addMethod(new GetSingleRowMethod(storage, rowObjectType, _iterator));
        }

        if (_iterator.isSingle() == false) {
            addMethod(new GetListMethod(_iterator));
        }

        // 更新可能属性の場合にのみの生成です。
        if (_iterator.isEnableUpdatableInterface()) {
            // 検索結果の列の数だけ、updateメソッドを生成
            boolean isAllFieldReadOnly = true;
            Iterator fieldIterator = _iterator.getFieldIterator();
            QueryField field = null;
            while (fieldIterator.hasNext()) {
                field = (QueryField) fieldIterator.next();

                // ResultSetMetaDataが Writableであれば それ以上は条件を加えずにメソッドを生成します。
                if (field.getWritable()) {
                    addMethod(new UpdateObjectMethod(storage, _iterator, field));
                    isAllFieldReadOnly = false;
                }
            }
            if (isAllFieldReadOnly == false) {
                addMethod(new UpdateRowMethod(storage, _iterator));
            }
        }

        addMethod(new CloseMethod(storage));

        addMethod(new Finalize(storage, getName()));
    }
}