/* 
 
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz

This file is part of C.a.R. software.

    C.a.R. is a free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, version 3 of the License.

    C.a.R. is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 */
 
 
 package rene.zirkel.graphics;

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.ImageObserver;
import java.io.PrintWriter;

import rene.gui.Global;
import rene.util.xml.SVGWriter;
import rene.zirkel.ZirkelFrame;
import rene.zirkel.objects.ConstructionObject;

class SvgFontMetrics extends FontMetrics {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public SvgFontMetrics() {
		super(new Font("Courier", 10, Font.PLAIN)); // a dummy font.
	}

	@Override
	public int stringWidth(final String s) {
		return s.length() * 10;
	}

	@Override
	public int getHeight() {
		return 12;
	}

	@Override
	public int getAscent() {
		return 2;
	}
}

/**
 * This is the Graphics class, you need to implement.
 */
public class MyGraphicsSvg extends MyGraphics {

	int W, H;
	PrintWriter Out;
	final static int STROKE_NORMAL = 0, STROKE_THIN = 1, STROKE_THICK = 2;
	final static int STYLE_NORMAL = 0, STYLE_THIN = 1, STYLE_THICK = 0;
	int Stroke = STROKE_NORMAL;
	Color col, fillcol;
	SvgFontMetrics MFM = new SvgFontMetrics();
	int yoffset = 6000;
	int FontH = 12;
	SVGWriter svg;

	public MyGraphicsSvg(final PrintWriter out, final int w, final int h) {
		svg = new SVGWriter(out);
		svg.startSVG(w, h);
		W = w;
		H = h;
	}

	public void close() {
		svg.endTagNewLine("svg");
	}

	@Override
	public void setColor(final Color c) {
		col = c;
	}

	public void setFillcolor(final Color c) {
		fillcol = c;
	}

	@Override
	public void setColor(final ConstructionObject o) {
		if (o.isJobTarget()) {
			setColor(ZirkelFrame.TargetColor);
		} else if (o.selected()) {
			setColor(ZirkelFrame.SelectColor);
		} else {
			if (o.getColorType() == ConstructionObject.THIN) {
				final int i = o.getColorIndex();
				if (o.isHidden()) {
					setColor(ZirkelFrame.BrighterLightColors[i]);
				} else {
					setColor(ZirkelFrame.LightColors[i]);
				}
			} else {
				final int i = o.getColorIndex();
				if (o.isHidden()) {
					setColor(ZirkelFrame.BrighterColors[i]);
				} else {
					setColor(ZirkelFrame.Colors[i]);
				}
			}
			if (o.getColorType() == ConstructionObject.THIN) {
				Stroke = STROKE_THIN;
			} else if (o.getColorType() == ConstructionObject.THICK) {
				Stroke = STROKE_THICK;
			} else {
				Stroke = STROKE_NORMAL;
			}
		}
	}

	@Override
	public void setFillColor(final ConstructionObject o) {
		if (o.isJobTarget()) {
			setFillcolor(ZirkelFrame.TargetColor);
		} else {
			if (o.getColorType() != ConstructionObject.THICK) {
				final int i = o.getColorIndex();
				if (o.isHidden()) {
					setFillcolor(ZirkelFrame.BrighterLightColors[i]);
				} else {
					setFillcolor(ZirkelFrame.LightColors[i]);
				}
			} else {
				final int i = o.getColorIndex();
				if (o.isHidden()) {
					setFillcolor(ZirkelFrame.BrighterColors[i]);
				} else {
					setFillcolor(ZirkelFrame.Colors[i]);
				}
			}
		}
	}

	@Override
	public void setLabelColor(final ConstructionObject o) {
		if (o.labelSelected()) {
			setColor(ZirkelFrame.SelectColor);
		} else if (o.isFilled()) {
			final int type = o.getColorType();
			o.setColorType(ConstructionObject.NORMAL);
			setColor(o);
			o.setColorType(type);
		} else {
			setColor(o);
		}
	}

