/*  This file is part of the source code for 3D-XplorMath-J, Version 1.0 (January 2008).
 *  Copyright (c) 2008 The 3D-XplorMath Consortium (http://3d-xplormath.org).
 *  This source code is released under a BSD License, which allows redistribution   
 *  in source and binary form, with or without modification, provided copyright
 *  and license information are included, and with no warranty or guarantee of
 *  any kind.  For details, see http://3d-xplormath.org/j/source/BSDLicense.txt
 */
 
 package vmm.core.render;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

import sun.reflect.generics.reflectiveObjects.NotImplementedException;
import vmm.core.Transform;
import vmm.core.View;

public class GeometryRenderer2D implements Renderer2D {
	
	private ArrayList<GeometryElement2D> elements = new ArrayList<GeometryElement2D>();
	
	private View view;
	private Transform transform;
	private int width;
	private int height;
	protected boolean antialiased;
	protected Color currentColor;
	protected Stroke currentStroke;

	public void startRender(View view, Transform transform, int width,
			int height) {
		this.view = view;
		this.transform = transform;
		this.width = width;
		this.height = height;
		elements.clear();
		transform.setUpDrawInfo(null, 0, 0, width, height, view.getPreserveAspect(), view.getApplyGraphics2DTransform());
		this.currentColor = view.getForeground();
		this.currentStroke = new BasicStroke(transform.getDefaultStrokeSize());
	}

	public boolean restartRender(View view, Transform transform, int width,
			int height) {
		if (this.view != view || this.transform != transform || this.width != width || this.height != height)
			return false;
		transform.setUpDrawInfo(null, 0, 0, width, height, view.getPreserveAspect(), view.getApplyGraphics2DTransform());
		this.view = view;
		this.transform = transform;
		this.width = width;
		this.height = height;
		return true;
	}

	public void endRender() {
	}

	public void dispose() {
		transform = null;
		view = null;
		elements.clear();
	}
	
	protected void drawBackground(Graphics2D g) {
		g.setColor(view.getBackground());
		g.fillRect(0,0,width,height);
	}

	public void draw(Graphics2D g) {
		drawBackground(g);
		transform.setUpDrawInfo(g, 0, 0, width, height, view.getPreserveAspect(), view.getApplyGraphics2DTransform());
		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
				view.getAntialiased()? RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
		g.setColor(view.getForeground());
		for (GeometryElement2D element : elements)
			element.draw(transform, g);
		transform.finishDrawing();
	}

	public BufferedImage getImage(boolean alwaysCopy) { 
		BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
		Graphics2D g = image.createGraphics();
		draw(g);
		g.dispose();
		return image;
	}

	public void setColor(Color c) {
		currentColor = c;
		elements.add(new SetColor(c == null ? view.getForeground() : c));
	}

	public Color getColor() {
		return currentColor;
	}

	public Stroke getStroke() {
		return currentStroke;
	}

	public void setStroke(Stroke stroke) {
		currentStroke = stroke;
		elements.add(new SetStroke(stroke));
	}

	public void drawPixel(double x, double y) {
		elements.add(new Pixels2D(x, y));
	}

	public void drawDot(Point2D pt, double diameter) {
		elements.add(new Dot2D(pt.getX(), pt.getY(), diameter));
	}

	public void drawPixels(Point2D[] points, int pointIndexStart,
			int pointIndexEnd) {
		elements.add(new Pixels2D(points, pointIndexStart, pointIndexEnd));
	}

	public void drawString(String s, double x, double y) {
		elements.add(new Text2D(s,x,y));
	}

	public void drawLine(double x1, double y1, double x2, double y2) {
		elements.add(new LineSegment2D(x1,y1,x2,y2));
	}

	public void drawCurve(Point2D[] points, int pointIndexStart,
			int pointIndexEnd) {
		elements.add(new Curve2D(points,pointIndexStart,pointIndexEnd));
	}

	public void drawOval(double x, double y, double width, double height) {
		elements.add(new RectShape2D(RectShape2D.OVAL, x, y, width, height));
	}

	public void fillOval(double x, double y, double width, double height) {
		elements.add(new RectShape2D(RectShape2D.FILLED_OVAL, x, y, width, height));
	}

	public void drawRect(double x, double y, double width, double height) {
		elements.add(new RectShape2D(RectShape2D.RECT, x, y, width, height));
	}

	public void fillRect(double x, double y, double width, double height) {
		elements.add(new RectShape2D(RectShape2D.FILLED_RECT, x, y, width, height));
	}

	public void drawCrosshair(double x, double y, int armlengthInPixels, int strokeWidthInPixels, Color color, Color background) {
		elements.add(new CrosshairElement2D(x,y,armlengthInPixels,strokeWidthInPixels,color,background));
	}

	public void setDrawAntialiased(boolean antialiased) {
		this.antialiased = antialiased;
		elements.add(new SetAntialiased(antialiased));
	}
	
	public boolean getDrawAntialiased() {
		return antialiased;
	}

}
