import ddf.minim.signals.*;
import ddf.minim.*;
import ddf.minim.analysis.*;
import ddf.minim.effects.*;

//TODO:
//score
//sounds
//death
//pre/post screen


//code liberally stolen from http://processing.org/learning/topics/follow3.html
//so thanks Keith Peters

float SNAKEHEADSIZE = 18;
float DUDESIZE = 5;
float APPLESIZE = 10;

float segx[] = new float[15];
float segy[] = new float[15];
float segLength = 9;

float dudeChance = 0;

float dudeSpeedRange = 2;
HashSet dudes = new HashSet();
HashSet apples = new HashSet();

int TITLE=0;
int PLAY=1;
int DEAD=2;

boolean applesgone = false;

AudioSnippet hooray;
AudioSnippet chomp[] = new AudioSnippet[5];

int gamerun = TITLE;

int score;

void setup() {
  size(200, 200);
  Minim.start(this);
  textFont(loadFont("BlackadderITC-Regular-30.vlw"),30);
  textAlign(CENTER);
  smooth(); 
  strokeWeight(5);
  ellipseMode(CENTER);
  hooray =  Minim.loadSnippet("hooray.mp3");
  for(int i = 0; i < chomp.length; i++){
     chomp[i] =  Minim.loadSnippet(i+".mp3");
  }

}

void mouseClicked(){
  if(gamerun == TITLE || gamerun == DEAD){

    startGame();
  } 
}

void stop()
{
  hooray.close();
    for(int i = 0; i < chomp.length; i++){
     chomp[i].close();
  }
  super.stop();
}


void startGame(){
  dudeChance = 40;
  dudes.clear();
  apples.clear();
  apples.add(new apple(100,70,0,-1));
  apples.add(new apple(70,130,-.5,.5));
  apples.add(new apple(130,130,.5,.5));
  addDude();
  gamerun = 1;
  score = 0;
  applesgone = false;

}
float mx,my;

void draw() {
  if(gamerun == TITLE){
    fill(0);
    text("DRAGGIN",100,40);
    text("save thine apples",100,80);
    text("and thy ass",100,110);
    text("from yon villagers",100,140);
    text("(clickest to play)",100,180);
    return; 
  }


  if(dudes.size()==0||random(40)< 1){
    addDude(); 
    if(dudeChance > 5){
      dudeChance -= .1; 

    }
    dudeSpeedRange += .01;
  }

  if(gamerun != DEAD){
    mx = mouseX; 
    my = mouseY;  
  }

  background(226);
  if(gamerun != DEAD){
    stroke(0,128,0, 100);
    fill(0,128,0, 100);
  } 
  else {
    stroke(0,20,0, 100);
    fill(0,40,0, 100);

  }
  dragSegment(0, mx, my);

  for(int i=0; i<segx.length-1; i++) {
    dragSegment(i+1, segx[i], segy[i]);
  }

  ellipse(mx,my,SNAKEHEADSIZE,SNAKEHEADSIZE);



  Iterator it = dudes.iterator();
  while(it.hasNext()){

    dude d = (dude)it.next();
    d.move();

    if(farOffscreen(d.x,d.y,30)){
      it.remove(); 
    }

    //does dragon bit person
    if(gamerun == PLAY && circlesOverlap(mouseX,mouseY,SNAKEHEADSIZE/2+2,d.x,d.y,DUDESIZE/2+2)){
      if(d.mode==MODERUNAPPLE){
        d.targetapple.carrier = null; //no one carrying now!
      }
      it.remove();
      int sfx = int(random(chomp.length));
       chomp[sfx].rewind();      chomp[sfx].play();
      if(! applesgone){
        score++;
      }
    }
    //does person hit dragon
    //if(d.mode == MODEFIGHT){
    for(int i=0; i<segx.length-1; i++) {
      if(circlesOverlap(segx[i],segy[i],0,d.x,d.y,DUDESIZE/2+3)){
        if(gamerun != DEAD){
          hooray.rewind();
          hooray.play();
        }
        gamerun = DEAD;

      }
    }
    //}
    if(d.mode==MODEGETAPPLE){
      if(circlesOverlap(d.targetapple.x,d.targetapple.y,APPLESIZE/2+3,d.x,d.y,DUDESIZE/2+3)){
        d.escapeWithApple();

        d.targetapple.carrier = d;
        d.targetapple.offsetx = d.targetapple.x - d.x;
        d.targetapple.offsety = d.targetapple.y - d.y;

      }
    }

    d.draw();
  }

  boolean allApplesGone = true;
  Iterator ait = apples.iterator();
  while(ait.hasNext()){
    apple a = (apple)ait.next();
    if(a.carrier != null){
      a.x = a.carrier.x + a.offsetx; 
      a.y = a.carrier.y + a.offsety;
    }
    if(! (farOffscreen(a.x,a.y,20))){
      allApplesGone = false;       
    } 
    else {
      if(a.offscreen == false){
        a.offscreen = true;
        hooray.rewind();
        hooray.play(); 
      }

    }
    a.draw();
  }
  if(allApplesGone){
    applesgone = true;
  }
  String and = "";
  if(gamerun == DEAD){
    fill(0,200);
    text("THOU ART",100,70);   
    text("SLAIN",100,100);
    text(and+"(clickest to replay)",100,180);
    and = "and ";
  }
  if(applesgone){
    fill(0,200);
    text(and+"all thine apples",100,130); 
    text("are stolen",100,150);
  }


  fill(0,100);
  text(score,100,15);

}

