package org.maachang.mimdb.core.impl ;

import org.maachang.mimdb.core.ResultArray;

/**
 * フラグリスト.
 * 
 * @version 2013/10/27
 * @author masahito suzuki
 * @since MasterInMemDB 1.00
 */
public abstract class AbstractSmallFlags implements Flags {
    
    /** 書換最小デフォルト値. **/
    protected static final int MIN_DEF = Integer.MAX_VALUE ;
    
    /** 最大管理データ数. **/
    protected int max ;
    
    /** フラグ管理情報. **/
    protected int[][] flags ;
    
    /**
     * 情報破棄.
     */
    public void destroy() {
        flags = null ;
        max = 0 ;
    }
    
    /**
     * 管理情報をクリア.
     */
    public final void clear() {
        flags = new int[ flags.length ][] ;
    }
    
    /**
     * Andモード取得.
     * @return boolean [true]の場合、ANDモードです.
     */
    public abstract boolean isAnd() ;
    
    /**
     * 指定位置のフラグをON.
     * @param no 対象の項番を設定します.
     */
    public abstract void add( final int no ) ;
    
    /**
     * 指定位置のフラグをON.
     * @param array 対象の項番群を設定します.
     */
    public abstract void addArray( final int[] array ) ;
    
    /**
     * 指定位置のフラグを設定.
     * @param no 対象の項番を設定します.
     * @param f フラグ条件を設定します.
     *          [0]がOFF、[1]がONです.
     */
    public abstract void set( final int no,final int f ) ;
    
    /**
     * 指定位置のフラグを設定.
     * @param array 対象の項番群を設定します.
     * @param f フラグ条件を設定します.
     *          [0]がOFF、[1]がONです.
     */
    public abstract void setArray( final int[] array,final int f ) ;
    
    /**
     * 全てのフラグをONに設定.
     */
    public abstract void all() ;
    
    /**
     * 対象の条件をマージ.
     * @param f マージ対象のオブジェクトを設定します.
     */
    public abstract void marge( final Flags f ) ;
    
    /**
     * 指定位置のフラグを取得.
     * @param no 対照の項番を設定します.
     * @return int フラグ条件が返却されます.
     *          [0]がOFF、[1]がONです.
     */
    public final int get( final int no ) {
        final int[] ff ;
        
        // ブロック位置条件が存在する場合のみ、情報取得.
        if( ( ff = flags[ no >> 10 ] ) != null ) {
            
            // フラグ条件を返却.
            final int n = no & 0x3ff ;
            return ( ff[ n >> 5 ] & ( 1 << ( n & 0x1f ) ) ) >> ( n & 0x1f ) ;
        }
        // ブロック位置条件が存在しない場合は0を返却.
        return 0 ;
    }
    
    /**
     * 最大データ数を取得.
     * @return int データ数が返却されます.
     */
    public final int max() {
        return max ;
    }
    
    /**
     * フラグがONの件数を取得.
     * @return int フラグがONの件数が返却されます.
     */
    public final int size() {
        int j,k,n,c,ret ;
        int[] ff ;
        ret = 0 ;
        
        final int[][] f = flags ;
        final int len = flags.length - 1 ;
        
        for( int i = 0 ; i < len ; i ++ ) {
            if( ( ff = f[ i ] ) != null ) {
                for( j = 0 ; j < BLOCK_INNER_SIZE ; j ++ ) {
                    if( ( n = ff[ j ] ) != 0 ) {
                        
                        // ビット数のONの合計を取得.
                        n = (n & 0x55555555) + (n >> 1 & 0x55555555);
                        n = (n & 0x33333333) + (n >> 2 & 0x33333333);
                        n = (n & 0x0f0f0f0f) + (n >> 4 & 0x0f0f0f0f);
                        n = (n & 0x00ff00ff) + (n >> 8 & 0x00ff00ff);
                        ret += (n & 0x0000ffff) + (n >>16 & 0x0000ffff);
                        
                    }
                }
            }
        }
        
        // 最終ブロック処理.
        final int mx = max - 32 ;
        if( ( ff = f[ len ] ) != null ) {
            for( j = 0 ; j < BLOCK_INNER_SIZE ; j ++ ) {
                if( ( n = ff[ j ] ) != 0 ) {
                    
                    // 今回の処理で最大値を越える検出が行われる場合.
                    if( ( ( len << 10 ) | ( j << 5 ) ) >= mx ) {
                        c = ( len << 10 ) | ( j << 5 ) ;
                        for( k = 0 ; k < 32 ; k ++ ) {
                            
                            // 対象条件で長さを越える検出の場合.
                            if( ( c | k ) >= max ) {
                                return ret ;
                            }
                            if( ( n & ( 1 << k ) ) != 0 ) {
                                ret ++ ;
                            }
                        }
                    }
                    // ON条件が存在する場合.
                    else {
                        // ビット数のONの合計を取得.
                        n = (n & 0x55555555) + (n >> 1 & 0x55555555);
                        n = (n & 0x33333333) + (n >> 2 & 0x33333333);
                        n = (n & 0x0f0f0f0f) + (n >> 4 & 0x0f0f0f0f);
                        n = (n & 0x00ff00ff) + (n >> 8 & 0x00ff00ff);
                        ret += (n & 0x0000ffff) + (n >>16 & 0x0000ffff);
                    }
                    
                }
                // 最大数を越えるが、フラグが全OFFの場合.
                else if( (( len << 10 ) | ( j << 5 )) >= mx ) {
                    return ret ;
                }
            }
        }
        return ret ;
    }
    
