import java.awt.*;
import java.awt.event.*;
import java.awt.Frame;
import java.awt.Image;
import java.applet.*;
import java.util.*;
import java.net.*;





public class SpriteApplet extends Applet implements ActionListener {
  public static final int LEFT = 1;
  public static final int RIGHT = 2;
  public static final int UP = 3;
  public static final int DOWN = 4;

  // horizontal & vertical increments
  public static final int dx = 3;
  public static final int dy = 3;


  private static Image shipImage[] = new Image[16];
  private static Image bgImage, globeImage;
  private static Playfield playField;
  private static Sprite globeSprite;
  private static MultiSprite shipSprite = new MultiSprite(50, 50);
  private static Toolkit tk = Toolkit.getDefaultToolkit();
  private MediaTracker tracker = new MediaTracker(this);
  private final int NUM_IMAGES = 16;
  public int heading = LEFT;
  private static Image output;

  public void init() {
    // set up handler
    Panel p = new Panel();
    p.setLayout(new GridLayout(2,4));
    ((Button)p.add(new Button("Left"))).addActionListener(this);
    ((Button)p.add(new Button("Right"))).addActionListener(this);
    ((Button)p.add(new Button("Up"))).addActionListener(this);
    ((Button)p.add(new Button("Down"))).addActionListener(this);
    ((Button)p.add(new Button("<< Rotate"))).addActionListener(this);
    ((Button)p.add(new Button("Rotate >>"))).addActionListener(this);
    add("South", p);


    
    // load the background image
    bgImage = getImage(getDocumentBase(), "bg1.jpg");
    tracker.addImage(bgImage, 0);
    
    // load the globe sprite
    globeImage = getImage(getDocumentBase(), "globe.gif");
    tracker.addImage(globeImage, 0);

    // load the 16 different rotational images of ship
    for(int i=0; i<NUM_IMAGES; i++) {
      if (i<10) {
	shipImage[i] = getImage(getDocumentBase(), "Ship000" + i + ".GIF");
      }
      else
	shipImage[i] = getImage(getDocumentBase(), "Ship00" + i + ".GIF");
      tracker.addImage(shipImage[i], 0);
    }
    
    
    
    // wait for all images to load completely
    getGraphics().drawString("Loading Images", 10, 10);
    try {
      tracker.waitForID(0);
    } catch (InterruptedException e) { }
    getGraphics().drawString("Done loading images.\nCreating new sprites...\n", 10, 10);
    
    
    // create the sprites and playfield
    playField = new Playfield(bgImage, 2);
    setSize(playField.width, playField.height);
    globeSprite = new Sprite(globeImage);
    for(int i=0; i<NUM_IMAGES; i++)
      shipSprite.addImage(shipImage[i]);
    
    // add sprites to playfield
    playField.addSprite(0, shipSprite);
    playField.addSprite(1, globeSprite);
    
    
    System.err.println("Done creating sprites.");
 
   
    new Timer(this).start();
    setEnabled(true);
  }
  


  public void update(Graphics g) {
   
    //g.drawImage(output, 0, 0, this);
    paint(g);
  }


  
  public  void paint(Graphics g) {
    //playField.draw();
    //output = playField.toImage(this);//shipSprite[whichImg%16].toImage(this);
    g.drawImage(output, 0, 0, this);
    
  }



  public void rotateRight() { 
    // effects:  rotates the ship left by 360/16 degrees
    shipSprite.nextImage(); 
    
  }
  


  public void rotateLeft() { 
    // effects:  rotates the ship right by 360/16 degrees
    shipSprite.prevImage(); 
    
  }

  
  public void nextFrame() {
    // effects:  this is where the actual animation takes place.  The behavior of each frame is set by the following commands.
    if(heading == LEFT)
      shipSprite.x -= dx;
    else if(heading == RIGHT)
      shipSprite.x += dx;
    else if(heading == UP)
      shipSprite.y -= dy;
    else if(heading == DOWN)
      shipSprite.y += dy;
    
    // do "wrap around" effect for globe
    if(globeSprite.x > playField.width)
      globeSprite.x = 0;
    if(globeSprite.y > playField.height)
      globeSprite.y = 0;

    globeSprite.x++;
    globeSprite.y+=2;
    playField.draw();
    output = playField.toImage();//shipSprite[whichImg%16].toImage(this);
    repaint();
    
    
    
  }


  public void actionPerformed (ActionEvent e) {
    String s = e.getActionCommand();
    if(s.equals("Left"))
      heading = LEFT;
    else if(s.equals("Right"))
      heading = RIGHT;
    else if(s.equals("Up"))
      heading = UP;
    else if(s.equals("Down"))
      heading = DOWN;
    else if(s.equals("<< Rotate"))
      rotateLeft();
    else if(s.equals("Rotate >>"))
      rotateRight();
    
  }
  
  
}





class Timer extends Thread {
  // effects:  calls nextFrame() in parent every 10 milliseconds

  SpriteApplet parent;
  
  Timer(SpriteApplet parent) {
    this.parent = parent;
    this.setPriority(Thread.NORM_PRIORITY);
  }
  
  public void run() {
    while (true) {
      try { sleep(20); } catch (InterruptedException e) { System.err.println("Interrupted!"); }
      
      parent.nextFrame();
    }
  }


}
