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

import blanco.db.definition.QueryIterator;
import blanco.db.util.BlancoDbObjectStorage;
import blanco.ig.expander.Scope;
import blanco.ig.expander.Type;
import blanco.ig.expander.Value;
import blanco.ig.expander.implementor.Implementor;
import blanco.ig.expander.method.MethodExpander;

/**
 * カーソル属性がtrueの場合に、このメソッドは作成されます。
 * 
 * @author Tosiki Iga
 */
public class RelativeMethod extends MethodExpander {
    private BlancoDbObjectStorage storage = null;

    private QueryIterator _iterator = null;

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

    /**
     * シングル属性が有効である場合には protectedとします。
     */
    protected Scope getScope() {
        if (_iterator.isSingle()) {
            return Scope.PROTECTED;
        } else {
            return Scope.PUBLIC;
        }
    }

    public void setupSignature() {
        setReturnType(new Type(boolean.class));

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

        final Type deadlockException = new Type(runtimePackage
                + ".exception.DeadlockException");
        getJavaDoc().addException(deadlockException, "データベースデッドロックが発生した場合。");
        addException(deadlockException);

        final Type timeoutException = new Type(runtimePackage
                + ".exception.TimeoutException");
        getJavaDoc().addException(timeoutException, "データベースタイムアウトが発生した場合。");
        addException(timeoutException);

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

        getJavaDoc().addParameter("rows",
                "現在の行から移動する相対行数を指定します。正の数ではカーソルを順方向に移動し、負の数ではカーソルを逆方向に移動します。");
        addArgument(new Value(int.class, "rows"));

        getJavaDoc().addLine("カーソルを結果セットの相対行数だけ移動します。");
        getJavaDoc().addLine("");
        if (_iterator.isSingle()) {
            getJavaDoc().addLine("シングル属性が有効なのでスコープをprotectedとします。<br>");
        }
        getJavaDoc().addLine("relative(1)はnext()を呼び出すのと同じです。<br>");
        getJavaDoc().addLine("relative(-1)はprevious()を呼び出すのと同じです。<br>");
        getJavaDoc().addReturn("新しい現在の行が有効な場合はtrue、それ以上の行がない場合はfalse。");
    }

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

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

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

        implementor.addLine("");
        implementor.addLine("try {");
        implementor.addLine("return fResultSet.relative(rows);");
        implementor.addLine("} catch (SQLException ex) {");
        implementor.addLine("throw BlancoDbUtil.convertToBlancoException(ex);");
        implementor.addLine("}");
    }
}