/*
 * PackedThreeOptionFlags.java
 *
 * Created on 24 July 2004, 10:59
 */
package org.bodington.util;



/**
 * This was invented for use with MCQResponse database record so that 5
 * true/false/dont knows can be packed into one byte storage in a way that
 * maps 5 true/false options in the same format as before. Combinations of
 * flags that have one or more 'dont know' values are mapped so that one or
 * more of the upper three bits are set.
 * @author  Administrator
 */
public class PackedThreeOptionFlags
{
    
    static int[] lookup_table=null;
    static int[] reverse_lookup_table=null;
    
    int flags;

    /** sets up lookup tables so that flag sets that don't contain
     * third options are stored as simple one bit per flag format */
    private static synchronized void init()
    {
        lookup_table = new int[243];
        reverse_lookup_table = new int[243];
        int indices[] = new int[5];
        int i;
        boolean binary;
        
        int[] temp = lookup_table;
        
        int value;
        int binary_value=0;
        int tertiary_value=32;
        int input=0;
        for ( indices[4]=0; indices[4]<3; indices[4]++ )
            for ( indices[3]=0; indices[3]<3; indices[3]++ )
                for ( indices[2]=0; indices[2]<3; indices[2]++ )
                    for ( indices[1]=0; indices[1]<3; indices[1]++ )
                        for ( indices[0]=0; indices[0]<3; indices[0]++ )
                        {
                            // binary set of flags?
                            binary=true;
                            for ( i=0; i<5; i++ )
                                binary = binary && (indices[i]<2);
                                
                            lookup_table[input++] = binary?binary_value++:tertiary_value++;
                        }
        
        // do reverse look up
        for ( value=0; value<243; value++ )
        {
            for ( i=0; i<243; i++ )
                if ( lookup_table[i] == value )
                {
                    reverse_lookup_table[value] = i;
                    break;
                }
        }
        
    }
    
    /** Creates a new instance of FlagTest */
    public PackedThreeOptionFlags()
    {
        flags=0;
    }
    
    public byte getPackedFlags()
    {
        if ( lookup_table == null )
            init();
        return (byte)lookup_table[flags];
    }
    
    public void setPackedFlags( byte f )
    {
        if ( reverse_lookup_table == null )
            init();
        flags = reverse_lookup_table[((int)f)&0xff];
    }
    
    public int getFlag( int index )
    {
        int i, power=1;
        if ( index<0 || index>4 )
            throw new IndexOutOfBoundsException( "Flag index out of bounds: " + index );
        int working_flags = flags;
        for ( i=0; i<index; i++ )
            power *= 3;
        return (working_flags/power) % 3;
    }
    
    public void setFlag( int index, int value )
    {
        int i, power=1;
        
        if ( index<0 || index>4 )
            throw new IndexOutOfBoundsException( "Flag index out of bounds: " + index );
        if ( value<0 || value>2 )
            throw new IndexOutOfBoundsException( "Flag value out of bounds: " + value );
        
        int working_flags = flags;
        for ( i=0; i<index; i++ )
            power *= 3;
        
        flags =
        (
            // flags above the one indexed
            ((working_flags/(power*3))*(power*3)) +
            // plus value in question
            (value*power) +
            //plus flags below the one indexed
            (working_flags%power)
        );        
    }
} 
