tankclass tank;
HashSet enemies = new HashSet();
HashSet deadenemies = new HashSet();
HashSet badbullets = new HashSet();
boolean gameover;

int nextEnemyDue;
int nextEnemyDueReset = 300;

int score = 0;

int playerLives = 3;
void playerKilled(){
    tank.hitcolors = 100;
    playerLives --;
  if(playerLives <= 0){
    gameover = true; 

    } else {

    badbullets.clear();
    }
}

void mouseReleased(){
if(gameover){
     gameover = false; 
      enemies.clear();
      badbullets.clear();
     tank.bullets.clear();
     nextEnemyDueReset = 300;
     nextEnemyDue = nextEnemyDueReset;
      enemyStartSpeed = .1;
 chanceOfFire = 100;
 playerLives = 3;
 score = 0;
}
}


void setup(){
  size(400,400,P3D);
  rectMode(CENTER);
  tank = new tankclass();
  gameover = false;
  addEnemy();
  framerate(50);
  
  textFont(loadFont("Arial-Black-14.vlw"),14);
}

float enemyStartSpeed = .1;
float chanceOfFire = 100;

void addEnemy(){
  enemies.add(new enemyclass(enemyStartSpeed,chanceOfFire));
  if(chanceOfFire > 2){
    chanceOfFire -=3;
  }
  enemyStartSpeed += .03;



}


void keyPressed(){
  if(keyCode==37){
    tank.xs= -1;
  }
  if(keyCode==39){
    tank.xs = 1;
  }
  if(keyCode==38){
    tank.ys = -1;
  }
  if(keyCode==40){
    tank.ys = 1;
  }
  if(keyCode==32 || keyCode == 17){
    tank.fire();
  }
  // println(keyCode); 
}


float xAngle = 0;
float yAngle = 0;
float zAngle = 0;
float x=0,y=0;


void draw(){




  background(128);

  Iterator i;
  if(! gameover){
    nextEnemyDue--;
    if( nextEnemyDue <= 0){
      addEnemy();
      nextEnemyDue = nextEnemyDueReset;
      if(nextEnemyDueReset > 20) nextEnemyDueReset -= 3;
//println(nextEnemyDueReset);

    }



    tank.move();
    tank.bounds();


    i = enemies.iterator();
    while(i.hasNext()){
      enemyclass enemy  =(enemyclass) i.next();
      enemy.move();
      enemy.bounds();

      if(enemy.h >= 90){
        gameover = true; 
      }

      if(enemy.checkfire()){
        badbullets.add(new badbulletclass(enemy.x,enemy.y,enemy.h)); 
      }
    }


    i = deadenemies.iterator();
    while(i.hasNext()){
      deadenemyclass enemy  =(deadenemyclass) i.next();
      enemy.move();
      enemy.bounds();
    }
boolean playerKilled = false;
    i = badbullets.iterator();
    while(i.hasNext()){
      badbulletclass badbullet  =(badbulletclass) i.next();
      badbullet.move();
      if(badbullet.h > 100){
        i.remove(); 
      }

      if(  badbullet.hit(tank)){
          playerKilled = true;
      }

      // badbullet.bounds();
    }

    if(playerKilled){
         playerKilled(); 
    }
  yAngle += .0002;
  } //not gameover so move shit



  fill(0,128);
  stroke(200);

  //"camera" translation
  translate(200,200,0);


  if(! gameover){
    noFill();
  } else {
     fill(0,255,0,30); 
  }
  rotateY(yAngle);


  //xAngle += .0001;

  //zAngle += .0001;
  box(200,200,200);

stroke(0,128);
fill(0,128);
text("score: "+score+"  lives:"+playerLives,-100,-100,0);
if(gameover){
text("GAME OVER   click to restart",-100,-75,0);
}

  tank.show();

  i = enemies.iterator();
  while(i.hasNext()){
    enemyclass enemy  =(enemyclass) i.next();
    enemy.show();

  }

  i = badbullets.iterator();
  while(i.hasNext()){
    badbulletclass badbullet  =(badbulletclass) i.next();
    badbullet.show();

  }

  i = deadenemies.iterator();
  while(i.hasNext()){
    deadenemyclass enemy  =(deadenemyclass) i.next();
    enemy.show();
  }


}





class deadenemyclass{
  public float x,y,h,xs,ys,hs;

  deadenemyclass(float px,float py, float ph){

    x = px;
    y = py;
    h = ph;
    hs = -10;
  }
  float s = 20;
  void show(){
    pushMatrix();
    stroke(0,200);
    noFill();
    translate(x,h,y);
    box(s,s,s);
    popMatrix();

  }


  void move(){
    h += hs;
  }


  void bounds(){
    if(h < -200){
//      println("whoo");
      deadenemies.remove(this); 
    } 
  }


}




class enemyclass{
  public float x,y,h,xs,ys,hs;



