class Snake{
  int x,y,tailx,taily,dir,lastDir;
  Head h;
  Tail t;
  
  
  int length = 10;
  
  ArrayList<Segment>segments = new ArrayList<Segment>();
  int upcomingDir;
  
  
  Snake(int px, int py){
    x = px; 
    y = py; 
    h = new Head();
    t = new Tail();
    tailx = x-1;
    taily = y;
    //grid[x][y].setOccupant(h);
    //grid[tailx][taily].setOccupant(t);
    dir = RIGHT;
    lastDir = RIGHT;
    upcomingDir = RIGHT;
    t.setDir(RIGHT);
    //we load one big copy of the body images so each segment doesn't have to load its own

   }
   
   
   boolean bodyIsGold = false;
   boolean tailIsGold = false;
   
   boolean isOnSnake(xy p){
      if(x == p.x && y == p.y) return true; 
      if(tailx ==p.x && taily == p.y) return true; 
      for(Segment s : segments){
        if(s.x == p.x && s.y == p.y) return true; 
      }
      return false;
   }
   
   
   void setDir(int newDir){
     //deny them from doubling back on themselves!
     //println("TRY "+dirToGfxDir(newDir));
     switch(newDir){
        case UP: 
            if(dir == DOWN) return; 
          break;
        case DOWN: 
            if(dir == UP) return; 
           break;
        case LEFT: 
          if(dir == RIGHT) return; 
         break;
        case RIGHT: 
          if(dir == LEFT) return; 
          break;
     }
          //println("---");
     upcomingDir = newDir;
   }
  
  
  void setDirFollowTail(){
//    println("X "+x+" Y "+y+" tailx "+tailx+" taily "+taily);
    boolean virgin = true;
    if(x != tailx){
        if(x < tailx) upcomingDir = RIGHT;
        if(x > tailx) upcomingDir = LEFT;
        virgin = false;
    }
    if(y != taily){
        if(y < taily) upcomingDir = DOWN;
        if(y > taily) upcomingDir = UP;
        if(!virgin) println("!!!!!!!!!!!!!!!!!!!!!!!!!!OH TWICE DAMN");
    }
    
  }
  
  
   void draw(){
     
      if(timer.goodToGo){
          tailIsGold = true;
      }
      if(loopTime){
           bodyIsGold = true;
      }
    
     
     
     
      t.drawGfx(tailx,taily);
      for(Segment s : segments){
       s.draw(); 
      }
      h.draw(x,y,dir); 

   }
 
  
  void move(){
    lastDir = dir;
       dir = upcomingDir;
    
      segments.add(new Segment(x,y,dir,lastDir,bodyimages_normal,turnimages_normal,bodyimages_gold,turnimages_gold));

     int oldtailx = tailx; int oldtaily = taily;
     
     if(segments.size() > length){
        Segment removedSegment = segments.remove(0); 
        //grid[tailx][taily].removeOccupant();
        tailx = removedSegment.x;
        taily = removedSegment.y;
        t.setDir(removedSegment.newDir);
        //grid[tailx][taily].setOccupant(t);
        
     }

     if(dir == RIGHT){
        x++;
     } 
     if(dir == LEFT){
        x--;
     } 
     if(dir == UP){
        y--;
     } 
     if(dir == DOWN){
        y++;
     }
     
      if((tailx == x && taily == y) ||(oldtailx == x && oldtaily == y)){
        if(tailIsGold){
          if(!loopTime){
            pauseBg();
            
            fxTailCaught();
   
          }
          loopTime = true;
          }
      } 
//      line(800,800,x*SQUARESIZE,y*SQUARESIZE);



      
      
      if(wallThere(x,y)){
         fxCrash();
         tryToEndGame(); 
      }
      ArrayList<Enemy> eaten  = new ArrayList<Enemy>();
      for(Enemy e : enemies){
          if(e.isIn(x,y)){
             eaten.add(e); 
          }
      }
      boolean gulp = false;
      for(Enemy e : eaten){
        e.eaten();
         enemies.remove(e);
         length += 4;
        gulp = true; 
          timer.advance();
      }
      if(gulp){

         fxBite(); 
         
      }
  }
    
    
}



class Head {
    int dir;
  
  
    Head(){
    }
  
