// IMPORT FROM PICCOLOX

package netmatch.piccolox;

import edu.umd.cs.piccolo.util.PAffineTransform;
import edu.umd.cs.piccolo.util.PPaintContext;

import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.*;
import java.io.Serializable;
import java.util.Arrays;

import sun.dc.path.*;
import sun.dc.pr.PathDasher;
import sun.dc.pr.PathStroker;

public class PFixedWidthStroke implements Stroke, Serializable {
  public class FillAdapter implements PathConsumer {
    boolean closed;
    GeneralPath path;

    public Shape getShape() {
      return path;
    }

    public void beginPath() {
    }

    public void beginSubpath(float f, float f1) {
      if(closed) {
        path.closePath();
        closed = false;
      }
      path.moveTo(f, f1);
    }

    public void appendLine(float f, float f1) {
      path.lineTo(f, f1);
    }

    public void appendQuadratic(float f, float f1, float f2, float f3) {
      path.quadTo(f, f1, f2, f3);
    }

    public void appendCubic(float f, float f1, float f2, float f3, float f4, float f5) {
      path.curveTo(f, f1, f2, f3, f4, f5);
    }

    public void closedSubpath() {
      closed = true;
    }

    public void endPath() {
      if(closed) {
        path.closePath();
        closed = false;
      }
    }

    public void useProxy(FastPathProducer fastpathproducer) throws PathException {
      fastpathproducer.sendTo(this);
    }

    public long getCPathConsumer() {
      return 0L;
    }

    public void dispose() {
    }

    public PathConsumer getConsumer() {
      return null;
    }

    public FillAdapter() {
      path = PFixedWidthStroke.TEMP_PATH;
      path.reset();
    }
  }

  private static PAffineTransform TEMP_TRANSFORM = new PAffineTransform();
  private static GeneralPath TEMP_PATH = new GeneralPath(1);
  public static final int JOIN_MITER = 0;
  public static final int JOIN_ROUND = 1;
  public static final int JOIN_BEVEL = 2;
  public static final int CAP_BUTT = 0;
  public static final int CAP_ROUND = 1;
  public static final int CAP_SQUARE = 2;
  private float width;
  private int join;
  private int cap;
  private float miterlimit;
  private float dash[];
  private float dash_phase;
  public static final int RasterizerCaps[] = {
      30,10,20
  };
  public static final int RasterizerCorners[] = {
      50,10,40
  };

  public PFixedWidthStroke() {
    this(1.0F, 2, 0, 10F, null, 0.0F);
  }

  public PFixedWidthStroke(float f) {
    this(f, 2, 0, 10F, null, 0.0F);
  }

  public PFixedWidthStroke(float f, int i, int j) {
    this(f, i, j, 10F, null, 0.0F);
  }

  public PFixedWidthStroke(float f, int i, int j, float f1) {
    this(f, i, j, f1, null, 0.0F);
  }

  public PFixedWidthStroke(float f, int i, int j, float f1, float af[], float f2) {
    if(f < 0.0F)
      throw new IllegalArgumentException("negative width");
    if(i != 0 && i != 1 && i != 2)
      throw new IllegalArgumentException("illegal end cap value");
    if(j == 0) {
      if(f1 < 1.0F)
        throw new IllegalArgumentException("miter limit < 1");
    }
    else if(j != 1 && j != 2)
      throw new IllegalArgumentException("illegal line join value");
    if(af != null) {
      if(f2 < 0.0F)
        throw new IllegalArgumentException("negative dash phase");
      boolean flag = true;
      for(int k = 0;k < af.length;k++) {
        float f3 = af[k];
        if((double) f3 > 0.0D) {
          flag = false;
          continue;
        }
        if((double) f3 < 0.0D)
          throw new IllegalArgumentException("negative dash length");
      }

      if(flag)
        throw new IllegalArgumentException("dash lengths all zero");
    }
    width = f;
    cap = i;
    join = j;
    miterlimit = f1;
    if(af != null)
      dash = (float[])af.clone();
    dash_phase = f2;
  }

  public Object clone() {
    try {
      return super.clone();
    }
    catch(CloneNotSupportedException clonenotsupportedexception) {
      clonenotsupportedexception.printStackTrace();
      return null;
    }
  }