  enemyclass(float phs, float pr){
    h = -90; 
    x = random(160) - 80;
    y = random(160) - 80;
    hs = phs;

    r = pr;
  }
  float r;
  float s = 20;
  void show(){
    pushMatrix();
    stroke(0,200);
    fill(150,255,150,128);
    translate(x,h,y);
    box(s,s,s);
    popMatrix();

    pushMatrix();
    noStroke();
    fill(0,10);
    translate(x,100,y);
    box(s,0,s);
    popMatrix();

  }

  boolean checkfire(){
    if(int(random(r))==0){
      return true;

    }
    return false;
  }

  void move(){
    h += hs;
    xs += (random(2)-1)/10;
    ys += (random(2)-1)/10;
    x+=xs;
    y += ys;
  }



  void bounds(){
    if(x < -90) {  
      x = -90; 
      xs = xs * -.5;
    }
    if(x > 90) { 
      x = 90;
      xs = xs * -.5;
    }
    if(y < -90) {
      y = -90;  
      ys = ys * -.5; 
    }
    if(y > 90) { 
      y = 90;
      ys = ys * -.5;
    }

  }


}

boolean overlap(float line1val1,float line1val2,float line2val1,float line2val2){
  float line1min = (line1val1 < line1val2)?line1val1:line1val2;
  float line1max = (line1val1 > line1val2)?line1val1:line1val2;
  float line2min = (line1val1 < line2val2)?line2val1:line2val2;
  float line2max = (line1val1 > line2val2)?line2val1:line2val2;

  if(line1min < line2min && line1max < line2min){
    return false; 
  }
  if(line1min > line2max && line1max > line2max){
    return false; 
  }  


  return true;
}

class badbulletclass{

  public  float x,y, h;
  badbulletclass(float px,float py,float ph){
    x = px;
    y = py;
    h = ph;
  }
  float  s = 20;
  void move(){
    h += 1;
  }

  boolean hit(tankclass t){
    if(h < 90){
      return false; 
    }
    if(! overlap(x-10,x+10,tank.x-10,tank.x+10)){
      return false;
    }
    if(! overlap(y-10,y+10,tank.y-10,tank.y+10)){
      return false;
    }


    return true;
  }

  void show(){
    pushMatrix();
    stroke(255,200);
    fill(255,150,150,128);
    translate(x,h,y);
    box(s,0,s);
    popMatrix();
    //shadow
    /*
    pushMatrix();
     noStroke();
     fill(255,150,150,50);
     translate(x,100,y);
     box(s/2,0,s/2);
     popMatrix();
     */
  }

}


class bulletclass{
  public  float x,y, h;
  boolean hit(enemyclass e){
    if(! overlap(h,h,e.h-10,e.h+10)){
      return false;
    }
    if(! overlap(x-10,x+10,e.x-10,e.x+10)){
      return false;
    }
    if(! overlap(y-10,y+10,e.y-10,e.y+10)){
      return false;
    }
    //  println("OUCH" + random(10000));
    return true;
  }



  bulletclass(float px,float py){
    x = px;
    y = py;
    h = 95;
  }
  float  s = 20;
  void move(){
    h -= 2;
  }

  void show(){
    pushMatrix();
    stroke(255,200);
    fill(150,150,255,128);
    translate(x,h,y);
    box(s,0,s);
    popMatrix();
  }

}

class tankclass {
  public float x,y,xs,ys; 

  public HashSet bullets = new HashSet();
  void move(){
    x += xs;
    y += ys;

    Iterator i = bullets.iterator();
    while(i.hasNext()){
      bulletclass bullet  =(bulletclass) i.next();
      bullet.move();
      if(bullet.h < -100){
        i.remove();
      }
      Iterator j = enemies.iterator();
      while(j.hasNext()){
        enemyclass enemy  =(enemyclass) j.next();
        if(bullet.hit(enemy)){
          deadenemies.add(new deadenemyclass(enemy.x,enemy.y,enemy.h));
score++;
                    j.remove();
          //TODO score
        }
      }      

    }


  }

  void fire(){
    bullets.add(new bulletclass(x,y)); 
  }
public float hitcolors = 255;
  float s = 20;

  void show(){
    pushMatrix();
    stroke(255,200);
    
    if(hitcolors < 255){
       hitcolors++; 
    }
    
    fill(255,hitcolors,hitcolors,128);
    translate(x,90,y);
    box(s,s,s);
    popMatrix();

    Iterator i = bullets.iterator();
    while(i.hasNext()){
      bulletclass bullet  =(bulletclass) i.next();
      bullet.show();
    }

  }




  void bounds(){
    if(x < -90) {  
      x = -90;
    }
    if(x > 90) { 
      x = 90;
    }
    if(y < -90) {
      y = -90;   
    }
    if(y > 90) { 
      y = 90;
    }
  }

}