package GlobalNavigation;

import java.awt.Color;
import java.awt.geom.*;
import java.util.*;

import LocalNavigation.GUIMessage;

import Carmen.*;

/**
 * <p>Message used to send a polygon to the GUI</p>
 * 
 * <p>Examples:
 * <pre>
 *    (new GUIPolyMessage(vertices, true).publish(); //use curent color
 *    (new GUIPolyMessage(Color.BLUE, vertices, false)).publish();
 * </pre></p>
 *
 * @author vona
 **/
public class GUIPolyMessage extends GUIMessage {

  /**
   * <p>The number of vertices.</p>
   **/
  public int numVertices;

  /**
   * <p>The CCW polygon vertex x coordinates in world frame (m).</p>
   **/
  public double[] x;

  /**
   * <p>The CCW polygon vertex y coordinates in world frame (m).</p>
   **/
  public double[] y;

  /**
   * <p>Whether to close the poly.</p>
   **/
  public int closed;

  /**
   * <p>Whether to fill the poly.</p>
   **/
  public int filled;

  private static final String CARMEN_GUI_POLY_NAME = "carmen_gui_poly";
  private static final String CARMEN_GUI_POLY_FMT =
    "{int, <double:1>, <double:1>, int, int, int, int, int, double, string};";
  private static final int IPC_QUEUE_LENGTH = 10;

  /**
   * <p>Create a new GUIPolyMessage.</p>
   *
   * <p>{@link #timestamp} and {@link #host} are set to the current time and
   * host, respectively.</p>
   *
   * @param r the red color component, negative to use current color
   * @param g the green color component, negative to use current color
   * @param b the blue color component, negative to use current color
   * @param vertices the polygon vertices in CCW order
   * @param closed whether to close the poly
   * @param filled whether to fill the poly
   **/
  public GUIPolyMessage(int r, int g, int b,
                        List<Point2D.Double> vertices,
                        boolean closed, boolean filled) {
    super(r, g, b);
    
    this.closed = (closed) ? 1 : 0;
    this.filled = (filled) ? 1 : 0;

    numVertices = vertices.size();

    x = new double[numVertices];
    y = new double[numVertices];

    int i = 0;
    for (Point2D.Double vertex : vertices) {
      x[i] = vertex.getX();
      y[i] = vertex.getY();
      i++;
    }
  }
 
  /**
   * <p>Covers {@link #GUIPolyMessage(int, int, int, List, boolean,
   * boolean)}.</p>
   *
   * @param color the color, or null to use current
   **/
  public GUIPolyMessage(Color color, List<Point2D.Double> vertices,
                        boolean closed, boolean filled) {
    this((color != null) ? color.getRed() : -1,
         (color != null) ? color.getGreen() : -1,
         (color != null) ? color.getBlue() : -1,
         vertices, closed, filled);
  }

  /**
   * <p>Convenience cover of {@link #GUIPolyMessage(int, int, int, List,
   * boolean, boolean)}, always uses current color.</p>
   **/
  public GUIPolyMessage(List<Point2D.Double> vertices, 
                        boolean closed, boolean filled) {
    this(-1, -1, -1, vertices, closed, filled);
  }
 
  /**
   * <p>Create a new GUIPolyMessage.</p>
   **/
  public GUIPolyMessage() {
    timestamp = Util.getTime();
    host = Util.getHostName();    
  }

  /**
   * <p>Make a list of the vertices in CCW order.</p>
   *
   * @return a list of the vertices in CCW order
   **/
  public List<Point2D.Double> makeVertexList() {
    List<Point2D.Double> vertices = new LinkedList<Point2D.Double>();
    for (int i = 0; i < x.length; i++)
      vertices.add(new Point2D.Double(x[i], y[i]));
    return vertices;
  }
  
  /**
   * <p>Check whether this poly is filled.</p>
   *
   * @return true iff this poly is filled
   **/
  public boolean isFilled() {
    return (filled != 0);
  }

  /**
   * <p>Check whether this poly is closed.</p>
   *
   * @return true iff this poly is closed
   **/
  public boolean isClosed() {
    return (closed != 0);
  }

  /**
   * <p>Subscribe a class to GUIPolyMessages.</p>
   * 
   * @param handler a GUIPolyHandler
   */
  public static void subscribe(GUIPolyHandler handler) {
    subscribe(CARMEN_GUI_POLY_NAME, CARMEN_GUI_POLY_FMT, handler, 
              GUIPolyMessage.class, "handle");
    IPC.IPC.setMsgQueueLength(CARMEN_GUI_POLY_NAME, IPC_QUEUE_LENGTH);
  }
  
  /**
   * <p>Publish GUIPolyMessage to subscribers</p>
   */
  public void publish() {
    publish(CARMEN_GUI_POLY_NAME, CARMEN_GUI_POLY_FMT, this);
  }
}
