package org.maachang.mimdb.core.impl ;

import java.io.OutputStream;

import org.maachang.mimdb.MimdbException;
import org.maachang.mimdb.core.BaseTable;
import org.maachang.mimdb.core.MimdbSearchElement;
import org.maachang.mimdb.core.MimdbSearchType;
import org.maachang.mimdb.core.util.ObjectBinary;

/**
 * [SQLAnalysis専用]メモリ検索要素情報実装.
 * 設定条件に対して、厳密チェックを行わない、単純検索要素.
 * 普通は[MSearchElement]を利用.
 * 
 * @version 2013/10/07
 * @author masahito suzuki
 * @since MasterInMemDB 1.00
 */
final class SqlSearchElement implements MimdbSearchElement {
    protected int type ;
    protected String column ;
    protected Object value ;
    protected int columnNo ;
    protected boolean preparedType ;
    
    /**
     * 検索条件を設定.
     * この条件は、括弧やand,orの条件のみが設定可能です.
     * @param type 検索条件を設定します.
     * @exception Exception 例外.
     */
    public SqlSearchElement( int type )
        throws Exception {
        this.column = null ;
        this.type = type ;
        this.value = null ;
        this.columnNo = -1 ;
        this.preparedType = false ;
    }
    
    /**
     * コンストラクタ.
     * この条件は、preparedモードで設定されます.
     * この条件は、比較カラムに対する条件指定の検索対象となります.
     * @param column 検索元のカラム名を設定します.
     * @param type 検索条件を設定します.
     * @exception Exception 例外.
     */
    public SqlSearchElement( String column,int type )
        throws Exception {
        this.column = column ;
        this.type = type ;
        this.value = null ;
        this.columnNo = -1 ;
        this.preparedType = true ;
    }
    
    /**
     * コンストラクタ.
     * この条件は、比較カラムに対する条件指定の検索対象となります.
     * @param column 検索元のカラム名を設定します.
     * @param type 検索条件を設定します.
     * @param value 検索要素を設定します.
     * @exception Exception 例外.
     */
    public SqlSearchElement( String column,int type,Object value )
        throws Exception {
        this.column = column ;
        this.type = type ;
        this.value = value ;
        this.columnNo = -1 ;
        this.preparedType = false ;
    }
    
    /**
     * 対象カラム名を取得.
     * @return String 比較対象のカラム名を取得します.
     */
    public String getColumn() {
        return column ;
    }
    
    /**
     * 検索タイプの取得.
     * @return int 検索タイプが返却されます.
     */
    public int getType() {
        return this.type ;
    }
    
    /**
     * 検索要素の取得.
     * @return Object 検索要素が返却されます.
     */
    public Object getValue() {
        return this.value ;
    }
    
    /**
     * 検索要素の設定.
     * @param v 検索要素を設定します.
     */
    public void setValue( Object v ) {
        this.value = v ;
    }
    
    /**
     * 検索条件がNULLかチェック.
     * @return boolean [true]の場合はNULLです.
     */
    public boolean isNull() {
        return this.value == null ;
    }
    
    /**
     * Preparedモードかチェック.
     * @return boolean [true]の場合、Preparedモードです.
     */
    public boolean isPrepared() {
        return preparedType ;
    }
    
    /**
     * 条件指定かチェック.
     * @return boolean [true]の場合、a=bのような条件指定です.
     */
    public boolean isWhere() {
        switch( type ) {
            case MimdbSearchType.PAR_START :
            case MimdbSearchType.PAR_END :
            case MimdbSearchType.AND :
            case MimdbSearchType.OR :
                return false ;
        }
        return true ;
    }
    
    /**
     * 条件指定かチェック.
     * @return boolean [true]の場合、and orのような条件指定です.
     */
    public boolean isAndOr() {
        switch( type ) {
            case MimdbSearchType.AND :
            case MimdbSearchType.OR :
                return true ;
        }
        return true ;
    }
    
    /**
     * オフセット、リミット条件かチェック.
     * @return boolean [true]の場合、オフセット、リミット条件です.
     */
    public boolean isOffLimit() {
        return type == MimdbSearchType.OFF_LIMIT ;
    }
    
    /**
     * カラム名を番号に変換.
     * @param table 対象のテーブルを設定します.
     * @return int カラム項番が返却されます.
     * @exception Exception 例外.
     */
    public int columnNameByNo( BaseTable table )
        throws Exception {
        // カラム名が存在する条件だけ対象とする.
        if( column != null ) {
            columnNo = table.getColumnNameByNo( column ) ;
            if( columnNo == -1 ) {
                throw new MimdbException( "テーブル[" + table.getName() + "]に、カラム名[" + column + "]は存在しません" ) ;
            }
            return columnNo ;
        }
        throw new MimdbException( "カラム名は存在しません" ) ;
    }
    
    /**
     * カラム項番を取得.
     * @return int カラム項番が返却されます.
     */
    public int getColumnNo() {
        return columnNo ;
    }
    
    /**
     * 文字列変換.
     * @return String 文字列に変換されます.
     */
    public String toString() {
        return MSearchElement.toStringStatic( type,column,value,preparedType ) ;
    }
    
    /**
     * バイナリ変換.
     * @param out 対象のOutputStreamを設定します.
     * @exception Exception 例外.
     */
    public void getOutput( OutputStream out )
        throws Exception {
        ObjectBinary.encode( out,type ) ;
        ObjectBinary.encode( out,column ) ;
        ObjectBinary.encode( out,value ) ;
        ObjectBinary.encode( out,columnNo ) ;
        ObjectBinary.encode( out,preparedType ) ;
    }
    
    /**
     * バイナリからオブジェクトを生成.
     * @param p オフセット値を保持するint[1]がセットされます.
     * @parma b 対象のバイナリを設定します.
     * @param len 対象の長さを設定します.
     * @exception Exception 例外.
     */
    public void toObject( int[] p,byte[] b,int len )
        throws Exception {
        type = (Integer)ObjectBinary.decodeBinary( p,b,len ) ;
        column = (String)ObjectBinary.decodeBinary( p,b,len ) ;
        value = ObjectBinary.decodeBinary( p,b,len ) ;
        columnNo = (Integer)ObjectBinary.decodeBinary( p,b,len ) ;
        preparedType = (Boolean)ObjectBinary.decodeBinary( p,b,len ) ;
    }
}
