// ============================================================================
// 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.awt.geom.GeneralPath;

/**
 *  One glyph in game, a letter or explosion or other.
 */
public class Glyph
{
  /** Identity transformation. */
  private static final AffineTransform IDENTITY = new AffineTransform();
  /** x offset to next letter. */
  private Point offset;
  /** The path of the letter. */
  private GeneralPath path;
  /** Bound sto be used for this glyph. */
  private Rectangle bounds;

  /**
   *  Constructor.
   *  Creates the glyph from http://www.too-late.de/result.txt line, extract
   *  of ROM data.
   *
   *  @param data ROM data
   */
  public Glyph(byte[] data)
  {
    boolean moveToPending = true;
    path = new GeneralPath();
    offset = new Point();
    for (int i = 0;  i < data.length;  i += 3) {
      // both x and y are given in inverse direction in result.txt
      int x = -data[i];
      int y = -data[i+1];
      int brightness = data[i+2];
      if (brightness == 0) {
        moveToPending = true;
        offset = new Point(x, y);
      }
      else {
        if (moveToPending) {
          path.moveTo(offset.x, offset.y);
          moveToPending = false;
        }
        path.lineTo(x, y);
      }
    }
  }

  /**
   *  Constructor.
   *  Creates the glyph from http://www.too-late.de/result.txt line, extract
   *  of ROM data.
   *
   *  @param data ROM data
   *  @param bounds bounds to use for this glyph
   */
  public Glyph(byte[] data, Rectangle bounds)
  {
    this(data);
    this.bounds = bounds;
  }

  /**
   * Draw the object and translate the graphics context.
   *
   * @param g graphics context
   * @param scaling scaling to used for drawing
   */
  public void drawAndTranslate(Graphics2D g, double scaling)
  {
    if (scaling != 1) {
      g.draw(AffineTransform.getScaleInstance(scaling, scaling).createTransformedShape(path));
      g.translate(scaling*offset.x,
                  scaling*offset.y);
    }
    else {
      g.draw(path);
      g.translate(offset.x, offset.y);
    }
  }

  /**
   *  Get the offset after this path is drawn.
   *  @return offset
   */
  public Point getOffset()
  {
    return offset;
  }

  /**
   *  Get the bounds of this glyph.
   *  This takes care of that some glyphs may be empty but have useful bounds nevertheless like the space character,
   *  which will not be indicated by using the bounds of the shape.
   *  @return glyph bounds
   */
  public Rectangle getBounds()
  {
    return getBounds(IDENTITY);
  }

  /**
   *  Get the bounds of this glyph.
   *  This takes care of that some glyphs may be empty but have useful bounds nevertheless like the space character,
   *  which will not be indicated by using the bounds of the shape.
   *  @param trafo transformation under which to calculate the bounds
   *  @return glyph bounds
   */
  public Rectangle getBounds(AffineTransform trafo)
  {
    if (bounds != null) {
      return trafo.createTransformedShape(bounds).getBounds();
    }
    else {
      return trafo.createTransformedShape(getPath()).getBounds();
    }
  }

  /**
   *  Get the bounds of this glyph.
   *  This takes care of that some glyphs may be empty but have useful bounds nevertheless like the space character,
   *  which will not be indicated by using the bounds of the shape.
   *  @param scale scaling to use
   *  @return glyph bounds
   */
  public Rectangle getBounds(double scale)
  {
    return getBounds(AffineTransform.getScaleInstance(scale, scale));
  }

  /**
   *  Get the path.
   *  @return path
   */
  public Shape getPath()
  {
    return path;
  }

  /**
   *  Get the path for a certain scaling.
   *  @param scale scaling
   *  @return path
   */
  public Shape getPath(double scale)
  {
    return AffineTransform.getScaleInstance(scale, scale).createTransformedShape(path);
  }
}