    /**
     * 検索結果情報を取得.
     * @param out 対象のオブジェクトが設定されます.
     * @return int 取得件数が返却されます.
     */
    public final int getResultArray( final ResultArray[] out ) {
        // 情報は存在しない.
        if( out.length == 0 ) {
            return 0 ;
        }
        
        int j,k,n,c,cnt ;
        int[] ff ;
        cnt = 0 ;
        final int[][] f = flags ;
        final int len = flags.length - 1 ;
        final int oLen = out.length ;
        
        for( int i = 0 ; i < len ; i ++ ) {
            
            if( ( ff = f[ i ] ) != null ) {
                for( j = 0 ; j < BLOCK_INNER_SIZE ; j ++ ) {
                    if( ( n = ff[ j ] ) != 0 ) {
                        c = ( i << 10 ) | ( j << 5 ) ;
                        
                        // 格納リミットの終端の可能性がある場合.
                        if( cnt + 32 >= oLen ) {
                            
                            // 全部がON条件の場合.
                            if( n == 0xffffffff ) {
                                for( k = 0 ; k < 32 ; k ++ ) {
                                    out[ cnt ++ ].no = ( c | k ) ;
                                    if( cnt == oLen ) {
                                        return cnt ;
                                    }
                                }
                            }
                            // ON条件が存在する.
                            else {
                                for( k = 0 ; k < 32 ; k ++ ) {
                                    if( ( n & ( 1 << k ) ) != 0 ) {
                                        out[ cnt ++ ].no = ( c | k ) ;
                                        if( cnt == oLen ) {
                                            return cnt ;
                                        }
                                    }
                                }
                            }
                            
                        }
                        // 全部がON条件の場合.
                        else if( n == 0xffffffff ) {
                            for( k = 0 ; k < 32 ; k ++ ) {
                                out[ cnt ++ ].no = ( c | k ) ;
                            }
                        }
                        // ON条件が存在する.
                        else {
                            for( k = 0 ; k < 32 ; k ++ ) {
                                if( ( n & ( 1 << k ) ) != 0 ) {
                                    out[ cnt ++ ].no = ( c | k ) ;
                                }
                            }
                        }
                        
                    }
                }
            }
        }
        
        // 最終ブロック処理.
        final int mx = max - 32 ;
        if( ( ff = f[ len ] ) != null ) {
            for( j = 0 ; j < BLOCK_INNER_SIZE ; j ++ ) {
                if( ( n = ff[ j ] ) != 0 ) {
                    
                    // 今回の処理で最大値を越える検出が行われる場合.
                    if( ( c = ( len << 10 ) | ( j << 5 ) ) >= mx ) {
                        if( cnt + 32 >= oLen ) {
                            
                            for( k = 0 ; k < 32 ; k ++ ) {
                                
                                // 対象条件で長さを越える検出の場合.
                                if( ( c | k ) >= max ) {
                                    return cnt ;
                                }
                                else if( ( n & ( 1 << k ) ) != 0 ) {
                                    out[ cnt ++ ].no = ( c | k ) ;
                                    if( cnt == oLen ) {
                                        return cnt ;
                                    }
                                }
                            }
                            
                        }
                        else {
                            
                            for( k = 0 ; k < 32 ; k ++ ) {
                                
                                // 対象条件で長さを越える検出の場合.
                                if( ( c | k ) >= max ) {
                                    return cnt ;
                                }
                                else if( ( n & ( 1 << k ) ) != 0 ) {
                                    out[ cnt ++ ].no = ( c | k ) ;
                                }
                            }
                            
                        }
                    }
                    // 格納リミットの終端の可能性がある場合.
                    else if( cnt + 32 >= oLen ) {
                        
                        // 全部がON条件の場合.
                        if( n == 0xffffffff ) {
                            for( k = 0 ; k < 32 ; k ++ ) {
                                out[ cnt ++ ].no = ( c | k ) ;
                                if( cnt == oLen ) {
                                    return cnt ;
                                }
                            }
                        }
                        // ON条件が存在する.
                        else {
                            for( k = 0 ; k < 32 ; k ++ ) {
                                if( ( n & ( 1 << k ) ) != 0 ) {
                                    out[ cnt ++ ].no = ( c | k ) ;
                                    if( cnt == oLen ) {
                                        return cnt ;
                                    }
                                }
                            }
                        }
                    }
                    // 全部がON条件の場合.
                    else if( n == 0xffffffff ) {
                        for( k = 0 ; k < 32 ; k ++ ) {
                            out[ cnt ++ ].no = ( c | k ) ;
                        }
                    }
                    // ON条件が存在する.
                    else {
                        for( k = 0 ; k < 32 ; k ++ ) {
                            if( ( n & ( 1 << k ) ) != 0 ) {
                                out[ cnt ++ ].no = ( c | k ) ;
                            }
                        }
                    }
                    
                }
                // 最大数を越えるが、フラグが全OFFの場合.
                else if( (( len << 10 ) | ( j << 5 )) >= mx ) {
                    return cnt ;
                }
            }
        }
        
        return cnt ;
    }
    
