// Ship.java
// the ship object
// responsible for rotating itself, updating itself, drawing itself..

import java.awt.*;
import java.lang.Math;

public class Ship {
  protected Rectangle location;
  protected double dx, dy;
  protected double[][] p = new double[3][3];
  protected int tilt;		// the direction angle
  protected Color color;
  protected String owner;
  protected int score;
  
  final double scale = 20.0;

  // more or less traditional constructor
  public Ship (int x1, int y1, int x2, int y2, double dx, double dy, Color color, String owner) {
    location = new Rectangle (x1, y1, x2, y2);
    p[0][0] = -1.0 * scale;
    p[0][1] = 0.0 * scale;
    p[0][2] = 0.0;          // dummy

    p[1][0] = 0.0 * scale;
    p[1][1] = 1.0 * scale;
    p[1][2] = 1.0;          // dummy

    p[2][0] = 1.0 * scale;
    p[2][1] = 0.0 * scale;
    p[2][2] = 2.0;         // dummy
    
    this.dx = dx;
    this.dy = dy;

    this.color = color;
    this.owner = owner;

    tilt = 0;
    score = 0;
  }

  // specialized constructor, used by client to add new ship to their space
  public Ship (String owner,
               int x1, int y1, int x2, int y2,
               double[][] orientation,
               double dx, double dy, Color color) {

    location = new Rectangle (x1, y1, x2, y2);

    p = orientation;
    
    this.dx = dx;
    this.dy = dy;

    this.color = color;
    this.owner = owner;

    tilt = 0;
  }

  public void setColor (Color newColor) { color = newColor; }

  public Color shipColor () { return color; }

  public void setMotion (double ndx, double ndy) { dx = ndx; dy = ndy; }

  // find out the owner of the ship
  public String shipOwner () { return owner; }

  // give the player/ship/whatever a point..
  public void addScore () { score++; }

  // take a way a point (no bounds checking)
  public void delScore () { score--; }
  
  // get player/ship/whatever score
  public int getScore () { return score; }

  // set score
  public void setScore (int score) { this.score = score; }
  
  public int x() { return location.x; }

  public int y() { return location.y; }

  // returns the 3,3 matrix that define the ship
  public double[][] dimensions() { return p; }

  // sets the 3,3 matrix to value passed in
  public void setP (double[][] newP) { p = newP; }
  
  public double xMotion() { return dx; }

  public double yMotion() { return dy; }

  public int shipTilt() { return tilt; }

  public Rectangle region() { return location; }

  public void moveTo (int x, int y) { location.setLocation (x, y); }

  public void move() { location.translate ((int) dx, (int) dy); }

  private double radian (double angle) { return angle * 2.0* Math.PI / 360.0; } 

  // a fix for the modulo operation to handle negative numbers
  // ex/  -3 % 10 = 7. assume b > 0
  private int mod (int a, int b) {
    if (a >= 0)
      return a % b;
    else 
      return b - (Math.abs (a) % b);
  }
  
  public void rotate (double angle) {   // angle is in degrees
    double[][] rotmat = new double[3][3];           // rotation matrix
    double[][] out    = new double[3][3];           // out = p * rootmat

    angle = mod ((int)angle, 360);   // adjust angle... (is this necessary?)
    tilt = (int) angle;
    angle = (double) tilt;
    // rotation matrix will enable us to rotate the ship
    rotmat[0][0] = Math.cos (radian (angle));
    rotmat[0][1] = -Math.sin (radian (angle));
    rotmat[0][2] = 0;
    
    rotmat[1][0] = Math.sin (radian (angle));
    rotmat[1][1] = Math.cos (radian (angle));
    rotmat[1][2] = 0;
    
    rotmat[2][0] = 0;
    rotmat[2][1] = 0;
    rotmat[2][2] = 1;
    
    // this multiplies our matrix by the rotation matrix
    for (int i = 0; i < 3; i++ ) {
      for (int j = 0; j < 3; j++ ) {
        double temp = 0.0;
        for (int k = 0; k < 3; k++) 
          temp+= p[i][k] * rotmat[k][j];
        out[i][j] = temp;
      }
    }
    p = out;
    tilt = (int) angle;    // do we need tilt?
  }
  
//  public void init() {
//  }

  // flicker free paint method
  public void draw (Graphics g) {
    g.setColor (color);
    g.drawLine (location.x + (int) p[0][0], 
                location.y + (int) p[0][1], 
                location.x + (int) p[1][0], 
                location.y + (int) p[1][1]); 
    
    g.drawLine (location.x + (int) p[1][0], 
                location.y + (int) p[1][1],
                location.x + (int) p[2][0], 
                location.y + (int) p[2][1]); 

    g.drawLine (location.x + (int) p[2][0], 
                location.y + (int) p[2][1], 
                location.x + (int) p[0][0], 
                location.y + (int) p[0][1]);
  }

  private void delay (int millis) {
    try { Thread.sleep (millis); } catch (Exception ignored) {}
  }
}







