/*
 * 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.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Iterator;

import blanco.db.conf.BlancoDbSetting;
import blanco.db.conf.Logging;
import blanco.db.definition.QueryField;
import blanco.db.definition.QueryIterator;
import blanco.db.expander.log.OutLogMethod;
import blanco.db.expander.query.Finalize;
import blanco.db.generator.TypeFactory;
import blanco.db.properties.GenerationProperties;
import blanco.db.util.BlancoDbObjectStorage;
import blanco.ig.expander.ClassExpander;
import blanco.ig.expander.Type;
import blanco.ig.expander.Value;
import blanco.ig.expander.field.FieldExpander;
import blanco.ig.expander.field.PrivateField;
import blanco.ig.expander.implementor.Call;

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

    private TypeFactory _typeFactory = null;

    private QueryItratorMethodFactory _methodFactory = null;

    private QueryIterator _iterator = null;

    private GenerationProperties _properties = null;

    public QueryIteratorClass(Type type, QueryIterator iterator) {
        super(type);

        _iterator = iterator;

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

        _methodFactory = new QueryItratorMethodFactory(_iterator);

        if (_properties.isGenerateJavaDoc()) {
            getJavaDoc().addLine(type.getName() + "クラス<br>");
            getJavaDoc().addLine("QueryIteratorに属するクラスです。<br>");
            getJavaDoc().addLine("検索型SQL文をラッピングして各種アクセサを提供します。");
        }
    }

    protected void expandClassStruct() {
        if (_setting.getLogging().equals(Logging.LOG4J)) {
            Value logger = new Value(new Type("org.apache.log4j.Logger"),
                    "Logger");
            FieldExpander field = new PrivateField(logger);
            Call c = new Call(logger.getType(), "getLogger");
            c.addArgument(new Call("getClass"));
            field.setDefaultStatement(c);
            addField(field);
        }

        addField(new PrivateField(Connection.class, "Connection"));
        addField(new PrivateField(PreparedStatement.class, "Statement"));
        addField(new PrivateField(ResultSet.class, "ResultSet"));

        addMethod(_methodFactory.createConstructor());

        addMethod(_methodFactory.createGetQuery(_iterator.getQuery()));

        addMethod(_methodFactory.createPrepareStatement());
        addMethod(_methodFactory.createPrepareStatement2());
        if (_iterator.getScrollInterface().equals("forward_only") == false
                || _iterator.isEnableUpdatableInterface()) {
            addMethod(_methodFactory.createPrepareStatementCursor());
        }
        // パラメータがある場合にのみ bindメソッドを生成します。
        Iterator iParameter = _iterator.getParameterIterator();
        if (iParameter.hasNext()) {
            addMethod(_methodFactory.createSetInputParameter());
        }

        addMethod(_methodFactory.createExecuteQuery());

        addMethod(_methodFactory.createNext());

        // カーソル属性がtrueの際には previousメソッドなどの
        // スクロールカーソル関連メソッドを追加生成
        // 前提: カーソル属性がtrueの場合にはsingle属性はfalse
        if (_iterator.getScrollInterface().equals("forward_only") == false) {
            addMethod(_methodFactory.createPrevious());
            addMethod(_methodFactory.createFirst());
            addMethod(_methodFactory.createLast());

            addMethod(_methodFactory.createAbsolute());
            addMethod(_methodFactory.createRelative());
        }

        addMethod(_methodFactory.createGetRow());

        addMethod(_methodFactory.createGetResultSet());

        if (_iterator.isSingle()) {
            addMethod(_methodFactory.createGetSingleRow());
        }

        if (_iterator.isSingle() == false) {
            addMethod(_methodFactory.createGetList());
        }

        // 更新可能属性の場合にのみの生成です。
        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(_methodFactory.createUpdateObject(field));
                    isAllFieldReadOnly = false;
                }
            }
            if (isAllFieldReadOnly == false) {
                addMethod(_methodFactory.createUpdateRow());
            }
        }

        addMethod(_methodFactory.createClose());

        if (_setting.getLogging().equals(Logging.LOG4J)) {
            addMethod(new OutLogMethod());
        }

        addMethod(new Finalize());

        if (_setting.isSupportOldVersionTableGateway()) {
            // これ以降は 以前のバージョンとの互換性確保のために準備
            addMethod(_methodFactory.createGetAsObject());

            if (!_iterator.isSingle()) {
                addMethod(_methodFactory.createGetAsList());
            }
        }
    }
}