    /**
     * 検索結果情報を取得.
     * @param out 対象のオブジェクトが設定されます.
     * @param off 対象のオフセット値を設定します.
     * @return int 取得件数が返却されます.
     */
    public final int getResultArray( final ResultArray[] out,final int off ) {
        // 情報は存在しない.
        if( out.length == 0 ) {
            return 0 ;
        }
        else if( off <= 0 ) {
            return getResultArray( out ) ;
        }
        
        int j,k,n,c,cnt,pos,npos,code ;
        int[] ff ;
        pos = 0 ;
        cnt = 0 ;
        final int[][] f = flags ;
        final int len = flags.length - 1 ;
        final int oLen = out.length ;
        
        for( int i = 0 ; i < len ; i ++ ) {
            
            if( ( ff = f[ i ] ) != null ) {
                for( j = 0 ; j < BLOCK_INNER_SIZE ; j ++ ) {
                    if( ( n = ff[ j ] ) != 0 ) {
                        
                        // オフセット以前の条件の場合.
                        if( pos < off ) {
                            
                            // フラグ数を計算して、オフセット値を超えるかチェックする.
                            code = n ;
                            code = (code & 0x55555555) + (code >> 1 & 0x55555555);
                            code = (code & 0x33333333) + (code >> 2 & 0x33333333);
                            code = (code & 0x0f0f0f0f) + (code >> 4 & 0x0f0f0f0f);
                            code = (code & 0x00ff00ff) + (code >> 8 & 0x00ff00ff);
                            npos = (code & 0x0000ffff) + (code >>16 & 0x0000ffff);
                            
                            // オフセット値を超えない場合.
                            if( npos + pos < off ) {
                                pos += npos ;
                                continue ;
                            }
                        }
                        // オフセット値を越えている場合.
                        else {
                            
                            c = ( i << 10 ) | ( j << 5 ) ;
                            
                            // 格納リミットの終端の可能性がある場合.
                            if( cnt + 32 >= oLen ) {
                                
                                // 全部がON条件の場合.
                                if( n == 0xffffffff ) {
                                    for( k = 0 ; k < 32 ; k ++ ) {
                                        out[ cnt ++ ].no = ( c | k ) ;
                                        if( cnt == oLen ) {
                                            return cnt ;
                                        }
                                    }
                                }
                                // ON条件が存在する.
                                else {
                                    for( k = 0 ; k < 32 ; k ++ ) {
                                        if( ( n & ( 1 << k ) ) != 0 ) {
                                            out[ cnt ++ ].no = ( c | k ) ;
                                            if( cnt == oLen ) {
                                                return cnt ;
                                            }
                                        }
                                    }
                                }
                                
                            }
                            // 全部がON条件の場合.
                            else if( n == 0xffffffff ) {
                                for( k = 0 ; k < 32 ; k ++ ) {
                                    out[ cnt ++ ].no = ( c | k ) ;
                                }
                            }
                            // ON条件が存在する.
                            else {
                                for( k = 0 ; k < 32 ; k ++ ) {
                                    if( ( n & ( 1 << k ) ) != 0 ) {
                                        out[ cnt ++ ].no = ( c | k ) ;
                                    }
                                }
                            }
                            
                            continue ;
                        }
                        
                        // オフセットの半ばの場合.
                        c = ( i << 10 ) | ( j << 5 ) ;
                        
                        // 格納リミットの終端の可能性がある場合.
                        if( cnt + 32 >= oLen ) {
                            
                            // 全部がON条件の場合.
                            if( n == 0xffffffff ) {
                                for( k = 0 ; k < 32 ; k ++ ) {
                                    if( ( pos += 1 ) > off ) {
                                        out[ cnt ++ ].no = ( c | k ) ;
                                        if( cnt == oLen ) {
                                            return cnt ;
                                        }
                                    }
                                }
                            }
                            // ON条件が存在する.
                            else {
                                for( k = 0 ; k < 32 ; k ++ ) {
                                    if( ( n & ( 1 << k ) ) != 0 ) {
                                        if( ( pos += 1 ) > off ) {
                                            out[ cnt ++ ].no = ( c | k ) ;
                                            if( cnt == oLen ) {
                                                return cnt ;
                                            }
                                        }
                                    }
                                }
                            }
                            
                        }
                        // 全部がON条件の場合.
                        else if( n == 0xffffffff ) {
                            for( k = 0 ; k < 32 ; k ++ ) {
                                if( ( pos += 1 ) > off ) {
                                    out[ cnt ++ ].no = ( c | k ) ;
                                }
                            }
                        }
                        // ON条件が存在する.
                        else {
                            for( k = 0 ; k < 32 ; k ++ ) {
                                if( ( n & ( 1 << k ) ) != 0 ) {
                                    if( ( pos += 1 ) > off ) {
                                        out[ cnt ++ ].no = ( c | k ) ;
                                    }
                                }
                            }
                        }
                        
                    }
                }
            }
            
        }
        
        // 最終ブロック処理
        final int mx = max - 32 ;
        if( ( ff = f[ len ] ) != null ) {
            for( j = 0 ; j < BLOCK_INNER_SIZE ; j ++ ) {
                if( ( n = ff[ j ] ) != 0 ) {
                    
                    // 今回の処理で最大値を越える検出が行われる場合.
                    if( ( c = ( len << 10 ) | ( j << 5 ) ) >= mx ) {
                        
                        if( cnt + 32 >= oLen ) {
                            
                            for( k = 0 ; k < 32 ; k ++ ) {
                                
                                // 対象条件で長さを越える検出の場合.
                                if( ( c | k ) >= max ) {
                                    return cnt ;
                                }
                                else if( ( n & ( 1 << k ) ) != 0 ) {
                                    if( ( pos += 1 ) > off ) {
                                        out[ cnt ++ ].no = ( c | k ) ;
                                        if( cnt == oLen ) {
                                            return cnt ;
                                        }
                                    }
                                }
                            }
                            
                        }
                        else {
                            
                            for( k = 0 ; k < 32 ; k ++ ) {
                                
                                // 対象条件で長さを越える検出の場合.
                                if( ( c | k ) >= max ) {
                                    return cnt ;
                                }
                                else if( ( n & ( 1 << k ) ) != 0 ) {
                                    if( ( pos += 1 ) > off ) {
                                        out[ cnt ++ ].no = ( c | k ) ;
                                    }
                                }
                            }
                            
                        }
                    }
                    // 格納リミットの終端の可能性がある場合.
                    else if( cnt + 32 >= oLen ) {
                        
                        // 全部がON条件の場合.
                        if( n == 0xffffffff ) {
                            for( k = 0 ; k < 32 ; k ++ ) {
                                if( ( pos += 1 ) > off ) {
                                    out[ cnt ++ ].no = ( c | k ) ;
                                    if( cnt == oLen ) {
                                        return cnt ;
                                    }
                                }
                            }
                        }
                        // ON条件が存在する.
                        else {
                            for( k = 0 ; k < 32 ; k ++ ) {
                                if( ( n & ( 1 << k ) ) != 0 ) {
                                    if( ( pos += 1 ) > off ) {
                                        out[ cnt ++ ].no = ( c | k ) ;
                                        if( cnt == oLen ) {
                                            return cnt ;
                                        }
                                    }
                                }
                            }
                        }
                        
                    }
                    // 全部がON条件の場合.
                    else if( n == 0xffffffff ) {
                        for( k = 0 ; k < 32 ; k ++ ) {
                            if( ( pos += 1 ) > off ) {
                                out[ cnt ++ ].no = ( c | k ) ;
                            }
                        }
                    }
                    // ON条件が存在する.
                    else {
                        for( k = 0 ; k < 32 ; k ++ ) {
                            if( ( n & ( 1 << k ) ) != 0 ) {
                                if( ( pos += 1 ) > off ) {
                                    out[ cnt ++ ].no = ( c | k ) ;
                                }
                            }
                        }
                    }
                    
                }
                // 最大数を越えるが、フラグが全OFFの場合.
                else if( (( len << 10 ) | ( j << 5 )) >= mx ) {
                    return cnt ;
                }
            }
        }
        
        return cnt ;
    }
}
