package org.maachang.rimdb.index ;


/**
 * 結果情報のリストをソート.
 * 
 * @version 2014/07/15
 * @author  masahito suzuki
 * @since   rimdb-1.00
 */
public final class ResultSort {
    protected ResultSort() {}
    
    /** 件数処理ソート. **/
    protected static final int CHANGE_SORT = 64 ;
    
    /** ソート対象データ. **/
    protected int[] rows ;
    protected int length ;
    
    /** ソート条件. **/
    protected boolean[] desc ;
    protected SortComparable[] sortInfo ;
    
    /**
     * コンストラクタ.
     * @param rows ソート対象行データを設定します.
     * @param length ソート対象行数を設定します.
     * @param desc ソート条件[true]の場合は降順、[false]の場合は昇順のリストを設定します.
     * @param comparable ソート条件を設定します.
     */
    public ResultSort( int[] rows,int length,boolean[] desc,SortComparable[] sortInfo ) {
        this.rows = rows ;
        this.length = length ;
        this.desc = desc ;
        this.sortInfo = sortInfo ;
    }
    
    /**
     * データ件数を取得.
     * @return int データ件数が返却されます.
     */
    public final int length() {
        return length ;
    }
    
    /**
     * 行配列を取得.
     * @return int[] 行配列が返却されます.
     */
    public final int[] getRows() {
        return rows ;
    }
    
    /**
     * 行情報を取得.
     * @param no 対象の項番を設定します.
     * @return int 行情報が返却されます.
     */
    public final int get( final int no ) {
        return rows[ no ] ;
    }
    
    /**
     * ソート処理.
     */
    public final void sort() {
        
        // 一定以上の件数の場合は、TIMソート.
        if( length > CHANGE_SORT ) {
            
            ResultTimSort.sort( this,0,length ) ;
        }
        // 一定以下の件数の場合は、挿入コムソート.
        else {
            
            csort( this,0,length ) ;
        }
    }
    
    /**
     * swap.
     * @param a スワップ元を設定します.
     * @param b スワップ先を設定します.
     */
    protected final void swap( final int a,final int b ) {
        final int n = rows[ a ] ;
        rows[ a ] = rows[ b ] ;
        rows[ b ] = n ;
    }
    
    /**
     * 比較処理.
     * @param src 比較元を設定します.
     * @param dest 比較先を設定します.
     * @return int 比較結果が返却されます.
     */
    protected final int comparable( final int src,final int dest ) {
        return raw( rows[ src ],rows[ dest ] ) ;
    }
    
    /**
     * 直接比較処理.
     * @param rawSrc 比較元の値を直接設定します.
     * @param rawDest 比較先の値を直接設定します.
     * @return int 比較結果が返却されます.
     */
    protected final int raw( final int rawSrc,final int rawDest ) {
        if( rawSrc == rawDest ) {
            return 0 ;
        }
        int n ;
        final int len = desc.length ;
        for( int i = 0 ; i < len ; i ++ ) {
            
            // 降順.
            if( desc[ i ] ) {
                if( ( n = sortInfo[ i ].comparable( rawDest,rawSrc ) ) != 0 ) {
                    return n ;
                }
            }
            // 昇順.
            else if( ( n = sortInfo[ i ].comparable( rawSrc,rawDest ) ) != 0 ) {
                return n ;
            }
            
        }
        return 0 ;
    }
    
    /** 挿入コムソート. **/
    protected static final void csort( final ResultSort list,final int fromIndex,final int toIndex ) {
        // 比較的件数が少ない場合に呼び出される.
        
        int i,j,k,t ;
        int gap = toIndex - fromIndex ;
        while( gap > 20 ) {
            gap = (int)(gap / 1.37 ) ;
            if( gap == 9 || gap == 10 ) {
                gap = 11 ;
            }
            for( i = fromIndex ; i + gap < toIndex ; i ++ ) {
                if( list.comparable( i + gap,i ) < 0 ) {
                    list.swap( i,i + gap ) ;
                }
            }
        }
        
        final int[] rows = list.rows ;
        for( i = fromIndex + 1 ; i < toIndex ; i ++ ) {
            t = rows[ i ] ;
            j = i ; k = i ;
            if( list.raw( t,rows[ fromIndex ] ) < 0 ) {
                while( fromIndex < j ) {
                    rows[ j ] = rows[ --k ] ;
                    j = k ;
                }
            }
            else {
                while( list.raw( t,rows[--k] ) < 0 ) {
                    rows[ j ] = rows[ k ] ;
                    j = k ;
                }
            }
            rows[ j ] = t ;
        }
    }
    
}