	@Override
	public void clearRect(final int x, final int y, final int w, final int h,
			final Color c) {
	}

	@Override
	public void drawRect(final double x, final double y, double w, double h) {
		svg.startTagStart("path");
		w--;
		h--;
		svg.printArg("d", "M " + x + " " + y + " H " + (x + w) + " V "
				+ (y + h) + " H " + x + " Z");
		svg.printArg("style", "fill:none;stroke:" + rgb() + ";stroke-width:1");
		svg.finishTagNewLine();
	}

	public String rgb() {
		return "rgb(" + col.getRed() + "," + col.getGreen() + ","
		+ col.getBlue() + ")";
	}

	public String frgb() {
		return "rgb(" + fillcol.getRed() + "," + fillcol.getGreen() + ","
		+ fillcol.getBlue() + ")";
	}

	@Override
	public void drawLine(final double x, final double y, final double x1,
			final double y1) {
		svg.startTagStart("line");
		svg.printArg("x1", "" + x);
		svg.printArg("y1", "" + y);
		svg.printArg("x2", "" + x1);
		svg.printArg("y2", "" + y1);
		switch (Stroke) {
		case STROKE_NORMAL:
			svg.printArg("style", "stroke:" + rgb() + ";stroke-width:1");
			break;
		case STROKE_THICK:
			svg.printArg("style", "stroke:" + rgb() + ";stroke-width:3");
			break;
		case STROKE_THIN:
			svg.printArg("style", "stroke:" + rgb()
					+ ";stroke-width:1;fill:none;stroke-dasharray:5,5");
			break;
		}
		svg.finishTagNewLine();
	}

	@Override
	public void drawThickLine(final double x, final double y, final double x1,
			final double y1) {
		svg.startTagStart("line");
		svg.printArg("x1", "" + x);
		svg.printArg("y1", "" + y);
		svg.printArg("x2", "" + x1);
		svg.printArg("y2", "" + y1);
		svg.printArg("style", "stroke:" + rgb() + ";stroke-width:3");
		svg.finishTagNewLine();
	}

	@Override
	public void drawLine(final double x, final double y, final double x1,
			final double y1, final ConstructionObject o) {
		svg.startTagStart("line");
		svg.printArg("x1", "" + x);
		svg.printArg("y1", "" + y);
		svg.printArg("x2", "" + x1);
		svg.printArg("y2", "" + y1);
		svg.printArg("style", "stroke:" + rgb() + ";stroke-width:1");
		svg.finishTagNewLine();
	}

	@Override
	public void drawArc(final double x, final double y, final double w,
			final double h, final double a, final double b) {
		final double x0 = Math.round(x + w / 2.0 + w
				* Math.cos(a / 180 * Math.PI) / 2);
		final double y0 = Math.round(y + h / 2.0 - h
				* Math.sin(a / 180 * Math.PI) / 2);
		final double x1 = Math.round(x + w / 2.0 + w
				* Math.cos((a + b) / 180 * Math.PI) / 2);
		final double y1 = Math.round(y + h / 2.0 - h
				* Math.sin((a + b) / 180 * Math.PI) / 2);
		int f = 0;
		if (b > 180) {
			f = 1;
		}
		svg.startTagStart("path");
		svg.printArg("d", "M " + x0 + " " + y0 + " A " + (w / 2) + " "
				+ (h / 2) + " 0 " + f + " 0 " + x1 + " " + y1);
		svg.printArg("style", "stroke:" + rgb() + ";stroke-width:1;fill:none");
		svg.finishTagNewLine();
	}

