import java.awt.*;
import java.util.Random;

/**
  @author       Heinze, Pausch, Robl
  @version      1.0
 */

public class Microbe
{
  /** current energy value of this microbe */
  private int energy;
  /** energyloss per step */
  private int energyloss;
  /** local reference to the playfield where this microbe "lives" */
  private PlayField playfield;

  /** old movement direction of this microbe */
  private int olddir;

  /** x- and y-position of the microbe */
  private int xp, yp;
  /** current movement direction for this microbe */
  private int dx, dy;
  /** the microbe's brain: the food-energy-storage */
  private int colorscore[]=new int[16];
  /** random generator for all random calculations needed for the microbe */
  private Random rnd=new Random();

  /**
  * calculates a positive random value in the rango of 0 to n-1
  * @param n upper limit for calculation
  */
  private int random(int n)
  {
    if (n<=0)
      return 0;
    int r=rnd.nextInt();
    if (r<0) r*=-1;
    return r%n;
  }

  /**
  * helpermethod - calculates dx and dy from dir
  * @param dir direction number
  */
  private void direction(int dir)
  {
    int x, y;
    for(y=-1; y<2; y++)
    {
      for(x=-1; x<2; x++)
      {
        if (x!=0 || y!=0)
        {
          if (dir==0)
          {
            dx=x;
            dy=y;
            return;
          }
          dir--;
        }
      }
    }
  }

  /**
  * creates a new microbe
  * @param pf playfield where this microbe "lives"
  * @param x x startposition
  * @param y y startposition
  * @param start_energy startenergy
  * @param start_energyloss energy loss per step
  */
  public Microbe(PlayField pf, int x, int y, int start_energy, int start_energyloss)
  {
    rnd.setSeed(rnd.nextInt()+(y*1234)+(x*9876)+(x*y)); // init the random generator (seed) by the current time and the microbes position

    playfield=pf;
    olddir=random(8);
    direction(olddir);

    for(int i=0; i<16; i++)
      colorscore[i]=0;

    Food f=new Food(Food.TYPE_BORDER);
    colorscore[f.gettype()]=f.getenergy(); // microbe *must* know: border is *immediate* death!!

    energy=start_energy;
    energyloss=start_energyloss;
    xp=x;
    yp=y;
  }

  /**
  * returns the current energy level of this microbe
  * @return energy level
  */
  public int getenergy()
  {
    return energy;
  }

  /**
  * sets the energy level to a new value
  * @param new_energy new energy level
  */
  public void setenergy(int new_energy)
  {
    energy=new_energy;
  }

  /**
  * returns the energy loss per step
  * @return energy loss per step
  */
  public int getenergyloss()
  {
    return energyloss;
  }

  /**
  * sets the energy loss per step to a new value
  * @param new_energyloss energyloss per step
  */
  public void setenergyloss(int new_energyloss)
  {
    energyloss=new_energyloss;
  }

  /**
  * returns the current x position of the microbe
  * @return x position
  */
  public int getx()
  {
    return xp;
  }

  /**
  * returns the current y position of the microbe
  * @return y position
  */
  public int gety()
  {
    return yp;
  }

  /**
  * calculates one microbe-step <br>
  * the microbe analyzes the surrounding food and runs into the direction which has the
  * best energy value; the microbe learns new energy values and divides into two microbes
  * if it reaches the energy limit of 1000 (each microbe gets the half of the old microbe energy)
  * @return true: microbe is alive / false: microbe is dead
  */
  boolean step()
  {
    int i, x, y;
    int m=colorscore[playfield.getfoodtype(xp+dx, yp+dy)];
    int wa[]=new int[9], wz=0;
    boolean ex=false;

    // evaluate the surrounding pixels, search for the best energy value and store it to m
    for(y=-1; y<2; y++)
      for(x=-1; x<2; x++)
        if (x!=0 || y!=0)
        {
          i=colorscore[playfield.playfield[xp+x][yp+y].gettype()];
          if (i>m) m=i;
        }

    // store all direction with the same value as m  in the direction-storage wa
    for(i=0, y=-1; y<2; y++)
      for(x=-1; x<2; x++)
        if (x!=0 || y!=0)
        {
          if (colorscore[playfield.playfield[xp+x][yp+y].gettype()]==m)
            wa[wz++]=i;
          i++;
        }

    // If the food in the direction of the old movement direction has also the best energy value,
    // the microbe shall go on in the old direction; now and then, a new movement direction
    // will be selected by random
    if (colorscore[playfield.playfield[xp+dx][yp+dy].gettype()]==m && wz>1)
    {
      for(i=0; i<wz; i++)
      {
        if (wa[i]==olddir)
        {
          ex=true;
          if (random(2+(1000-energy)/80)==0)  // select only relatively rarely a new direction
          {                                   // here: the less energy, the more rarely
            for(; i<wz-1; i++)
              wa[i]=wa[i+1];
            ex=false;
          }
          break;
        }
      }
    }

    // shouldn't until now a new direction haven't been selected, select one of the best
    // directions by random
    if (wz>0 && !ex)
      direction(wa[random(wz)]);

    xp+=dx; yp+=dy; // apply the movement direction to the microbe's position

    i=playfield.playfield[xp][yp].gettype(); // get the food type on the new position
    colorscore[i]=playfield.playfield[xp][yp].getenergy(); // and store in the "brain" the energy value
    energy+=colorscore[i]-energyloss; // the food energy value influences the microbe's energy value (+ energy loss per step!)

    playfield.playfield[xp][yp].clear(); // the food gets "eaten"

    if (energy>=1000)
    { // the microbe divides into two microbes if it reaches the energy limit of 1000
      energy/=2;
      playfield.new_microbe(xp, yp, energy, energyloss);
      return true; // microbe is still alive
    }
    else if (energy>0)
    {
      return true; // microbe is still alive
    }

    return false; // microbe is dead
  }

  /**
  * returns the "color" of this microbe, the "color" depends on its current energy level
  * @return "color" value in the range from 0 to 255
  */
  public int getcolor()
  {
    int col=(energy*255)/1000;
    if (col<0) col=0;
    if (col>255) col=255;
		return col;
  }
}

