package org.maachang.rimdb.index.comparable ;

import org.maachang.rimdb.RimDbException;
import org.maachang.rimdb.index.Index;
import org.maachang.rimdb.index.IndexUtil;
import org.maachang.rimdb.util.NAdd;

/**
 * Comparable(比較可能なJavaオブジェクト)インデックス.
 * 
 * @version 2014/07/04
 * @author  masahito suzuki
 * @since   rimdb-1.00
 */
@SuppressWarnings("unchecked")
public final class ComparableIndex extends Index<Comparable> {
    
    /** インデックス情報. **/
    private final Comparable[] index ;
    
    /**
     * コンストラクタ.
     * @param index 対象のインデックスを設定します.
     * @param line 対象の行情報を設定します.
     * @param max 全体長を設定します.
     */
    public ComparableIndex( Comparable[] index,int[][] line,int max ) {
        super( line,max ) ;
        this.index = index ;
    }
    
    /**
     * インデックス情報を取得.
     * @return Comparable[] インデックス情報が返却されます.
     */
    public Comparable[] getIndex() {
        return index ;
    }
    
    /**
     * 一致検索.
     * @param key 対象のキーを設定します.
     * @return int インデックス番号が返却されます.
     */
    public final int eq( final Comparable key ) {
        return IndexUtil.search( index,key ) ;
    }
    
    /**
     * 大なり検索.
     * @param eq 一致を許可する場合には[true]をセットします.
     * @param key 対象のキーを設定します.
     * @return int インデックス番号が返却されます.
     */
    public final int big( final boolean eq,final Comparable key ) {
        if( index[ index.length-1 ].compareTo( key ) == -1 ) {
            return -1 ;
        }
        else if( eq ) {
            return IndexUtil.searchBS( true,index,key ) ;
        }
        else {
            int n = IndexUtil.searchBS( true,index,key ) ;
            if( key.compareTo( index[ n ] ) == 0 && (++n) >= maxLine ) {
                return -1 ;
            }
            return n ;
        }
    }
    
    /**
     * 小なり検索.
     * @param eq 一致を許可する場合には[true]をセットします.
     * @param key 対象のキーを設定します.
     * @return int インデックス番号が返却されます.
     */
    public final int small( final boolean eq,final Comparable key ) {
        if( index[ 0 ].compareTo( key ) == 1 ) {
            return -1;
        }
        else if( eq ) {
            return IndexUtil.searchBS( false,index,key ) ;
        }
        else {
            int n = IndexUtil.searchBS( false,index,key ) ;
            if( key.compareTo( index[ n ] ) == 0 && (--n) < 0 ) {
                return -1 ;
            }
            return n ;
        }
    }
    
    /**
     * between検索.
     * @param out 格納行情報を設定します.
     * @param start 開始値を設定します.
     * @param end 終了値を設定します.
     * @return boolean [true]の場合、範囲取得に成功しました.
     */
    public final boolean between( final int[] out,Comparable start,Comparable end ) {
        if( start.compareTo( end ) == 1 ) {
            Comparable n = start ;
            start = end ;
            end = n ;
        }
        out[ 0 ] = IndexUtil.searchBS( true,index,start ) ;
        out[ 1 ] = IndexUtil.searchBS( false,index,end ) ;
        
        final int f = index[ out[ 0 ] ].compareTo( start ) ;
        final int e = index[ out[ 1 ] ].compareTo( end ) ;
        return ( f >= 0 || e >= 0 ) && ( f <= 0 || e <= 0 ) ;
    }
    
    /**
     * 部分一致検索.
     * @param result 一致行情報を格納するListオブジェクトを設定します.
     * @param key 対象のLike条件を設定します.
     */
    public final void like( final NAdd result,String key ) {
        throw new RimDbException( "ComparableではLikeはサポートされていません" ) ;
    }
}

