package org.maachang.rimdb.index ;

import org.maachang.rimdb.RimDbException;
import org.maachang.rimdb.util.NAdd;


/**
 * 判別検索ポインター.
 * 
 * @version 2014/06/29
 * @author  masahito suzuki
 * @since   rimdb-1.00
 */
@SuppressWarnings("unchecked")
public abstract class IfPointer<W> extends SearchPointer<Index<W>> {
    
    /** 一致行. **/
    protected int position = -1 ;
    
    /** 検索ワード. **/
    protected W word ;
    
    /** equalsフラグ. **/
    protected boolean eq ;
    
    /**
     * 情報リセット.
     * @param mode [true]を設定した場合、設定ワード条件も削除します.
     */
    public final void reset( boolean mode ) {
        super.reset( mode ) ;
        if( mode ) {
            word = null ;
        }
        position = -1 ;
    }
    
    /**
     * 情報セット.
     * @param word 対象の情報を設定します.
     */
    public void set( W word ) {
        if( word == null ) {
            throw new RimDbException( "[" + this.getClass().getName() + "]検索条件にnullは設定できません" ) ;
        }
        this.word = word ;
        this.resetFlag = false ;
    }
    
    /**
     * インデックス位置を取得.
     * @return int インデックス位置が返却されます.
     */
    public final int position() {
        return position ;
    }
    
    /**
     * 検索処理.
     * @param index 対象のインデックスを設定します.
     */
    public final void search( final Index<W> index ) {
        
        if( resetFlag ) {
            throw new RimDbException( "[" + this.getClass().getName() + "]条件が設定されていません" ) ;
        }
        
        switch( type ) {
            
            // =?
            // !=? or <>?
            case SearchPointer.TYPE_EQ :
            case SearchPointer.TYPE_NEQ :
                
                if( ( position = index.eq( word ) ) == -1 ) {
                    if( eq ) {
                        length = 0 ;
                        count = 0 ;
                    }
                    else {
                        length = index.getLength() ;
                        count = index.getMaxLine() ;
                    }
                }
                else if( eq ) {
                    length = 1 ;
                    count = index.getMaskLine( position ).length ;
                }
                else {
                    length = index.getLength() - 1 ;
                    count = index.getMaxLine() - index.getMaskLine( position ).length ;
                }
                
                break ;
                
            // >? or >=?
            case SearchPointer.TYPE_BIG :
            case SearchPointer.TYPE_BIG_EQ :
                
                if( ( position = index.big( eq,word ) ) == -1 ) {
                    length = 0 ;
                    count = 0 ;
                }
                else {
                    length = index.getLength() - position ;
                    count = index.getMaxLine() - index.getMaskLine( position ).count ;
                }
                
                break ;
                
            // <? or <=?
            case SearchPointer.TYPE_SMALL :
            case SearchPointer.TYPE_SMALL_EQ :
                
                if( ( position = index.small( eq,word ) ) == -1 ) {
                    length = 0 ;
                    count = 0 ;
                }
                else {
                    length = position ;
                    count = index.getMaskLine( position ).count + 1 ;
                }
                
                break ;
        }
        
    }
    
    /**
     * 検索結果情報をNAdd情報に格納.
     * ※この処理は、検索条件が１件の場合に利用します.
     * @param out 検索結果の行情報をNAdd情報にセットします.
     * @param index 対象のインデックスを設定します.
     */
    public final void get( final NAdd out,final Index<W> index ) {
        
        final int pos = position ;
        if( type != SearchPointer.TYPE_NEQ && pos == -1 ) {
            return ;
        }
        final int[][] indexToLine = ((Index)index).getIndexToLine() ;
        
        switch( type ) {
            // =?
            case SearchPointer.TYPE_EQ :
            {
                int[] n = indexToLine[ pos ] ;
                int len = n.length ;
                for( int i = 0 ; i < len ; i ++ ) {
                    out.add( n[ i ] ) ;
                }
            }
            break ;
            
            // >? or >=?
            case SearchPointer.TYPE_BIG :
            case SearchPointer.TYPE_BIG_EQ :
            {
                int j,lenJ ;
                int[] n ;
                final int len = ((Index)index).getLength() ;
                for( int i = pos ; i < len  ; i ++ ) {
                    n = indexToLine[ i ] ;
                    lenJ = n.length ;
                    for( j = 0 ; j < lenJ ; j ++ ) {
                        out.add( n[ j ] ) ;
                    }
                }
            }
            break ;
            
            // <? or <=?
            case SearchPointer.TYPE_SMALL :
            case SearchPointer.TYPE_SMALL_EQ :
            {
                int j,lenJ ;
                int[] n ;
                for( int i = 0 ; i <= pos ; i ++ ) {
                    n = indexToLine[ i ] ;
                    lenJ = n.length ;
                    for( j = 0 ; j < lenJ ; j ++ ) {
                        out.add( n[ j ] ) ;
                    }
                }
            }
            break ;
            
            // !=? or <>?
            case SearchPointer.TYPE_NEQ :
            {
                if( pos == -1 ) {
                    final int len = ((Index)index).getMaxLine() ;
                    for( int i = 0 ; i < len ; i ++ ) {
                        out.add( i ) ;
                    }
                }
                else {
                    int j,lenJ ;
                    int[] n ;
                    final int len = ((Index)index).getLength() ;
                    for( int i = 0 ; i < len ; i ++ ) {
                        if( i == pos ) {
                            continue ;
                        }
                        n = indexToLine[ i ] ;
                        lenJ = n.length ;
                        for( j = 0 ; j < lenJ ; j ++ ) {
                            out.add( n[ j ] ) ;
                        }
                    }
                }
            }
            break ;
            
        }
    }
    
    /** ベースコピー. **/
    protected void baseCopy( final boolean mode,final IfPointer o ) {
        super.baseCopy( mode,o ) ;
        if( !mode ) {
            o.word = word ;
            o.resetFlag = false ;
        }
        o.eq = eq ;
        o.position = -1 ;
    }
}
