// ============================================================================
// File:               $File$
//
// Project:            
//
// Purpose:            
//
// Author:             Rammi
//
// Copyright Notice:   (c) 2008  Rammi (rammi@caff.de)
//                     This code is in the public domain.
//                     Use at own risk.
//                     No guarantees given.
//
// Latest change:      $Date$
//
// History:	       $Log$
//=============================================================================
package de.caff.asteroid;

import java.awt.*;
import java.awt.geom.AffineTransform;
import java.util.Collection;

/**
 * Space ship in automated player of Asteroid game.
 *
 * This is part of a solution for a competition
 * <a href="http://www.heise.de/ct/creativ/08/02/details/">by the German computer magazine c't</a>
 */
public class SpaceShip
        extends MovingGameObject
{
  /** Ship color. */
  private static final Color COLOR = new Color(0x80, 0x80, 0x80); // not as white as bullets

  /** The ship glyph. */
  public static final Glyph SHIP_GLYPH =  // 0xA6D
          new Glyph(new byte[] {16, 24, 0, -16, 24, 7, -32, 40, 7, 0, -56, 7, 32, 40, 7, 16, 24, 7, -64, 0, 0});
  /** The thrustiing ship glyph. */
  public static final Glyph THRUSTING_SHIP_GLYPH =  // 0xA6D with an insertion
          new Glyph(new byte[] {16, 24, 0, 0, 56, 7, -16, 24, 7, -32, 40, 7, 0, -56, 7, 32, 40, 7, 16, 24, 7, -64, 0, 0});
  /** Scling used for ship glyph. */
  public static final double SHIP_SCALING = 0.25;
  /** The identity of the ufo. */
  public static final Integer IDENT = new Integer(-1);
  /** The unthrustingship shape for drawing. */
  private static final Shape SHIP_SHAPE;
  /** The thrustingship shape for drawing. */
  private static final Shape THRUSTING_SHIP_SHAPE;
  static {
    AffineTransform at = AffineTransform.getRotateInstance(-Math.PI/2);
    at.concatenate(AffineTransform.getScaleInstance(SHIP_SCALING, SHIP_SCALING));
    SHIP_SHAPE = at.createTransformedShape(SHIP_GLYPH.getPath());
    THRUSTING_SHIP_SHAPE = at.createTransformedShape(THRUSTING_SHIP_GLYPH.getPath());
  }

  /** The direction of the ship, x coordinate. */
  private final int dx;
  /** The direction of the ship, y coordinate. */
  private final int dy;
  /** Is the ship thrusting? */
  private boolean thrusting;

  /**
   *  Constructor.
   *  @param x  x coordinate of ship center
   *  @param y  y coordinate of ship center
   *  @param dx direction x
   *  @param dy direction y
   */
  public SpaceShip(int x, int y, int dx, int dy)
  {
    super(x, y);
    this.dx = dx;
    this.dy = dy;
    setIdentity(IDENT);
  }

  /**
   *  Get the size of the object.
   *
   *  The size returned by this method is half the length of a square which contains the object,
   *  so the object's bounding box is between (x - size, y - size) and (x + size, y + size).
   *  @return object size
   */
  public int getSize()
  {
    return 13;
  }

  /**
   *  Get the x coordinate of the ship's direction.
   *  @return ship direction, x coordinate
   */
  public int getDirX()
  {
    return dx;
  }

  /**
   *  Get the y coordinate of the ship's direction.
   *  @return ship direction, y coordinate
   */
  public int getDirY()
  {
    return dy;
  }

  /**
   *  Get the direction angle.
   *
   *  The angle is measured counterclockwise, with <code>0</code> pointing to the right
   *  @return ship direction in radians
   */
  public double getDirectionAngle()
  {
    return Math.atan2(dy, dx);
  }

  /**
   *  Get the direction.
   *  @return direction
   */
  public Point getDirection()
  {
    return new Point(dx, dy);
  }

  /**
   * Draw the object.
   *
   * @param g graphics context
   */
  @Override
  public void draw(Graphics2D g)
  {
    g.setColor(COLOR);
    g.draw(getShipShape(getX(), getY(), getDirectionAngle(), thrusting));

    drawVelocityVector(g, Color.green);
  }

  /**
   *  Get a translated and rotated ship shape.
   *  @param px    ship shape's x coordinate
   *  @param py    ship shape's y coordinate
   *  @param angle ship angle (CCW, radians, 0 points right)
   *  @param thrusting is the ship thrusting
   *  @return transformed ship shape
   */
  public static Shape getShipShape(int px, int py, double angle, boolean thrusting)
  {
    AffineTransform at = AffineTransform.getTranslateInstance(px, py);
    at.concatenate(AffineTransform.getRotateInstance(angle));
    return at.createTransformedShape(thrusting ?
            THRUSTING_SHIP_SHAPE  :
            SHIP_SHAPE);
  }

  /**
   * Returns a string representation of the object.
   *
   * @return a string representation of the object.
   */
  @Override
  public String toString()
  {
    return String.format("SpaceShip@(%d,%d)>(%-3.1f°)", getX(), getY(), 180*getDirectionAngle()/Math.PI);
  }

  /**
   * Get the properties of this object.
   *
   * @return collection of properties
   */
  @Override
  public Collection<Property> getProperties()
  {
    Collection<Property> props = super.getProperties();
    props.add(new Property<Point>("Direction", getDirection()));
    props.add(new Property<Double>("Direction Angle (°)", 180*getDirectionAngle()/Math.PI));
    props.add(new Property<Boolean>("Thrusting", isThrusting()));
    return props;
  }

  /**
   *  Is the ship thrusting?
   *  @return the answer
   */
  public boolean isThrusting()
  {
    return thrusting;
  }

  /**
   *  Set whether the ship is thrusting.
   *  @param thrusting thrusting?
   */
  public void setThrusting(boolean thrusting)
  {
    this.thrusting = thrusting;
  }

  /**
   * Get the type of game object.
   *
   * @return game object type
   */
  public String getObjectType()
  {
    return "Space Ship";
  }

  /**
   * Access method for visitor pattern.
   *
   * @param visitor visitor
   */
  public void visitedBy(GameObjectVisitor visitor)
  {
    visitor.handle(this);
  }

}
