// SpriteVector Class
// SpriteVector.java

// Imports
import java.awt.*;
import java.util.*;

public class SpriteVector extends Vector {
  protected Background background;

  public SpriteVector(Background back) {
    super(50, 10);
    background = back;
  }

  public Background getBackground() {
    return background;
  }

  public void setBackground(Background back) {
    background = back;
  }

  public Point getEmptyPosition(Dimension sSize) {
    Rectangle pos = new Rectangle(0, 0, sSize.width, sSize.height);
    Random    rand = new Random(System.currentTimeMillis());
    boolean   empty = false;
    int       numTries = 0;

    // Look for an empty position
    while (!empty && numTries++ < 50) {
      // Get a random position
      pos.x = Math.abs(rand.nextInt() %
        background.getSize().width);
      pos.y = Math.abs(rand.nextInt() %
        background.getSize().height);

      // Iterate through sprites, checking if position is empty
      boolean collision = false;
      for (int i = 0; i < size(); i++) {
        Rectangle testPos = ((Sprite)elementAt(i)).getPosition();
        if (pos.intersects(testPos)) {
          collision = true;
          break;
        }
      }
      empty = !collision;
    }
    return new Point(pos.x, pos.y);
  }

  Sprite isPointInside(Point pt) {
    // Iterate backward through the sprites, testing each
    for (int i = (size() - 1); i >= 0; i--) {
      Sprite s = (Sprite)elementAt(i);
      if (s.isPointInside(pt))
        return s;
    }
    return null;
  }

  public void update() {
    // Iterate through sprites, updating each
    Sprite    s, sHit;
    Rectangle lastPos;
    for (int i = 0; i < size(); ) {
      // Update the sprite
      s = (Sprite)elementAt(i);
      lastPos = new Rectangle(s.getPosition().x, s.getPosition().y,
        s.getPosition().width, s.getPosition().height);
      BitSet action = s.update();

      // Check for the SA_ADDSPRITE action
      if (action.get(Sprite.SA_ADDSPRITE)) {
        // Add the sprite
        Sprite sToAdd = s.addSprite(action);
        if (sToAdd != null) {
          int iAdd = add(sToAdd);
          if (iAdd >= 0 && iAdd <= i)
            i++;
        }
      }

      // Check for the SA_RESTOREPOS action
      if (action.get(Sprite.SA_RESTOREPOS))
        s.setPosition(lastPos);

      // Check for the SA_KILL action
      if (action.get(Sprite.SA_KILL)) {
        removeElementAt(i);
        continue;
      }

      // Test for collision
      int iHit = testCollision(s);
      if (iHit >= 0)
        if (collision(i, iHit))
          s.setPosition(lastPos);
      i++;
    }
  }

  public void draw(Graphics g) {
    // Draw the background
    background.draw(g);

    // Iterate through sprites, drawing each
    for (int i = 0; i < size(); i++)
      ((Sprite)elementAt(i)).draw(g);
  }

  public int add(Sprite s) {
    // Use a binary search to find the right location to insert the
    // new sprite (based on z-order)
    int   l = 0, r = size(), i = 0;
    int   z = s.getZOrder(),
          zTest = z + 1;
    while (r > l) {
      i = (l + r) / 2;
      zTest = ((Sprite)elementAt(i)).getZOrder();
      if (z < zTest)
        r = i;
      else
        l = i + 1;
      if (z == zTest)
        break;
    }
    if (z >= zTest)
      i++;

    insertElementAt(s, i);
    return i;
  }

  protected int testCollision(Sprite test) {
    // Check for collision with other sprites
    Sprite  s;
    for (int i = 0; i < size(); i++)
    {
      s = (Sprite)elementAt(i);
      if (s == test)  // don't check itself
        continue;
      if (test.testCollision(s))
        return i;
    }
    return -1;
  }

  protected boolean collision(int i, int iHit) {
    // Swap velocities (bounce)
    Sprite s = (Sprite)elementAt(i);
    Sprite sHit = (Sprite)elementAt(iHit);
    Point swap = s.getVelocity();
    s.setVelocity(sHit.getVelocity());
    sHit.setVelocity(swap);
    return true;
  }
}
