content: // ===============================================================================
  // Authors: AFRL/RQQD
  // Organization: Air Force Research Laboratory, Aerospace Systems Directorate, Power and Control Division
  // 
  // Copyright (c) 2017 Government of the United State of America, as represented by
  // the Secretary of the Air Force.  No copyright is claimed in the United States under
  // Title 17, U.S. Code.  All Other Rights Reserved.
  // ===============================================================================
  
  /*
   * GRAL: GRAphing Library for Java(R)
   *
   * (C) Copyright 2009-2013 Erich Seifert <dev[at]erichseifert.de>,
   * Michael Seifert <mseifert[at]error-reports.org>
   *
   * This file is part of GRAL.
   *
   * GRAL is free software: you can redistribute it and/or modify
   * it under the terms of the GNU Lesser General Public License as published by
   * the Free Software Foundation, either version 3 of the License, or
   * (at your option) any later version.
   *
   * GRAL 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 Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public License
   * along with GRAL.  If not, see <http://www.gnu.org/licenses/>.
   */
  package de.erichseifert.gral.io.plots;
  
  import java.awt.Graphics2D;
  import java.awt.geom.Rectangle2D;
  import java.io.IOException;
  import java.io.OutputStream;
  import java.lang.reflect.Constructor;
  import java.lang.reflect.InvocationTargetException;
  import java.text.MessageFormat;
  import java.util.HashMap;
  import java.util.Map;
  
  import de.erichseifert.gral.graphics.Drawable;
  import de.erichseifert.gral.graphics.DrawingContext;
  import de.erichseifert.gral.graphics.DrawingContext.Quality;
  import de.erichseifert.gral.graphics.DrawingContext.Target;
  import de.erichseifert.gral.io.IOCapabilities;
  import de.erichseifert.gral.io.IOCapabilitiesStorage;
  import de.erichseifert.gral.util.Messages;
  
  /**
   * <p>Class that stores {@code Drawable} instances as vector graphics.
   * This implementation requires the <i>VectorGraphics2D</i> library to provide
   * support for the following file formats:</p>
   * <ul>
   *   <li>Encapsulated PostScript (EPS)</li>
   *   <li>Portable Document Format (PDF)</li>
   *   <li>Scalable Vector Graphics (SVG)</li>
   * </ul>
   *
   * <p>If the <i>VectorGraphics2D</i> library isn't available the file formats
   * aren't registered in the plug-in system. This class shouldn't be used directly
   * but using the {@link DrawableWriterFactory}.</p>
   */
  public class VectorWriter extends IOCapabilitiesStorage
  		implements DrawableWriter {
  	/** Mapping of MIME type string to {@code Graphics2D}lementation. */
  	private static final Map<String, Class<?>> graphics;
  	/** Java package that contains the VecorGraphics2D package. */
  	private static final String VECTORGRAPHICS2D_PACKAGE =
  		"de.erichseifert.vectorgraphics2d"; //$NON-NLS-1$
  
  	static {
  		graphics = new HashMap<String, Class<?>>();
  		Class<?> cls;
  
  		try {
  			cls = Class.forName(VECTORGRAPHICS2D_PACKAGE
  					+ ".EPSGraphics2D"); //$NON-NLS-1$
  			addCapabilities(new IOCapabilities(
  				"EPS", //$NON-NLS-1$
  				Messages.getString("ImageIO.epsDescription"), //$NON-NLS-1$
  				"application/postscript", //$NON-NLS-1$
  				new String[] {"eps", "epsf", "epsi"} //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
  			));
  			graphics.put("application/postscript", cls); //$NON-NLS-1$
  		} catch (ClassNotFoundException e) {
  			cls = null;
  		}
  
  		try {
  			cls = Class.forName(VECTORGRAPHICS2D_PACKAGE
  					+ ".PDFGraphics2D"); //$NON-NLS-1$
  			addCapabilities(new IOCapabilities(
  				"PDF", //$NON-NLS-1$
  				Messages.getString("ImageIO.pdfDescription"), //$NON-NLS-1$
  				"application/pdf", //$NON-NLS-1$
  				new String[] {"pdf"} //$NON-NLS-1$
  			));
  			graphics.put("application/pdf", cls); //$NON-NLS-1$
  		} catch (ClassNotFoundException e) {
  			cls = null;
  		}
  
  		try {
  			cls = Class.forName(VECTORGRAPHICS2D_PACKAGE
  					+ ".SVGGraphics2D"); //$NON-NLS-1$
  			addCapabilities(new IOCapabilities(
  				"SVG", //$NON-NLS-1$
  				Messages.getString("ImageIO.svgDescription"), //$NON-NLS-1$
  				"image/svg+xml", //$NON-NLS-1$
  				new String[] {"svg", "svgz"} //$NON-NLS-1$ //$NON-NLS-2$
  			));
  			graphics.put("image/svg+xml", cls); //$NON-NLS-1$
  		} catch (ClassNotFoundException e) {
  			cls = null;
  		}
  	}
  
  	/** Current data format as MIME type string. */
  	private final String mimeType;
  	/** Current {@cod{@code Graphics2D}ation used for rendering. */
  	private final Class<? extends Graphics2D> graphicsClass;
  
  	/**
  	 * Creates a new {@code VectorWriter} object with the specified
  	 * MIME-Type.
  	 * @param mimeType Output MIME-Type.
  	 */
  	@SuppressWarnings("unchecked")
  	protected VectorWriter(String mimeType) {
  		this.mimeType = mimeType;
  		Class<? extends Graphics2D> gfxCls = null;
  		try {
  			gfxCls = (Class<? extends Graphics2D>) graphics.get(mimeType);
  		} catch (ClassCastException e) {
  			gfxCls = null;
  		}
  		graphicsClass = gfxCls;
  		if (graphicsClass == null) {
  			throw new IllegalArgumentException(MessageFormat.format(
  				"Unsupported file format: {0}", mimeType)); //$NON-NLS-1$
  		}
  	}
  
  	/**
  	 * Stores the specified {@code Drawable} instance.
  	 * @param d {@code Drawable} to be written.
  	 * @param destination Stream to write to
  	 * @param width Width of the image.
  	 * @param height Height of the image.
  	 * @throws IOException if writing to stream fails
  	 */
  	public void write(Drawable d, OutputStream destination,
  			double width, double height) throws IOException {
  		write(d, destination, 0.0, 0.0, width, height);
  	}
  
  	/**
  	 * Stores the specified {@code Drawable} instance.
  	 * @param d {@code Drawable} to be written.
  	 * @param destination Stream to write to
  	 * @param x Horizontal position.
  	 * @param y Vertical position.
  	 * @param width Width of the image.
  	 * @param height Height of the image.
  	 * @throws IOException if writing to stream fails
  	 */
  	public void write(Drawable d, OutputStream destination,
  			double x, double y, double width, double height)
  			throws IOException {
  		try {
  			// Create instance of export class
  			Constructor<? extends Graphics2D> constructor =
  				graphicsClass.getConstructor(
  					double.class, double.class, double.class, double.class);
  			Graphics2D g = constructor.newInstance(x, y, width, height);
  
  			// Output data
  			Rectangle2D boundsOld = d.getBounds();
  			d.setBounds(x, y, width, height);
  			DrawingContext context =
  				new DrawingContext(g, Quality.QUALITY, Target.VECTOR);
  			d.draw(context);
  			byte[] data = (byte[]) graphicsClass.getMethod(
  				"getBytes").invoke(g); //$NON-NLS-1$
  			destination.write(data);
  			d.setBounds(boundsOld);
  		} catch (SecurityException e) {
  			throw new IllegalStateException(e);
  		} catch (NoSuchMethodException e) {
  			throw new IllegalStateException(e);
  		} catch (IllegalArgumentException e) {
  			throw new IllegalStateException(e);
  		} catch (InstantiationException e) {
  			throw new IllegalStateException(e);
  		} catch (IllegalAccessException e) {
  			throw new IllegalStateException(e);
  		} catch (InvocationTargetException e) {
  			throw new IllegalStateException(e);
  		}
  	}
  
  	/**
  	 * Returns the output format of this writer.
  	 * @return String representing the MIME-Type.
  	 */
  	public String getMimeType() {
  		return mimeType;
  	}
  
  }
  