     void draw(int x, int y,int dir){
        HashMap<String,PImage>  images = images_normal;
       if(snake.bodyIsGold) images =  images_gold;
      PImage img = images.get(dirToGfxDir(dir));
      image(img, x * SQUARESIZE,y * SQUARESIZE);
   }
        void draw(int x, int y){
          fill(20,200,20);
//          ellipse((x+.5)*SQUARESIZE,(x+.5)*SQUARESIZE,(x+.5)*SQUARESIZE,(x+.5)*SQUARESIZE,      
   }
   void setDir(int pdir){
      dir = pdir; 
   }
  
}

class Tail {
    int dir;
  
    HashMap<String,PImage> images_normal;
    HashMap<String,PImage> images_gold;
  
    Tail(){
       images_normal =  load4DirImages("snake/tail",true);
       images_gold =  load4DirImages("goldsnake/tail",true);

    }
     void draw(int x, int y){
      //line(SQUARESIZE*x,SQUARESIZE*y,SQUARESIZE*(x+1),SQUARESIZE*(y+1));
   }
     void drawGfx(int x, int y){
        HashMap<String,PImage>  images = images_normal;
        if(snake.tailIsGold) images =  images_gold;

      PImage img = images.get(dirToGfxDir(dir));
      image(img, x * SQUARESIZE,y * SQUARESIZE);
   }

   void setDir(int pdir){
      dir = pdir; 
   }
  
}
//this holds a part of the snake body, for the list
class Segment{
  int x,y;
  int newDir, oldDir;
  HashMap<String,PImage> imagesStraight_normal;
    HashMap<String,PImage> imagesTurn_normal;
  HashMap<String,PImage> imagesStraight_gold;
    HashMap<String,PImage> imagesTurn_gold;
   Segment(int px, int py, int pdir,int poldDir,
       HashMap<String,PImage> pimagesStraight_normal,HashMap<String,PImage> pimagesTurn_normal,
       HashMap<String,PImage> pimagesStraight_gold,HashMap<String,PImage> pimagesTurn_gold
       
       ){
      x = px;
      y = py;
      newDir = pdir;
      oldDir = poldDir;
      imagesStraight_normal = pimagesStraight_normal;
      imagesTurn_normal = pimagesTurn_normal;
      imagesStraight_gold = pimagesStraight_gold;
      imagesTurn_gold = pimagesTurn_gold;

   } 
   
  void draw(){
    
      PImage img;  
    if(newDir == oldDir){
        HashMap<String,PImage>  imagesStraight = imagesStraight_normal;
        if(snake.bodyIsGold) imagesStraight =  imagesStraight_gold;

        img = imagesStraight.get(dirToGfxDir(newDir));  
      } else {
        HashMap<String,PImage>  imagesTurn = imagesTurn_normal;
        if(snake.bodyIsGold) imagesTurn =  imagesTurn_gold;
         img = imagesTurn.get(dirToGfxDir(oldDir)+"_"+dirToGfxDir(newDir));  
         
       //  println("old move "+dirToGfxDir(oldDir)+"_ new move "+dirToGfxDir(newDir));
      }    
      image(img, x * SQUARESIZE,y * SQUARESIZE);
  }
   
   
}




HashMap<String,PImage> load4DirImages(String prefix,boolean duh){
  HashMap<String,PImage> hm = new HashMap<String,PImage>();
  hm.put("up",loadImage(prefix+"_up.png"));
  hm.put("down",loadImage(prefix+"_down.png"));
  hm.put("left",loadImage(prefix+"_left.png"));
  hm.put("right",loadImage(prefix+"_right.png"));
  return hm;  
}


HashMap<String,PImage> load8DirImages(String prefix,boolean duh){
  HashMap<String,PImage> hm = new HashMap<String,PImage>();
  hm.put("up_right",loadImage(prefix+"_up_right.png"));
  hm.put("up_left",loadImage(prefix+"_up_left.png"));
  hm.put("down_right",loadImage(prefix+"_down_right.png"));
  hm.put("down_left",loadImage(prefix+"_down_left.png"));
  hm.put("left_up",loadImage(prefix+"_left_up.png"));
  hm.put("left_down",loadImage(prefix+"_left_down.png"));
  hm.put("right_up",loadImage(prefix+"_right_up.png"));
  hm.put("right_down",loadImage(prefix+"_right_down.png"));


  hm.put("down_up",loadImage(prefix+"_down_up.png"));
  hm.put("up_down",loadImage(prefix+"_up_down.png"));
  hm.put("left_right",loadImage(prefix+"_left_right.png"));
  hm.put("right_left",loadImage(prefix+"_right_left.png"));


  return hm;  
}