package Organisms2.g4;

class DandelionEntity extends Entity {

    final static int my_id = 105;

    final int dist;
    final int off_duty_count;

    final int e_expand;
    final int e_spawn;
    final int e_navigate;

    int status = -1;
    boolean[] spawned = new boolean[5];


    public DandelionEntity( int[] param, int key ) {
        super( param );

        if ( key != -1 )
        {
            spawned[EAST] = ( (key & 0x1) != 0 );
            spawned[WEST] = ( (key & 0x2) != 0 );
            spawned[NORTH] = ( (key & 0x4) != 0 );
            spawned[SOUTH] = ( (key & 0x8) != 0 );
            spawned[4] = ( (key & 0x10) != 0 );            

            sethome( (int)(byte)( ( key >> 8 ) & 0xff ), 
                     (int)(byte)( ( key >> 16 ) & 0xff ) );
        }
        else
            status = -100;

        dist = 2;
        int factor = 4;
        if ( ev * 3 <= eu )
        {
            factor += factor;
            off_duty_count = ( dist + dist + 3 ) * 2;
        }
        else
        {
            off_duty_count = dist + dist + 3;
        }

        e_navigate = em - ev - ev - ev;
        e_expand = Math.min( ev * dist * ( factor + (int)( 10*Math.random() ) ),
                             em - ev - ev );
        e_spawn = Math.min( e_expand + ev * dist * (int) ( 5*Math.random() ),
                            e_navigate );
    }

    private boolean is_our_entity( int entity ) {
        return entity == my_id;
    }

    void setCloneAttr( boolean east, boolean west, boolean north, 
                       boolean south, boolean spawn, int x, int y ) {
        int ret = 0;
        if ( east )
            ret |= 0x1;
        if ( west )
            ret |= 0x2;
        if ( north )
            ret |= 0x4;
        if ( south )
            ret |= 0x8;
        if ( spawn )
            ret |= 0x10;

        setCloneAttr( ret | ((x&0xff)<<8) | ((y&0xff)<<16) );
    }

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

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

    public int action() {
        int ret;
        if ( status < -2 )
        {
            status++;
            if ( -2 == status || food() * eu > ev * 100  )
                status = 0;
            reset();
            
            ret = action_findfood();
            if ( ret >= 0 )
                return ret;
            return STAY;
        }

        if ( -2 == status )
            return STAY;

        if ( -1 == status )
        {
            if ( athome() )
            {
                status = 0;
            }
            else
            {
                ret = gohome();
                int entity = actionBlockedBy( ret );
                if ( is_our_entity( entity ) )
                {
                    status = -2;
                    return STAY;
                }
                return ret;
            }
        }

        if ( status > 0 )
            status--;

        ret = action_gohome();
        if ( ret >= 0 )
            return ret;

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

        ret = action_spawn();
        if ( ret >= 0 )
            return ret;

        ret = action_navigate();
        if ( ret >= 0 )
            return ret;

        ret = action_findfood();
        if ( ret >= 0 )
            return ret;

        return gohome();
    }

    private int action_gohome() {
        if ( athome() )
            return -1;

        if ( status > distance() )
        {
            int ret = action_findfood();
            if ( ret >= 0 )
                return ret;
        }

        return gohome();
    }

    private int action_expand( int d ) {
        if ( spawned[d] )
            return -1;

        if ( energy() >= e_expand && !hasEntity( d ) )
        {
            switch ( d )
            {
            case NORTH:
                setCloneAttr( false, false, false, true, false,
                              0, -(dist+dist-1) );
                break;
            case SOUTH:
                setCloneAttr( false, false, true, false, false,
                              0, dist+dist-1 );
                break;
            case EAST:
                setCloneAttr( false, true, true, true, false,
                              dist+dist-1, 0 );
                break;
            case WEST:
                setCloneAttr( true, false, true, true, false,
                              -(dist+dist-1), 0 );
                break;
            }

            spawned[d] = true;
            return CLONE | d;
        }

        return -1;
    }

    private int action_spawn() {
        if ( spawned[4] )
            return -1;

        if ( energy() >= e_spawn )
        {
            if ( !hasEntity( NORTH ) )
            {
                setCloneAttr( true, true, true, true, true, 
                              dist, dist-1 );
                return CLONE | NORTH;
            }
            else if ( !hasEntity( EAST ) )
            {
                setCloneAttr( true, true, true, true, true, 
                              dist-1, dist );
                return CLONE | EAST;
            }
        }

        return -1;
    }

    private int action_navigate() {

        if ( Math.random() < 0.005 )
        {
            int r = (int) ( Math.random() * 5.0 );
            if ( r > 5 )
                r = 5;
            spawned[r] = false;
        }

        return -1;
    }

    private int action_findfood() {
        int ret;
        if ( food() > 0 )
            return STAY;

        if ( distance() >= dist )
            return -1;

        ret = action_findfood( EAST );
        if ( ret >= 0 )
            return ret;
        ret = action_findfood( WEST );
        if ( ret >= 0 )
            return ret;
        ret = action_findfood( NORTH );
        if ( ret >= 0 )
            return ret;
        ret = action_findfood( SOUTH );
        if ( ret >= 0 )
            return ret;
        return -1;
    }

    private int action_findfood( int d ) {
        if ( !hungry() )
            return -1;

        if ( !hasFood( d ) )
            return -1;

        if ( status <= 0 )
            status = off_duty_count;

        return MOVE | d;
    }

    public int talk() {
        return my_id;
    }
}
