package plot;

import java.awt.*;
import real.Formats;

/** PlotPaths are the basic class drawn into RealCanvases.
	Drawing follows the PostScript model.
	Each path is an array of segments.
	Each segment is an array of coordinates.
	Stroking a path means drawing lines along the pieces.
	Filling it means turning each piece into a polygon. */
	
public class PlotPath {
	final static int INC = 128;

	RealGraphics gfx;

	Polygon segment[];
	Polygon currentSegment = null;
	int maxSegmentNo = INC;
	int segmentNo;
	
	// mark last moveto:
	int last[];
	int cp[];
	int N = 0;

	public PlotPath(RealGraphics gfx) {
		this.gfx = gfx;
		segment = new Polygon[INC];
		segmentNo = 0;
	}

	int[] currentPoint() {
		return(cp);
	}

	// - moves --------------------------------------------

	void movetoPoint(int q[]) {
		if (segmentNo >= maxSegmentNo) {
			// System.out.println("overflow!");
			maxSegmentNo += INC;
			Polygon newseg[] = new Polygon[maxSegmentNo];
			for (int i=0;i<segmentNo;i++) {
				newseg[i] = segment[i];
			}
			segment = newseg;
		}
		segment[segmentNo] = new Polygon();
		currentSegment = segment[segmentNo++];
		currentSegment.addPoint(q[0], q[1]);
		last = q;
		cp = q;
	}

	public void moveto(double x, double y) {
		int q[] = gfx.toPoint(x, y);
		movetoPoint(q);
	}

	public void moveto(double p[]) {
		int q[] = gfx.toPoint(p);
		movetoPoint(q);
	}
	
	public void rmoveto(double x[]) throws NoCurrentPointException {
		if (cp != null) {
			int P[] = gfx.toRelativePoint(x);
			P[0] += cp[0];
			P[1] += cp[1];
			movetoPoint(P);
		} else {
			throw new NoCurrentPointException(); 
		}
	}

	public void rmoveto(double x, double y) throws NoCurrentPointException {
		if (cp != null) {
			int P[] = gfx.toRelativePoint(x, y);
			P[0] += cp[0];
			P[1] += cp[1];
			movetoPoint(P);
		} else {
			throw new NoCurrentPointException(); 
		}
	}

	// - lines --------------------------------------------

	public void lineto(double p[]) throws NoCurrentPointException {
		if (cp != null) {
			N++;
			int q[] = gfx.toPoint(p);
			currentSegment.addPoint(q[0], q[1]);
			cp = q;
		} else {
			throw new NoCurrentPointException(); 
		}
	}
	
	public void lineto(double x, double y) throws NoCurrentPointException {
		if (cp != null) {
			N++;
			int q[] = gfx.toPoint(x, y);
			currentSegment.addPoint(q[0], q[1]);
			cp = q;
		} else {
			throw new NoCurrentPointException(); 
		}
	}

	public void rlineto(double x, double y) throws NoCurrentPointException {
		if (cp != null) {
			N++;
			int P[] = gfx.toRelativePoint(x, y);
			cp[0] += P[0];
			cp[1] += P[1];
			currentSegment.addPoint(cp[0], cp[1]);
		} else {
			throw new NoCurrentPointException(); 
		}
	}

	// - curves -------------------------------------------
	
	public void curveto(double P[]) throws NoCurrentPointException {
		if (cp != null) {
			double P1[] = gfx.toFinePoint(P[0], P[1]);
			double P2[] = gfx.toFinePoint(P[2], P[3]);
			double P3[] = gfx.toFinePoint(P[4], P[5]);
			Curve.addCurve(currentSegment, P1, P2, P3);
			cp = new int[2];
			cp[0] = (int) P3[0];
			cp[1] = (int) P3[1];
		} else {
			throw new NoCurrentPointException(); 
		}
	}

	public void curveto(double P[][]) throws NoCurrentPointException {
		if (cp != null) {
			double q[][] = new double[3][];
			q[0] = gfx.toFinePoint(P[0]);
			q[1] = gfx.toFinePoint(P[1]);
			q[2] = gfx.toFinePoint(P[2]);
			Curve.addCurve(currentSegment, q[0], q[1], q[2]);
			cp = new int[2];
			cp[0] = (int) q[2][0];
			cp[1] = (int) q[2][1];
		} else {
			throw new NoCurrentPointException(); 
		}
	}

	// ----------------------------------------------------
	
	void drawPath(Polygon P) {
		int n = P.npoints;
		Graphics g = gfx.getGraphics();
		if (n > 0) {
			int x = P.xpoints[0];
			int y = P.ypoints[0];
			for (int i=1;i<P.npoints;i++) {
				int x1 = P.xpoints[i];
				int y1 = P.ypoints[i];
				g.drawLine(x, y, x1, y1);
				x = x1; y = y1;
			}
		}
	}

	public void close() {
		if (last != null) {
			currentSegment.addPoint(last[0], last[1]);
			movetoPoint(last);
		}
	}

	public void stroke() {
		for (int i=0;i<segmentNo;i++) {
			drawPath(segment[i]);
		}
	}

	public void stroke(Color c) {
		Color tmp = gfx.getColor();
		gfx.setColor(c);
		for (int i=0;i<segmentNo;i++) {
			drawPath(segment[i]);
		}
		gfx.setColor(tmp);
	}

	public void fill() {
		for (int i=0;i<segmentNo;i++) {
			gfx.fillPolygon(segment[i]);
		}
	}

	public void fill(Color c) {
		Color tmp = gfx.getColor();
		gfx.setColor(c);
		for (int i=0;i<segmentNo;i++) {
			gfx.fillPolygon(segment[i]);
		}
		gfx.setColor(tmp);
	}

	public String toString() {
		StringBuffer sb = new StringBuffer();
		for (int i=0;i<segmentNo;i++) {
			Polygon p = segment[i];
			for (int j=0;j<p.npoints;j++) {
				sb.append('(');
				sb.append(Formats.toString(p.xpoints[j]));
				sb.append(',');
				sb.append(Formats.toString(p.ypoints[j]));
				sb.append(')');
			}
		}
		return(new String(sb));
	} 
}

