package org.maachang.mimdb.core;

import org.maachang.mimdb.MimdbException;
import org.maachang.mimdb.core.impl.SqlAnalyzer;

/**
 * Mimdbクエリー要素.
 * 
 * @version 2013/10/14
 * @author masahito suzuki
 * @since MasterInMemDB 1.00
 */
public class MimdbQuery {
    
    /** クエリー情報. **/
    private QueryInfo info = null ;
    
    /** コンパイル済みオブジェクト. **/
    private MimdbQueryPrepared compile = null ;
    
    /** オフセット位置. **/
    private int offset = -1 ;
    
    /** リミット位置. **/
    private int limit = -1 ;
    
    /**
     * コンストラクタ.
     */
    public MimdbQuery() {
        
    }
    
    /**
     * コンストラクタ.
     * @param info 対象のQueryInfoを設定します.
     * @exception Exception 例外.
     */
    public MimdbQuery( QueryInfo info ) throws Exception {
        this.create( info ) ;
    }
    
    /** デストラクタ. **/
    protected void finalize() throws Exception {
        clear() ;
    }
    
    /**
     * SQL文を指定して、MimdbStmtを生成.
     * @param sql 対象のSQL文を設定します.
     * @return MimdbQuery ステートメントオブジェクトが返却されます.
     * @exception Exception 例外.
     */
    public static final MimdbQuery create( String sql ) throws Exception {
        MimdbQuery ret = new MimdbQuery() ;
        create( ret,sql ) ;
        return ret ;
    }
    
    /**
     * SQL文を指定して、MimdbStmtを生成.
     * @param out MimdbStmtオブジェクトを設定します.
     * @param sql 対象のSQL文を設定します.
     * @exception Exception 例外.
     */
    public static final void create( MimdbQuery out,String sql ) throws Exception {
        QueryInfo info = new QueryInfo() ;
        SqlAnalyzer.analysis( info,sql ) ;
        out.create( info ) ;
    }
    
    /**
     * SQL文を指定して、MimdbPreparedを生成.
     * @param sql 対象のSQL文を設定します.
     * @return MimdbQuery ステートメントオブジェクトが返却されます.
     * @exception Exception 例外.
     */
    public static final MimdbQueryPrepared createPrepared( String sql ) throws Exception {
        MimdbQueryPrepared ret = new MimdbQueryPrepared() ;
        createPrepared( ret,sql ) ;
        return ret ;
    }
    
    /**
     * SQL文を指定して、MimdbPreparedを生成.
     * @param out MimdbStmtオブジェクトを設定します.
     * @param sql 対象のSQL文を設定します.
     * @exception Exception 例外.
     */
    public static final void createPrepared( MimdbQueryPrepared out,String sql ) throws Exception {
        out.create( createCompile( sql ) ) ;
    }
    
    /**
     * SQL文を指定して、MimdbPreparedを生成.
     * @param out MimdbStmtオブジェクトを設定します.
     * @param sql 対象のSQL文を設定します.
     * @exception Exception 例外.
     */
    protected static final QueryCompileInfo createCompile( String sql ) throws Exception {
        QueryInfo info = new QueryInfo() ;
        QueryCompileInfo ret = new QueryCompileInfo() ;
        SqlAnalyzer.analysis( info,sql ) ;
        QueryCompile.compile( ret,info,MimdbTableManager.getInstance() ) ;
        return ret ;
    }
    
    /**
     * QueryInfoを設定.
     * @param table 対象のQueryInfoを設定します.
     * @exception Exception 例外.
     */
    public void create( QueryInfo info ) throws Exception {
        if( info == null ) {
            throw new MimdbException( "QueryInfoが定義されていません" ) ;
        }
        this.clear() ;
        this.info = info ;
    }
    
    /**
     * 情報クリア.
     */
    public void clear() {
        if( info != null ) {
            info.clear() ;
            info = null ;
        }
        compile = null ;
        offset = -1 ;
        limit = -1 ;
    }
    
    /**
     * オブジェクトがクリアーされているかチェック.
     * @return boolean [true]の場合、クリアされています.
     */
    public boolean isClear() {
        return info == null ;
    }
    
    /** チェック処理. **/
    protected final void check() {
        if( info == null ) {
            throw new MimdbException( "オブジェクトはクリアされています" ) ;
        }
    }
    
    /**
     * テーブル名を取得.
     * @return String テーブル名が返却されます.
     */
    public String getName() {
        check() ;
        return info.name ;
    }
    
    /**
     * QueryInfoを取得.
     * @return QueryInfoが返却されます.
     */
    public QueryInfo getInfo() {
        check() ;
        return info ;
    }
    
    /**
     * コンパイルを実施させずに、クエリー実行.
     * @return MimdbResult 実行結果が返却されます.
     * @exception Exception 例外.
     */
    public MimdbResult executeQuery() throws Exception {
        check() ;
        if( compile == null || compile.isClear() ) {
            MimdbQueryPrepared c = new MimdbQueryPrepared() ;
            compile( c ) ;
            if( c.getInfo().preparedParamsSize > 0 ) {
                throw new MimdbException( "パラメータが必要な条件なので、この処理は実行できません" ) ;
            }
            compile = c ;
        }
        compile.setOffset( offset ) ;
        compile.setLimit( limit ) ;
        offset = -1 ;
        limit = -1 ;
        return compile.executeQuery() ;
    }
    
    /**
     * オフセット、リミットのクリア.
     */
    public void clearOffset() {
        check() ;
        offset = -1 ;
        limit = -1 ;
    }
    
    /**
     * 表示オフセット値を設定.
     * この条件により、表示位置を確定できます.
     * @param off 表示オフセット値を設定します.
     *            [-1]が設定された場合、表示幅は確定されません.
     * @return MimdbQuery このオブジェクトが返却されます.
     */
    public MimdbQuery setOffset( int off ) {
        check() ;
        offset = off ;
        return this ;
    }
    
    /**
     * 表示リミット値を設定.
     * この条件により、表示位置を確定できます.
     * @param limit 表示リミット値を設定します.
     *            [-1]が設定された場合、表示幅は確定されません.
     * @return MimdbQuery このオブジェクトが返却されます.
     */
    public MimdbQuery setLimit( int limit ) {
        check() ;
        this.limit = limit ;
        return this ;
    }
    
    /**
     * コンパイル処理.
     * @param out プリコンパイル済みオブジェクトを設定します.
     * @exception Exception 例外.
     */
    public void compile( MimdbQueryPrepared out ) throws Exception {
        check() ;
        QueryCompileInfo cinfo = new QueryCompileInfo() ;
        QueryCompile.compile( cinfo,info,MimdbTableManager.getInstance() ) ;
        out.create( cinfo ) ;
    }
    
    /**
     * コンパイル処理.
     * @return MimdbQueryPrepared プリコンパイル済みオブジェクトが返却されます.
     * @exception Exception 例外.
     */
    public MimdbQueryPrepared compile() throws Exception {
        check() ;
        MimdbQueryPrepared ret = new MimdbQueryPrepared() ;
        compile( ret ) ;
        return ret ;
    }
    
    /**
     * 現在のコンパイル結果オブジェクトを取得.
     * @return MimdbQueryPrepared コンパイルされているオブジェクトが返却されます.
     */
    public MimdbQueryPrepared getCompile() {
        check() ;
        return compile ;
    }
    
}