  public Shape createStrokedShape(Shape shape) {
    FillAdapter filladapter = new FillAdapter();
    PathStroker pathstroker = new PathStroker(filladapter);
    float f = 1.0F;
    if(PPaintContext.CURRENT_PAINT_CONTEXT != null)
      f = width / (float) PPaintContext.CURRENT_PAINT_CONTEXT.getScale();
    Rectangle2D rectangle2d = shape.getBounds2D();
    double d = 1.0D;
    if(rectangle2d.getWidth() > rectangle2d.getHeight()) {
      if(rectangle2d.getWidth() != 0.0D)
        d = (rectangle2d.getWidth() - (double) f) / rectangle2d.getWidth();
    }
    else if(rectangle2d.getHeight() != 0.0D)
      d = (rectangle2d.getHeight() - (double) f) / rectangle2d.getHeight();
    TEMP_TRANSFORM.setToIdentity();
    TEMP_TRANSFORM.scaleAboutPoint(d, rectangle2d.getCenterX(), rectangle2d.getCenterY());
    pathstroker.setPenDiameter(f);
    PathIterator pathiterator = shape.getPathIterator(TEMP_TRANSFORM);
    pathstroker.setPenT4(null);
    pathstroker.setCaps(RasterizerCaps[cap]);
    pathstroker.setCorners(RasterizerCorners[join], miterlimit);
    Object obj;
    if(dash != null) {
      PathDasher pathdasher = new PathDasher(pathstroker);
      pathdasher.setDash(dash, dash_phase);
      pathdasher.setDashT4(null);
      obj = pathdasher;
    }
    else {
      obj = pathstroker;
    }
    try {
      ((PathConsumer) (obj)).beginPath();
      boolean flag = false;
      float f1 = 0.0F;
      float f2 = 0.0F;
      float af[] = new float[6];
      for(;!pathiterator.isDone();pathiterator.next()) {
        int i = pathiterator.currentSegment(af);
        if(flag) {
          flag = false;
          if(i != 0)
            ((PathConsumer) (obj)).beginSubpath(f1, f2);
        }
        switch(i) {
          case 0:// '\0'
            f1 = af[0];
            f2 = af[1];
            ((PathConsumer) (obj)).beginSubpath(af[0], af[1]);
            break;

          case 1:// '\001'
            ((PathConsumer) (obj)).appendLine(af[0], af[1]);
            break;

          case 2:// '\002'
            ((PathConsumer) (obj)).appendQuadratic(af[0], af[1], af[2], af[3]);
            break;

          case 3:// '\003'
            ((PathConsumer) (obj)).appendCubic(af[0], af[1], af[2], af[3], af[4], af[5]);
            break;

          case 4:// '\004'
            ((PathConsumer) (obj)).closedSubpath();
            flag = true;
            break;
        }
      }

      ((PathConsumer) (obj)).endPath();
    }
    catch(PathException pathexception) {
      throw new InternalError("Unable to Stroke shape (" + pathexception.getMessage() + ")");
    }
    return filladapter.getShape();
  }

  public boolean equals(Object obj) {
    if(!(obj instanceof PFixedWidthStroke))
      return false;
    PFixedWidthStroke pfixedwidthstroke = (PFixedWidthStroke) obj;
    if(width != pfixedwidthstroke.width)
      return false;
    if(join != pfixedwidthstroke.join)
      return false;
    if(cap != pfixedwidthstroke.cap)
      return false;
    if(miterlimit != pfixedwidthstroke.miterlimit)
      return false;
    if(dash != null) {
      if(dash_phase != pfixedwidthstroke.dash_phase)
        return false;
      if(!Arrays.equals(dash, pfixedwidthstroke.dash))
        return false;
    }
    else if(pfixedwidthstroke.dash != null)
      return false;
    return true;
  }

  public float[] getDashArray() {
    if(dash == null)
      return null;
    else
      return (float[]) dash.clone();
  }

  public float getDashPhase() {
    return dash_phase;
  }

  public int getEndCap() {
    return cap;
  }

  public int getLineJoin() {
    return join;
  }

  public float getLineWidth() {
    return width;
  }

  public float getMiterLimit() {
    return miterlimit;
  }

  public int hashCode() {
    int i = Float.floatToIntBits(width);
    i = i * 31 + join;
    i = i * 31 + cap;
    i = i * 31 + Float.floatToIntBits(miterlimit);
    if(dash != null) {
      i = i * 31 + Float.floatToIntBits(dash_phase);
      for(int j = 0;j < dash.length;j++)
        i = i * 31 + Float.floatToIntBits(dash[j]);

    }
    return i;
  }


}