/**
 *  Licensed under GPL. For more information, see
 *    http://jaxodraw.sourceforge.net/license.html
 *  or the LICENSE file in the jaxodraw distribution.
 */
package net.sf.jaxodraw.util.graphics;

import java.awt.Color;
import java.awt.Composite;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.Paint;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ImageObserver;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.RenderableImage;

import java.text.AttributedCharacterIterator;

import java.util.Map;


/** Wrapper around an existing Graphics2D.
 * All methods except two create() are delegated.
 * @since 2.0
 */
public class JaxoWrapperGraphics2D extends Graphics2D implements Cloneable {
    private Graphics2D graphics;

    /** Constructor.
     * @param g The initial graphics object.
     */
    protected JaxoWrapperGraphics2D(final Graphics2D g) {
        super();
        graphics = g;
    }

    /** A clone which wraps the same Graphics2D as this.
     * @return A clone of the Graphics2D.
     */
    protected Object copy() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            throw new Error(e);
        }
    }

    /** A clone which wraps the given Graphics2D.
     * @param g The graphics object to clone.
     * @return A clone of the Graphics2D.
     */
    protected JaxoWrapperGraphics2D clone(final Graphics2D g) {
        final JaxoWrapperGraphics2D result = (JaxoWrapperGraphics2D) copy();
        result.graphics = g;
        return result;
    }

    /** A JaxoWrapperGraphics2D wrapping a Graphics2D obtained
     * from the wrapped Graphics' create().
     * @return A new graphics object.
     */
    public Graphics create() {
        return clone((Graphics2D) graphics.create());
    }

    /** A JaxoWrapperGraphics2D wrapping a Graphics2D obtained
     * from the wrapped Graphics' create(...).
     * @param x The x coordinate.
     * @param y The y coordinate.
     * @param w The width.
     * @param h The height.
     * @return A new graphics object.
     */
    @Override
    public Graphics create(final int x, final int y, final int w, final int h) {
        return clone((Graphics2D) graphics.create(x, y, w, h));
    }

    /// Everything else is delegated

    /** {@inheritDoc} */
    public void dispose() {
        graphics.dispose();
    }

    /** {@inheritDoc} */
    public void setPaintMode() {
        graphics.setPaintMode();
    }

    /** {@inheritDoc} */
    public void translate(final int x, final int y) {
        graphics.translate(x, y);
    }

    /** {@inheritDoc} */
    public void clearRect(final int x, final int y, final int width, final int height) {
        graphics.clearRect(x, y, width, height);
    }

    /** {@inheritDoc} */
    public void clipRect(final int x, final int y, final int width, final int height) {
        graphics.clipRect(x, y, width, height);
    }

    /** {@inheritDoc} */
    public void drawLine(final int x1, final int y1, final int x2, final int y2) {
        graphics.drawLine(x1, y1, x2, y2);
    }

    /** {@inheritDoc} */
    public void drawOval(final int x, final int y, final int width, final int height) {
        graphics.drawOval(x, y, width, height);
    }

    /** {@inheritDoc} */
    @Override
    public void drawRect(final int x, final int y, final int width, final int height) {
        graphics.drawRect(x, y, width, height);
    }

    /** {@inheritDoc} */
    public void fillOval(final int x, final int y, final int width, final int height) {
        graphics.fillOval(x, y, width, height);
    }

    /** {@inheritDoc} */
    public void fillRect(final int x, final int y, final int width, final int height) {
        graphics.fillRect(x, y, width, height);
    }

    /** {@inheritDoc} */
    public void setClip(final int x, final int y, final int width, final int height) {
        graphics.setClip(x, y, width, height);
    }

    /** {@inheritDoc} */
    @Override
    public boolean hitClip(final int x, final int y, final int width, final int height) {
        return graphics.hitClip(x, y, width, height);
    }

    /** {@inheritDoc} */
    public void copyArea(final int x, final int y, final int width, final int height, final int dx, final int dy) {
        graphics.copyArea(x, y, width, height, dx, dy);
    }

    /** {@inheritDoc} */
    public void drawArc(final int x, final int y, final int width, final int height, final int startAngle, final int arcAngle) {
        graphics.drawArc(x, y, width, height, startAngle, arcAngle);
    }

    /** {@inheritDoc} */
    public void drawRoundRect(final int x, final int y, final int width, final int height, final int arcWidth, final int arcHeight) {
        graphics.drawRoundRect(x, y, width, height, arcWidth, arcHeight);
    }

    /** {@inheritDoc} */
    public void fillArc(final int x, final int y, final int width, final int height, final int startAngle, final int arcAngle) {
        graphics.fillArc(x, y, width, height, startAngle, arcAngle);
    }

    /** {@inheritDoc} */
    public void fillRoundRect(final int x, final int y, final int width, final int height, final int arcWidth, final int arcHeight) {
        graphics.fillRoundRect(x, y, width, height, arcWidth, arcHeight);
    }

    /** {@inheritDoc} */
    @Override
    public void draw3DRect(final int x, final int y, final int width, final int height, final boolean raised) {
        graphics.draw3DRect(x, y, width, height, raised);
    }

    /** {@inheritDoc} */
    @Override
    public void fill3DRect(final int x, final int y, final int width, final int height, final boolean raised) {
        graphics.fill3DRect(x, y, width, height, raised);
    }

    /** {@inheritDoc} */
    @Override
    public void drawBytes(final byte[] data, final int offset, final int length, final int x, final int y) {
        graphics.drawBytes(data, offset, length, x, y);
    }

    /** {@inheritDoc} */
    @Override
    public void drawChars(final char[] data, final int offset, final int length, final int x, final int y) {
        graphics.drawChars(data, offset, length, x, y);
    }

    /** {@inheritDoc} */
    public void drawPolygon(final int[] xPoints, final int[] yPoints, final int nPoints) {
        graphics.drawPolygon(xPoints, yPoints, nPoints);
    }

    /** {@inheritDoc} */
    public void drawPolyline(final int[] xPoints, final int[] yPoints, final int nPoints) {
        graphics.drawPolyline(xPoints, yPoints, nPoints);
    }

    /** {@inheritDoc} */
    public void fillPolygon(final int[] xPoints, final int[] yPoints, final int nPoints) {
        graphics.fillPolygon(xPoints, yPoints, nPoints);
    }

    /** {@inheritDoc} */
    public Color getColor() {
        return graphics.getColor();
    }

    /** {@inheritDoc} */
    public void setColor(final Color c) {
        graphics.setColor(c);
    }

    /** {@inheritDoc} */
    public void setXORMode(final Color c1) {
        graphics.setXORMode(c1);
    }

    /** {@inheritDoc} */
    public Font getFont() {
        return graphics.getFont();
    }

    /** {@inheritDoc} */
    public void setFont(final Font font) {
        graphics.setFont(font);
    }

    /** {@inheritDoc} */
    @Override
    public FontMetrics getFontMetrics() {
        return graphics.getFontMetrics();
    }

    /** {@inheritDoc} */
    @Override
    public void drawPolygon(final Polygon p) {
        graphics.drawPolygon(p);
    }

    /** {@inheritDoc} */
    @Override
    public void fillPolygon(final Polygon p) {
        graphics.fillPolygon(p);
    }

    /** {@inheritDoc} */
    public Rectangle getClipBounds() {
        return graphics.getClipBounds();
    }

    /** {@inheritDoc} */
    public Shape getClip() {
        return graphics.getClip();
    }

    /** {@inheritDoc} */
    public void setClip(final Shape clip) {
        graphics.setClip(clip);
    }

    /** {@inheritDoc} */
    public FontMetrics getFontMetrics(final Font f) {
        return graphics.getFontMetrics(f);
    }

    /** {@inheritDoc} */
    @Override
    public Rectangle getClipBounds(final Rectangle r) {
        return graphics.getClipBounds(r);
    }

    /** {@inheritDoc} */
    public boolean drawImage(final java.awt.Image img, final int dx1, final int dy1, final int dx2, final int dy2,
        final int sx1, final int sy1, final int sx2, final int sy2, final ImageObserver observer) {
        return graphics.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer);
    }

    /** {@inheritDoc} */
    public boolean drawImage(final java.awt.Image img, final int x, final int y, final int width, final int height,
        final ImageObserver observer) {
        return graphics.drawImage(img, x, y, width, height, observer);
    }

    /** {@inheritDoc} */
    public boolean drawImage(final java.awt.Image img, final int x, final int y, final ImageObserver observer) {
        return graphics.drawImage(img, x, y, observer);
    }

    /** {@inheritDoc} */
    public boolean drawImage(final java.awt.Image img, final int dx1, final int dy1, final int dx2, final int dy2,
        final int sx1, final int sy1, final int sx2, final int sy2, final Color bgcolor, final ImageObserver observer) {
        return graphics.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer);
    }

    /** {@inheritDoc} */
    public boolean drawImage(final java.awt.Image img, final int x, final int y, final int width, final int height,
        final Color bgcolor, final ImageObserver observer) {
        return graphics.drawImage(img, x, y, width, height, bgcolor, observer);
    }

    /** {@inheritDoc} */
    public boolean drawImage(final Image img, final int x, final int y, final Color bgcolor, final ImageObserver observer) {
        return graphics.drawImage(img, x, y, bgcolor, observer);
    }

    /** {@inheritDoc} */
    public void rotate(final double theta) {
        graphics.rotate(theta);
    }

    /** {@inheritDoc} */
    public void scale(final double sx, final double sy) {
        graphics.scale(sx, sy);
    }

    /** {@inheritDoc} */
    public void shear(final double shx, final double shy) {
        graphics.shear(shx, shy);
    }

    /** {@inheritDoc} */
    public void translate(final double tx, final double ty) {
        graphics.translate(tx, ty);
    }

    /** {@inheritDoc} */
    public void rotate(final double theta, final double x, final double y) {
        graphics.rotate(theta, x, y);
    }

    /** {@inheritDoc} */
    public Color getBackground() {
        return graphics.getBackground();
    }

    /** {@inheritDoc} */
    public void setBackground(final Color color) {
        graphics.setBackground(color);
    }

    /** {@inheritDoc} */
    public Composite getComposite() {
        return graphics.getComposite();
    }

    /** {@inheritDoc} */
    public void setComposite(final Composite comp) {
        graphics.setComposite(comp);
    }

    /** {@inheritDoc} */
    public GraphicsConfiguration getDeviceConfiguration() {
        return graphics.getDeviceConfiguration();
    }

    /** {@inheritDoc} */
    public Paint getPaint() {
        return graphics.getPaint();
    }

    /** {@inheritDoc} */
    public void setPaint(final Paint paint) {
        graphics.setPaint(paint);
    }

    /** {@inheritDoc} */
    public RenderingHints getRenderingHints() {
        return graphics.getRenderingHints();
    }

    /** {@inheritDoc} */
    public void clip(final Shape s) {
        graphics.clip(s);
    }

    /** {@inheritDoc} */
    public void draw(final Shape s) {
        graphics.draw(s);
    }

    /** {@inheritDoc} */
    public void fill(final Shape s) {
        graphics.fill(s);
    }

    /** {@inheritDoc} */
    public Stroke getStroke() {
        return graphics.getStroke();
    }

    /** {@inheritDoc} */
    public void setStroke(final Stroke s) {
        graphics.setStroke(s);
    }

    /** {@inheritDoc} */
    public FontRenderContext getFontRenderContext() {
        return graphics.getFontRenderContext();
    }

    /** {@inheritDoc} */
    public void drawGlyphVector(final GlyphVector g, final float x, final float y) {
        graphics.drawGlyphVector(g, x, y);
    }

    /** {@inheritDoc} */
    public AffineTransform getTransform() {
        return graphics.getTransform();
    }

    /** {@inheritDoc}
     * @param tx the <code>AffineTransform</code> that was retrieved
     *           from the <code>getTransform</code> method
     */
    public void setTransform(final AffineTransform tx) {
        graphics.setTransform(tx);
    }

    /** {@inheritDoc}
     * @param tx the <code>AffineTransform</code> that was retrieved
     *           from the <code>getTransform</code> method
     */
    public void transform(final AffineTransform tx) {
        graphics.transform(tx);
    }

    /** {@inheritDoc} */
    public void drawString(final String str, final float x, final float y) {
        graphics.drawString(str, x, y);
    }

    /** {@inheritDoc} */
    public void drawString(final String str, final int x, final int y) {
        graphics.drawString(str, x, y);
    }

    /** {@inheritDoc} */
    public void drawString(final AttributedCharacterIterator iterator, final float x, final float y) {
        graphics.drawString(iterator, x, y);
    }

    /** {@inheritDoc} */
    public void drawString(final AttributedCharacterIterator iterator, final int x, final int y) {
        graphics.drawString(iterator, x, y);
    }

    /** {@inheritDoc} */
    public void addRenderingHints(final Map<?, ?> hints) {
        graphics.addRenderingHints(hints);
    }

    /** {@inheritDoc} */
    public void setRenderingHints(final Map<?, ?> hints) {
        graphics.setRenderingHints(hints);
    }

    /** {@inheritDoc} */
    public boolean hit(final Rectangle rect, final Shape s, final boolean onStroke) {
        return graphics.hit(rect, s, onStroke);
    }

    /** {@inheritDoc} */
    public void drawRenderedImage(final RenderedImage img, final AffineTransform xform) {
        graphics.drawRenderedImage(img, xform);
    }

    /** {@inheritDoc} */
    public void drawRenderableImage(final RenderableImage img, final AffineTransform xform) {
        graphics.drawRenderableImage(img, xform);
    }

    /** {@inheritDoc} */
    public void drawImage(final BufferedImage img, final BufferedImageOp op, final int x, final int y) {
        graphics.drawImage(img, op, x, y);
    }

    /** {@inheritDoc} */
    public Object getRenderingHint(final RenderingHints.Key hintKey) {
        return graphics.getRenderingHint(hintKey);
    }

    /** {@inheritDoc} */
    public void setRenderingHint(final RenderingHints.Key hintKey, final Object hintValue) {
        graphics.setRenderingHint(hintKey, hintValue);
    }

    /** {@inheritDoc} */
    public boolean drawImage(final Image img, final AffineTransform xform, final ImageObserver obs) {
        return graphics.drawImage(img, xform, obs);
    }
}