boolean circlesOverlap(float x1,float y1, float r1,float x2,float y2, float r2){
  return  sqrt(pow(x1-x2,2) + pow(y1-y2,2)) <= r1+r2;


}


void dragSegment(int i, float xin, float yin) {
  float dx = xin - segx[i];
  float dy = yin - segy[i];
  float angle = atan2(dy, dx);  
  segx[i] = xin - cos(angle) * segLength;
  segy[i] = yin - sin(angle) * segLength;
  segment(segx[i], segy[i], angle);
}

void segment(float x, float y, float a) {
  pushMatrix();
  translate(x, y);
  rotate(a);
  line(0, 0, segLength, 0);
  popMatrix();
}

int MODEFIGHT = 0;
int MODEGETAPPLE = 1;
int MODERUNAPPLE = 2;

class dude{
  float x,y,xs,ys;
  int mode;
  apple targetapple = null;
  int dragontarget = 0; 

  dude(float px,float py,float pxs,float pys, int pmode){
    x = px; 
    y = py; 
    xs=pxs;
    ys=pys;
    mode = pmode;
    if(mode == MODEGETAPPLE){
      int r = int(random(apples.size()));
      targetapple = (apple)apples.toArray()[r];
    }
  }

  void move(){
    if(mode == MODEFIGHT){

      if(random(10)< 5){
        if(x < segx[dragontarget] ){
          xs+=.1; 
        } 
        else {
          xs -= .1; 
        }
        if(y < segy[dragontarget]){
          ys+=.1; 
        } 
        else {
          ys -= .1; 
        }
        xs *= .9;
        ys *= .9;
      }
      x += xs; 
      y += ys; 

    }
    if(mode == MODEGETAPPLE){
      if(random(10)< 5){
        if(x < targetapple.x){
          xs+=.1; 
        } 
        else {
          xs -= .1; 
        }
        if(y < targetapple.y){
          ys+=.1; 
        } 
        else {
          ys -= .1; 
        }
        xs *= .9;
        ys *= .9;
      }
      x += xs; 
      y += ys; 

    }
    if(mode == MODERUNAPPLE){
      x += xs;
      y += ys; 
    }

  }

  void escapeWithApple(){
    mode=MODERUNAPPLE;
    xs = targetapple.gox;
    ys = targetapple.goy;
  }

  void draw(){
    stroke(0,0,0, 100);
    fill(0,0,0, 100);
    ellipse(x,y,DUDESIZE,DUDESIZE) ;
  }

}

void addDude(){
  //every dude is launched  from one of the 4 walls
  float posOnWall = random(200);
  float mainSpeed = random(dudeSpeedRange);
  //speed parallel to wall
  float lateralSpeed = random(dudeSpeedRange);
  if(posOnWall > 100){
    lateralSpeed *= -1; 
  } 
  float x=0,y=0, xs=0,ys=0;
  int r =   int(random(4));
  if(r == 0){ //leftwall
    x = -5;
    y = posOnWall;
    xs = mainSpeed;
    ys = lateralSpeed;
  }
  if(r == 1){ //rightwall
    x = 200+5;
    y = posOnWall;
    xs = -1*mainSpeed;
    ys = lateralSpeed;
  }
  if(r == 2){ //topwall
    x = posOnWall;
    y = -5;
    xs = lateralSpeed;
    ys = mainSpeed;
  }
  if(r == 3){ //topwall
    x = posOnWall;
    y = 200+5;
    xs = lateralSpeed;
    ys = -1* mainSpeed;
  }


  dude d = new dude(x,y,xs,ys,int(random(2)));
  //make sure guy isn't going for offscreen apple
  if(d.targetapple != null && farOffscreen(d.targetapple.x,d.targetapple.y,30)){
    d.mode = MODEFIGHT;
  } 
  if(d.mode == MODEFIGHT){
    //target is a random segment on dragon
    d.dragontarget = int(random(segx.length)); 
  }
  dudes.add(d);
}

boolean farOffscreen(float x, float y, float far){
  if (x < -far || x > 200+far || y < -far || y > 200+far){
    return true;
  } 
  return false;
}


class apple{
  dude carrier = null;
  boolean offscreen = false;
  float offsetx, offsety;
  float x,y;
  float gox,goy;
  apple(float px,float py, float pgox, float pgoy){
    x = px; 
    y = py; 
    gox = pgox;
    goy = pgoy;
  }


  void draw(){
    stroke(255,0,0, 100);
    fill(255,0,0, 100);
    ellipse(x,y,APPLESIZE,APPLESIZE) ;
    stroke(0,255,0,100);
    line(x+1,y-APPLESIZE,x+1,y-APPLESIZE);
  }
}