	@Override
	public void drawArc(double x, double y, double w, double h, final double a,
			final double b, final ConstructionObject o) {
		w = w / 2;
		h = h / 2;
		x += w;
		y += h;
		final double x0 = Math.round(x + w * Math.cos(a / 180 * Math.PI));
		final double y0 = Math.round(y - h * Math.sin(a / 180 * Math.PI));
		final double x1 = Math.round(x + w * Math.cos((a + b) / 180 * Math.PI));
		final double y1 = Math.round(y - h * Math.sin((a + b) / 180 * Math.PI));
		int f = 0;
		if (b > 180) {
			f = 1;
		}
		svg.startTagStart("path");
		svg.printArg("d", "M " + x0 + " " + y0 + " A " + w + " " + h + " 0 "
				+ f + " 0 " + x1 + " " + y1);
		switch (Stroke) {
		case STROKE_NORMAL:
			svg.printArg("style", "stroke:" + rgb()
					+ ";stroke-width:1;fill:none");
			break;
		case STROKE_THICK:
			svg.printArg("style", "stroke:" + rgb()
					+ ";stroke-width:3;fill:none");
			break;
		case STROKE_THIN:
			svg.printArg("style", "stroke:" + rgb()
					+ ";stroke-width:1;fill:none;stroke-dasharray:5,5");
			break;
		}
		svg.finishTagNewLine();
	}

	@Override
	public FontMetrics getFontMetrics() {
		return MFM;
	}

	@Override
	public void drawString(final String s, final double x, final double y) {
		svg.startTagStart("text");
		svg.printArg("x", "" + x);
		svg.printArg("y", "" + (y + 10));
		svg
		.printArg("style", "font-size:"
				+ FontH
				+ ";fill:"
				+ rgb()
				+ ";font-weight:"
				+ (Global.getParameter("font.bold", false) ? "gold"
						: "normal"));
		svg.startTagEnd();
		svg.print(s);
		svg.endTag("text");
	}

	@Override
	public void drawOval(double x, double y, double w, double h) {
		svg.startTagStart("ellipse");
		w = w / 2;
		h = h / 2;
		x += w;
		y += h;
		svg.printArg("cx", "" + x);
		svg.printArg("cy", "" + y);
		svg.printArg("rx", "" + w);
		svg.printArg("ry", "" + h);
		svg.printArg("style", "stroke:" + rgb() + ";stroke-width:1;fill:none");
		svg.finishTagNewLine();
	}

	@Override
	public void drawOval(double x, double y, double w, double h,
			final ConstructionObject o) {
		svg.startTagStart("ellipse");
		w = w / 2;
		h = h / 2;
		x += w;
		y += h;
		svg.printArg("cx", "" + x);
		svg.printArg("cy", "" + y);
		svg.printArg("rx", "" + w);
		svg.printArg("ry", "" + h);
		switch (Stroke) {
		case STROKE_NORMAL:
			svg.printArg("style", "stroke:" + rgb()
					+ ";fill:none;stroke-width:1");
			break;
		case STROKE_THICK:
			svg.printArg("style", "stroke:" + rgb()
					+ ";fill:none;stroke-width:3");
			break;
		case STROKE_THIN:
			svg.printArg("style", "stroke:" + rgb()
					+ ";stroke-width:1;fill:none;stroke-dasharray:5,5");
			break;
		}
		svg.finishTagNewLine();
	}

	@Override
	public void fillRect(final double x, final double y, double w, double h,
			final boolean outline, final boolean transparent,
			final ConstructionObject o) {
		svg.startTagStart("path");
		w--;
		h--;
		svg.printArg("d", "M " + x + " " + y + " H " + (x + w) + " V "
				+ (y + h) + " H " + x + " Z");
		svg.printArg("style", "fill:" + rgb() + ";stroke:" + rgb()
				+ ";stroke-width:1");
		svg.finishTagNewLine();
	}

