/*
 * For this lab you will be working on writing a UFO game.  The
 * UFO will fall from the top of the screen, the player will control
 * a tank at the bottom of the screen attempting to shoot it, and
 * the game will end if the UFO is shot or if it lands.
 */

/*
 * First of all, we need to import some classes that are built into
 * ProfessorJ.  Posn works similarly to the Posns you saw in U211:
 *
 * Posn p = new Posn(4, 5);
 * p.x == 4 // The x coordinate is 4
 * p.y == 5 // The y coordinate is 5
 *
 * The World class handles all the things like drawing, events,
 * etc.  You'll actually create a subclass of World later in this
 * lab.
 */

// We need these to get Posns and Worlds.
import draw.Posn;
import draw.World;

/*
 * The Color class is an abstract class from which all the
 * various color classes (Blue, Red, etc.) are derived.
 * The color classes are created like so:
 *
 * Color c = new Blue();
 */

// Here's all the colors we'll use.
import draw.Color;
import draw.Red;
import draw.White;
import draw.Green;
import draw.Blue;
import draw.Black;

/*
 * You won't need to use Random directly in this lab as we'll
 * be giving you code that uses it.
 */

// We need random for the UFO's horizontal movement.
import java.util.Random;

/*
 * First you should create a couple of classes to represent UFOs
 * and Tanks.  UFOs and Tanks both have a position in the game world,
 * and that's all the information they need to store.
 *
 * Each class also should have a move() method that takes the
 * distances to move the UFO/Tank in the x and y directions and
 * also the size of the world (to do checks in case the tank or
 * ufo is moving outside the world, in which case it should stop
 * moving in that direction).
 *
 * You should also write a same() method for each in order to test
 * the move() method (and others later) appropriately.
 */

/*
 * Once you have move(), you can stick the following code into UFO which
 * will handle the fact that the UFO zig-zags randomly left and right as
 * it falls.
 */

  // Given n, we pick (randomly) a distance to move horizontally whose absolute
  // value is <= n.  We also move the UFO by diffy pixels vertically.
  //
  // width and height are the dimensions of the world, which we use in move().
  //
  // UFO moveRandom(int n, int diffy, int width, int height) {
  //   return this.move(-n + (new Random()).nextInt(2 * n), diffy, width, height);
  // }

/*
 * Now we'll start working on how to draw these onto a canvas.  For each class,
 * write a method with the following contract:
 *
 * boolean draw(World w)
 *
 * The following methods of class World will be useful for writing these methods:
 *
 * boolean drawDisk(Posn p, int radius, Color c)
 * boolean drawRect(Posn p, int width, int height, Color c)
 * 
 * And the following will be useful for testing them (see Examples for example usage):
 *
 * // Creates a canvas of the given dimensions and displays it
 * boolean start(int width, int height)
 * // Destroys the canvas
 * boolean stop()
 */

/*
 * We will also need shots in this game as the tank will be attempting to stop the
 * UFO from landing, so create a Shot class and a series of classes to model lists
 * of shots (ALoS, MTLoS, ConsLoS).  Each should have move(), draw(), and same()
 * methods like the UFO and Tank classes.  You may also want to write a method for
 * lists of classes that removes shots from the list once they've left the canvas,
 * but that's not necessary.
 *
 * Also write a method in the Tank class that creates a new Shot (which will be
 * useful when we make the game interactive).
 */

/*
 * Now that you can draw the UFO, Tank, and Shot(s), now we will create UFOGameWorld
 * (which is a subclass of World) to hold all the information about our game.
 * Obviously it should contain a UFO object, a Tank object and a list of shots, but
 * it should also contain the height and width of the world.  Make it so that the
 * constructor has the following header:
 *
 * UFOGameWorld(int width, int height, UFO ufo, Tank tank, ALoS los)
 *
 * This way you can use the example given to you in the Examples class.
 *
 * You will want to write the following methods for UFOGameWorld:
 *
 * // Draws the world
 * boolean draw()
 *
 * You should use calls to the other classes' draw() methods, and you will also
 * want to use drawRect to "clear" the canvas before doing so by redrawing the
 * background.
 */

