package Organisms2.g4;

class OctopusEntity extends Entity {
    int d_expand;                  // the direction to expand
    int level;                     // the level in the family tree
    int branch_level;              // the level since the last branch
    int e_canclone, e_mustclone;
    int status;
    boolean branchable = false;

    int[] state_count = new int[4];

    final int max_state_count = 16;
    final int off_duty_count;
    final double prob_branch = 0.99;
    final int dist_branch = 3;
    final double prob_ex_branch = 0.0001;

    public OctopusEntity( int[] param, int legacy ) {
        super( param );

        int factor = 4;
        if ( ev * 3 <= eu )
            factor = 10;
        
        e_canclone = Math.min( ev * factor, (em-eu)/2 );
        e_mustclone = Math.min( ev * 2 * factor, (em-eu)/3 );

        if ( legacy == -1 )
        {
            d_expand = -1;
            level = 0;
            branch_level = 0;
        }
        else
        {
            d_expand = legacy & 0x3;
            level = legacy >> 8;
            branch_level = ( legacy >> 2 ) & 0x3f;

            if ( branch_level == (dist_branch+1)/2 )
            {
                e_canclone = Math.min( e_canclone*4, em-eu*3 );
                e_mustclone = Math.min( e_mustclone*4, em-eu*2 );
            }

            if ( branch_level > dist_branch && 
                 Math.random() < prob_branch )
            {
                branchable = true;
                branch_level = 0;
            }
        }

        if ( eu > 5*ev )
            off_duty_count = 3;
        else if ( eu > 3*ev )
            off_duty_count = Math.max( 3, ev/2 );
        else
            off_duty_count = Math.max( 3, ev );

        status = 0;

        if ( d_expand < 0 )
            status = -Math.min( em/2, 40 + off_duty_count * 10 );
    }

    private void setCloneAttr( int d, int bl, int level ) {
        setCloneAttr( ( d & 0x3 ) | ( (bl&0x3f)<<2 ) 
                      | ( (level & 0xffff) << 8 ) );
    }

    private void recount_d( int d ) {
        if ( hasEntity( d ) )
            state_count[d] = max_state_count;
        else if ( state_count[d] > 0 )
            state_count[d]--;
    }

    private void recount() {
        recount_d( EAST );
        recount_d( WEST );
        recount_d( NORTH );
        recount_d( SOUTH );
    }

    private final int rootaction_d( int dir ) {
        if ( energy() < e_canclone )
        {
            if ( hasFood( dir ) )
            {
                status = off_duty_count;
                return MOVE | dir;
            }

            return -1;
        }

        if ( energy() < e_mustclone )
        {
            if ( hasFood( dir ) && 0 == state_count[dir] )
            {
                setCloneAttr( dir, 1, 1 );
                return CLONE | dir;
            }

            return -1;
        }
        else if ( 0 == state_count[dir] )
        {
            setCloneAttr( dir, 1, 1 );
            return CLONE | dir;
        }

        return -1;
    }

    private final int rootaction() {
        int ret;
        ret = rootaction_d( EAST );
        if ( ret >= 0 )
            return ret;
        ret = rootaction_d( WEST );
        if ( ret >= 0 )
            return ret;
        ret = rootaction_d( NORTH );
        if ( ret >= 0 )
            return ret;
        ret = rootaction_d( SOUTH );
        if ( ret >= 0 )
            return ret;
        return STAY;
    }

    private int action_food( int d ) {
        if ( hasFood( d ) )
            return MOVE | d;
        return -1;
    }

    public int request( int d ) {
        return 0;
    }

    public void notify( int value, int d ) {
    }

    public int action() {
        recount();

        if ( status < 0 )
        {
            status++;
            reset();

            if ( food() * eu > ev * 100 )
                status = 0;
            
            if ( food() > 0 )
                return STAY;

            int ret;
            ret = action_food( EAST );
            if ( ret >= 0 )
                return ret;
            ret = action_food( WEST );
            if ( ret >= 0 )
                return ret;
            ret = action_food( NORTH );
            if ( ret >= 0 )
                return ret;
            ret = action_food( SOUTH );
            if ( ret >= 0 )
                return ret;

            return STAY;
        }

        if ( !athome() || ( d_expand < 0 && status > 0 ) )
        {
            if ( status > 0 )
                status--;

            if ( status <= distance()+1 )
                return gohome();

            if ( food() > 0 )
                return STAY;

            if ( hasFood(EAST) && hungry() )
                return MOVE | EAST;

            if ( hasFood(WEST) && hungry() )
                return MOVE | WEST;

            if ( hasFood(NORTH) && hungry() )
                return MOVE | NORTH;

            if ( hasFood(SOUTH) && hungry() )
                return MOVE | SOUTH;

            if ( !hungry() )
                return gohome();

            return STAY;
        }

        if ( d_expand < 0 )
            return rootaction();

        if ( status > 0 )
            status = 0;

        int left = turnLeft( d_expand );
        int right = turnRight( d_expand );
        int back = turnBack( d_expand );

        if ( energy() > e_canclone || hasFood( d_expand ) )
        {
            if ( 0 == state_count[d_expand] )
            {
                setCloneAttr( d_expand, branch_level+1, level+1 );
                return CLONE | d_expand;
            }
            else if ( 0 == state_count[back] )
            {
                setCloneAttr( d_expand, 0, level+1 );
                return CLONE | back;
            }
        }

        if ( food() > 0 )
            return STAY;

        if ( hasFood( left ) && hungry() )
        {
            status = off_duty_count;
            return MOVE | left;
        }
        if ( hasFood( right ) && hungry() )
        {
            status = off_duty_count;
            return MOVE | right;
        }

        if ( energy() >= e_mustclone && 
             ( branchable || Math.random() < prob_ex_branch ) )
        {
            // branchable = false;
            if ( Math.random() >= 0.5 )
            {
                if ( !hasEntity( left ) )
                {
                    setCloneAttr( left, 0, level+1 );
                    return CLONE | left;
                }
            }
            else
            {
                if ( !hasEntity( right ) )
                {
                    setCloneAttr( right, 0, right+1 );
                    return CLONE | right;
                }
            }
        }

        return STAY;
    }
}
