// ============================================================================
// File:               $File$
//
// Project:            Asteroids game solver.
//
// 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.awt.geom.GeneralPath;
import java.util.Collection;

/**
 * Asteroid object in automated player of Asteroids game.
 *
 * This class is part of a solution for a
 * <a href="http://www.heise.de/ct/creativ/08/02/details/">competition by the German computer magazine c't</a>.
 */
public class Asteroid
        extends MovingGameObject
{
  /** Score for large asteroid. */
  public static final int SCORE_LARGE_ASTEROID  = 20;
  /** Score for middle size asteroid. */
  public static final int SCORE_MIDDLE_ASTEROID = 50;
  /** Score for small asteroid. */
  public static final int SCORE_SMALL_ASTEROID  = 100;

  /** Color of asteroid. */
  private static final Color ASTEROID_COLOR = new Color(0x80, 0x80, 0x80);
  /** The scores by scale. */
  private static final int[] SCORES = new int[] {
          0, 0, SCORE_SMALL_ASTEROID, 0, SCORE_MIDDLE_ASTEROID, 0, 0, 0, SCORE_LARGE_ASTEROID
  };
  /** Scaling for shapes when drawing big asteroid. */
  private static int NORMAL_SCALE = 8;

  /** Size of a large asteroid. */
  public static final int SIZE_LARGE_ASTEROID  = 4*NORMAL_SCALE;
  /** Size of a middle size asteroid. */
  public static final int SIZE_MIDDLE_ASTEROID = 2*NORMAL_SCALE;
  /** Size of a small asteroid. */
  public static final int SIZE_SMALL_ASTEROID  = NORMAL_SCALE;
  /** Scaling of this asteroid. */
  private int scale;
  /** Type of this asteroid. There are 4 different types numbered from 0 to 3. */
  private int type;
  /** Index of the asteroid in datagram. */
  private final int index;

  private static final GeneralPath PATH0 = new GeneralPath();
  private static final GeneralPath PATH1 = new GeneralPath();
  private static final GeneralPath PATH2 = new GeneralPath();
  private static final GeneralPath PATH3 = new GeneralPath();
  static {
    PATH0.moveTo(1, 0);
    PATH0.lineTo(4, 1);
    PATH0.lineTo(4, 2);
    PATH0.lineTo(1, 4);
    PATH0.lineTo(-2, 4);
    PATH0.lineTo(-1, 3);
    PATH0.lineTo(-4, 3);
    PATH0.lineTo(-4, -1);
    PATH0.lineTo(-2, -4);
    PATH0.lineTo(1, -3);
    PATH0.lineTo(2, -4);
    PATH0.lineTo(4, -2);
    PATH0.closePath();

    PATH1.moveTo(3, 0);
    PATH1.lineTo(4, 2);
    PATH1.lineTo(2, 4);
    PATH1.lineTo(0, 2);
    PATH1.lineTo(-2, 4);
    PATH1.lineTo(-4, 2);
    PATH1.lineTo(-4, -2);
    PATH1.lineTo(-2, -4);
    PATH1.lineTo(1, -4);
    PATH1.lineTo(4, -2);
    PATH1.closePath();

    PATH2.moveTo(4, 1);
    PATH2.lineTo(2, 4);
    PATH2.lineTo(-1, 4);
    PATH2.lineTo(-4, 1);
    PATH2.lineTo(-2, 0);
    PATH2.lineTo(-4, -1);
    PATH2.lineTo(-2, -4);
    PATH2.lineTo(0, -1);
    PATH2.lineTo(0, -4);
    PATH2.lineTo(2, -4);
    PATH2.lineTo(4, -1);
    PATH2.closePath();

    PATH3.moveTo(2, 1);
    PATH3.lineTo(4, 2);
    PATH3.lineTo(2, 4);
    PATH3.lineTo(0, 3);
    PATH3.lineTo(-2, 4);
    PATH3.lineTo(-4, 2);
    PATH3.lineTo(-3, 0);
    PATH3.lineTo(-4, -2);
    PATH3.lineTo(-2, -4);
    PATH3.lineTo(-1, -3);
    PATH3.lineTo(2, -4);
    PATH3.lineTo(4, -1);
    PATH3.closePath();
  }
  /** The asteroid shapes sorted by type. */
  private static final Shape[] SHAPES = new Shape[] {
          PATH1,
          PATH3,
          PATH2,
          PATH0,
  };

  /**
   * Constructor.
   * @param index index of this asteroid in the incoming datagram
   * @param x position (x coordinate)
   * @param y position (y coordinate)
   * @param size size (as given by game, so 0 is big and 14 is small)
   * @param type type of asteroid (0, 1, 2, or 3)
   */
  public Asteroid(int index, int x, int y, int size, int type)
  {
    super(x, y);
    switch (size) {
    case 0:
      this.scale = NORMAL_SCALE;
      break;

    case 15:
      this.scale = NORMAL_SCALE/2;
      break;

    case 14:
      this.scale = NORMAL_SCALE/4;
      break;
    }
    assert(type >= 0  &&  type < SHAPES.length);
    this.type = type;
    this.index = index;
  }

  /**
   *  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 4*scale;
  }

  /**
   *  Get the type of this asteroid.
   *  @return anumber between 0 and 3
   */
  public int getType()
  {
    return type;
  }

  /**
   *  Get the index of this asteroid in the datagram.
   *  @return index in datagram
   */
  public int getIndex()
  {
    return index;
  }

  /**
   *  Draw the object.
   *  @param g graphics context
   */
  @Override
  public void draw(Graphics2D g)
  {
    g.setColor(ASTEROID_COLOR);
    AffineTransform trafo = new AffineTransform(scale, 0, 0, scale, getX(), getY());
    g.draw(trafo.createTransformedShape(SHAPES[type]));

    drawVelocityVector(g, Color.red);
  }

  /**
   * Returns a string representation of the object.
   *
   * @return a string representation of the object.
   */
  @Override
  public String toString()
  {
    return String.format("Asteroid@(%d,%d)*%d?%d", getX(), getY(), 4*scale, type);
  }

  /**
   * Get the properties of this object.
   *
   * @return collection of properties
   */
  @Override
  public Collection<Property> getProperties()
  {
    Collection<Property> props = super.getProperties();
    props.add(new Property<Integer>("Asteroid Type", getType()));
    props.add(new Property<Integer>("Scale Factor", scale));
    return props;
  }

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

  /**
   * Get the score which is added if this object is hit.
   *
   * @return score or {@link #NO_SCORE}
   */
  @Override
  public int getScore()
  {
    return SCORES[scale];
  }

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

  
}