/*
 * Now you can draw the world, but it's pretty boring just sitting there, so let's
 * make it do something.  In order to handle key events (like pressing the arrow
 * keys), you'll need to define the following method in your UFOGameWorld:
 *
 * World onKeyEvent(String ke)
 *
 * ke will be a string describing the key pressed.  For this game, you will only
 * need to know about three possible values: "left" (for pressing the left arrow
 * key), "right" (for pressing the right arrow key) and "up" (for pressing the up
 * arrow key).
 *
 * The only object that responds to key events is the tank: you want to make it
 * so that the following happens:
 *
 *  - Pressing the left arrow key moves the tank left.
 *  - Pressing the right arrow key moves the tank right.
 *  - Pressing the up arrow key makes the tank shoot.
 *
 * You should also insert the following method into your UFOGameWorld -- run() will
 * call all the methods needed to start the game.
 */

  // run() takes the amount of time between ticks as a double and calls all the necessary
  // functions.
  //
  // boolean run(double tick) {
  //   return this.start(this.width, this.height) && this.bigBang(tick);
  // }

/*
 * Now we need to add a last bit of functionality so that the UFO and shots move --
 * otherwise it's a very boring and pointless game!  Implement the following method
 * in UFOGameWorld:
 *
 * World onTick()
 *
 * You should handle the shots moving upward and the UFO moving downwards here.
 *
 * If the UFO lands (i.e. gets too close to the bottom of the screen), the game
 * should end.  In order to end the game, the following method of World (and thus
 * of UFOGameWorld) should be called:
 *
 * World endOfWorld()
 *
 */

/*
 * Everything moves now, but there's still a problem -- the UFO just goes through the
 * shots!  In UFO and Shot, create a method that creates an appropriate BoundingBox
 * (which is already provided), then create a method for lists of shots which tests
 * to see if any of the shots in the list hits the UFO.
 *
 * Once you have that written, make sure to end the game if any of the shots hit the
 * UFO during gameplay and you're done!
 */

/*
 * Everything below are the classes we're giving to you -- a class that implements
 * all you need for bounding boxes and an Examples class with some definitions
 * that you can uncomment as you implement the classes.
 */

// We use rectangles for bounding boxes -- the main thing you
// want them for is to tell when they overlap.
class BoundingBox {
  Posn loc; // Upper left of bounding box
  int width;
  int height;

  BoundingBox(Posn loc, int width, int height) {
    this.loc = loc;
    this.width = width;
    this.height = height;
  }

  // When two bounding boxes overlap, we want to return true.
  // We do this by the following:
  //
  // Check the sides of the boxes.  If the we have that there's
  // an overlap between the boxes both horizontally and vertically,
  // then we have an overlap.
  //
  // For each, we check the left-most (top-most) right (bottom) side
  // and subtract from it the right-most (bottom-most) left (top)
  // side.  Draw it out and you'll see what I mean.
  boolean intersects(BoundingBox bb) {
    return (Math.min(this.loc.x + this.width, bb.loc.x + bb.width) -
            Math.max(this.loc.x, bb.loc.x) > 0) &&
           (Math.min(this.loc.y + this.height, bb.loc.y + bb.height) -
            Math.max(this.loc.y, bb.loc.y) > 0);
  }
}

// Our handy-dandy examples class.
class Examples {
  int width  = 200; // How wide we want the game to be
  int height = 500; // How tall we want it to be
 
  Examples() {}

  // The UFO should start in the middle of the canvas, a little bit down from the top.
  // UFO  ufo  = new UFO(new Posn(this.width / 2, 10));

  // The tank should start in the middle of the canvas, a little bit up from the bottom.
  // Tank tank = new Tank(new Posn(this.width / 2, this.height - 10));

  // Here's a world to test drawing UFOs and Tanks with:
  World w = new World();

  // Now to test the above out, try the following in the Interactions window:
  //
  // Examples e = new Examples();
  // e.w.start(e.width, e.height)
  // e.ufo.draw(e.w)
  // e.tank.draw(e.w)
  //
  // To destroy the canvas, just call e.w.stop() or close the window.

  // There are no shots at the start of the game.
  // ALoS los  = new MTLoS();

  // Create a new game world with the actors defined above.
  // UFOGameWorld ugw = new UFOGameWorld(this.width, this.height, this.ufo, this.tank, this.los);
}