	@Override
	public void fillArc(final double x, final double y, final double w,
			final double h, final double a, final double b,
			final boolean outline, final boolean transparent,
			final boolean arc, final ConstructionObject o) {
		setFillColor(o);
		final int x0 = (int) (Math.round(x + w / 2.0 + w
				* Math.cos(a / 180 * Math.PI) / 2));
		final int y0 = (int) (Math.round(y + h / 2.0 - h
				* Math.sin(a / 180 * Math.PI) / 2));
		final int x1 = (int) (Math.round(x + w / 2.0 + w
				* Math.cos((a + b) / 180 * Math.PI) / 2));
		final int y1 = (int) (Math.round(y + h / 2.0 - h
				* Math.sin((a + b) / 180 * Math.PI) / 2));
		int f = 0;
		if (b > 180) {
			f = 1;
		}
		svg.startTagStart("path");
		if (arc) {
			svg.printArg("d", "M " + (x + w / 2) + " " + (y + h / 2) + " L "
					+ x0 + " " + y0 + " A " + (w / 2) + " " + (h / 2) + " 0 "
					+ f + " 0 " + x1 + " " + y1 + " L " + (x + w / 2) + " "
					+ (y + h / 2));
		} else {
			svg.printArg("d", "M " + x0 + " " + y0 + " A " + (w / 2) + " "
					+ (h / 2) + " 0 " + f + " 0 " + x1 + " " + y1 + " L " + x0
					+ " " + y0);
		}
		switch (Stroke) {
		case STROKE_NORMAL:
			svg.printArg("style", "fill:" + frgb()
					+ (transparent && !o.isSolid() ? ";fill-opacity:0.5" : ""));
			break;
		case STROKE_THICK:
			svg.printArg("style", "fill:" + frgb());
			break;
		case STROKE_THIN:
			svg.printArg("style", "fill:" + frgb()
					+ (transparent && !o.isSolid() ? ";fill-opacity:0.5" : ""));
			break;
		}
		svg.finishTagNewLine();
		if (outline) {
			setColor(o);
			drawArc(x, y, w, h, a, b);
		}
	}

	@Override
	public void fillOval(final double x, final double y, final double w,
			final double h, final boolean outline, final boolean transparent,
			final ConstructionObject o) {
		setFillColor(o);
		svg.startTagStart("ellipse");
		svg.printArg("cx", "" + (x + w / 2));
		svg.printArg("cy", "" + (y + h / 2));
		svg.printArg("rx", "" + (w / 2));
		svg.printArg("ry", "" + (h / 2));
		switch (Stroke) {
		case STROKE_NORMAL:
			svg.printArg("style", "fill:" + frgb()
					+ (transparent && !o.isSolid() ? ";fill-opacity:0.5" : ""));
			break;
		case STROKE_THICK:
			svg.printArg("style", "fill:" + frgb());
			break;
		case STROKE_THIN:
			svg.printArg("style", "fill:" + frgb()
					+ (transparent && !o.isSolid() ? ";fill-opacity:0.5" : ""));
			break;
		}
		svg.finishTagNewLine();
		if (outline) {
			setColor(o);
			drawOval(x, y, w, h);
		}
	}

	@Override
	public void fillPolygon(final double x[], final double y[], final int n,
			final boolean outline, final boolean transparent,
			final ConstructionObject o) {

		setFillColor(o);
		svg.startTagStart("path");
		String s = "M " + x[0] + " " + y[0];
		for (int i = 1; i < n; i++) {
			s = s + " L " + x[i] + " " + y[i];
		}
		s = s + " L " + x[0] + " " + y[0];
		svg.printArg("d", s);
		switch (Stroke) {
		case STROKE_NORMAL:
			svg.printArg("style", "fill:" + frgb()
					+ (transparent && !o.isSolid() ? ";fill-opacity:0.5" : ""));
			break;
		case STROKE_THICK:
			svg.printArg("style", "fill:" + frgb());
			break;
		case STROKE_THIN:
			svg.printArg("style", "fill:" + frgb()
					+ (transparent && !o.isSolid() ? ";fill-opacity:0.5" : ""));
			break;
		}
		svg.finishTagNewLine();
		if (outline) {
			svg.startTagStart("path");
			svg.printArg("d", s);
			setColor(o);
			svg.printArg("style", "fill:none;stroke:" + rgb()
					+ ";stroke-width:1");
			svg.finishTagNewLine();
		}
	}

	@Override
	public void drawImage(final Image i, final int x, final int y,
			final ImageObserver o) {
	}

	@Override
	public void drawImage(final Image i, final int x, final int y, final int w,
			final int h, final ImageObserver o) {
	}

	@Override
	public void setFont(final int h, final boolean bold) {
		FontH = h;
	}

	int fsize;
	boolean flarge, fbold;
	int ffactor = Global.getParameter("ffactor", 130);

	@Override
	public void setDefaultFont(final int h, final boolean large,
			final boolean bold) {
		fsize = h;
		flarge = large;
		fbold = bold;
		ffactor = Global.getParameter("ffactor", 130);
		setFont(large, bold);
	}

	@Override
	public void setFont(final boolean large, final boolean bold) {
		int size = fsize;
		if (large) {
			size = size * ffactor / 100;
		}
		if (flarge) {
			size = size * ffactor / 100;
		}
		setFont(size, bold || fbold);
	}

	@Override
	public void drawImage(final Image i, final double x, final double y,
			final double x1, final double y1, final double x2, final double y2,
			final ImageObserver o) {
	}

	@Override
	public Graphics getGraphics() {
		return null;
	}

	@Override
	public int stringWidth(final String s) {
		return getFontMetrics().stringWidth(s);
	}

	@Override
	public int stringHeight(final String s) {
		return getFontMetrics().getHeight();
	}

	@Override
	public int drawStringExtended(final String s, final double x, final double y) {
		drawString(s, x, y + getFontMetrics().getAscent());
		return getFontMetrics().getHeight();
	}

	@Override
	public int stringAscent(final String s) {
		return getFontMetrics().getAscent();
	}

	@Override
	public void fillOval(final double x, final double y, final double w,
			final double h, final Color WithColor) {
	}

	@Override
	public void fillRect(final double x, final double y, final double w,
			final double h, final Color WithColor) {
	}

	@Override
	public void drawDiamond(final double x, final double y, final double w,
			final boolean isThick, final ConstructionObject o) {
	}

	@Override
	public void drawDcross(final double x, final double y, final double w,
			final boolean isThick, final ConstructionObject o) {
	}

	@Override
	public void setAntialiasing(final boolean bool) {
	}

	@Override
	public void drawAxisLine(final double x, final double y, final double x1,
			final double y1) {
	}

	@Override
	public void fillPolygon(final double[] x, final double[] y, final int n,
			final ConstructionObject o) {
		setFillColor(o);
		String s = "M " + x[0] + " " + y[0];
		for (int i = 1; i < n; i++) {
			s = s + " L " + x[i] + " " + y[i];
		}
		s = s + " L " + x[0] + " " + y[0];
		if (o.isFilled()) {
			svg.startTagStart("path");

			svg.printArg("d", s);
			switch (Stroke) {
			case STROKE_NORMAL:
				svg.printArg("style", "fill:"
						+ frgb()
						+ (o.getColorType() != ConstructionObject.THICK
								&& !o.isSolid() ? ";fill-opacity:0.5" : ""));
				break;
			case STROKE_THICK:
				svg.printArg("style", "fill:" + frgb());
				break;
			case STROKE_THIN:
				svg.printArg("style", "fill:"
						+ frgb()
						+ (o.getColorType() != ConstructionObject.THICK
								&& !o.isSolid() ? ";fill-opacity:0.5" : ""));
				break;
			}
			svg.finishTagNewLine();
		}

		if (!o.isFilled() || o.indicated() || o.selected()
				|| o.getColorType() == ConstructionObject.NORMAL) {
			svg.startTagStart("path");
			svg.printArg("d", s);
			setColor(o);
			String strk = "";
			switch (Stroke) {
			case STROKE_NORMAL:
				strk = "1";
				break;
			case STROKE_THICK:
				strk = "2";
				break;
			case STROKE_THIN:
				strk = "0.5";
				break;
			}
			svg.printArg("style", "fill:none;stroke:" + frgb()
					+ ";stroke-width:" + strk);
			svg.finishTagNewLine();
		}
	}
}
