/*
 *  Draco Econometrics
 *  Copyright (C) 2006-2007 Approximatrix, LLC
 *  http://www.approximatrix.com
 *  
 *  This program is 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, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 com.approximatrix.draco.application.icons;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.Dimension;
import java.awt.Component;
import javax.swing.Icon;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;

import com.kitfox.svg.SVGDiagram;
import com.kitfox.svg.SVGException;
import com.kitfox.svg.SVGUniverse;
import com.kitfox.svg.SVGCache;

public class VectorIcon implements Icon {

	private SVGUniverse svgUniverse = SVGCache.getSVGUniverse();
	private URI svgURI = null;
	
	private boolean center_x = true;
	private boolean center_y = false;
	
	private int width = 16;
	private int height = 16;
	
	private boolean fixedSize = false;
	
	/** Stores the properly sized icon image */
	private BufferedImage icon_image = null;
		
	public VectorIcon(String resource) {
		// Set the uri for this icon
		try {
			this.svgURI = new URI(getClass().getResource(resource).toString());
			this.generateIcon();
		} catch(URISyntaxException usex) {
			System.err.println("Bad URI when loading icons...");
			usex.printStackTrace();
		} catch(NullPointerException npe) {
			System.err.println("Error initializing icon: "+resource);
			npe.printStackTrace();
		}
	}

	public int getIconHeight() {
		return this.width;
	}
	
	public int getIconWidth() {
		return this.height;
	}
	
	/** Sets the icon's size 
	 *
	 * @param d the new size for the icon
	 */
	public void setDimension(Dimension d) {
		if(this.width != (int)d.getWidth() && this.height != (int)d.getHeight()) {
			this.width = (int)d.getWidth();
			this.height = (int)d.getHeight();
			this.generateIcon();
		}
	}
	
	/** Returns the icon size as a Dimension argument
	 *
	 * @return a Dimension containing the icon's size
	 */
	public Dimension getDimension() {
		return new Dimension(this.width,this.height);
	}
	
	/** The implementation of paintIcon for this class.  Actually
	 * paints only the buffered image for speed purposes.
	 *
	 * @param c the Component on which to draw the icon
	 * @param g the Graphics object to draw on
	 * @param x the x position to start drawing
	 * @param y the y position to start drawing
	 */
	public void paintIcon(Component c, Graphics g, int x, int y) {
		Graphics2D g2 = (Graphics2D)g;
		AffineTransform at = new AffineTransform();
		at.translate((double)x,(double)y);
		g2.drawRenderedImage(this.icon_image,at);
	}
	
	private InputStream getFileInputStream(String filename) {
		FileInputStream svg_file = null;
		try {
			svg_file = new FileInputStream(new File(filename));
		} catch(FileNotFoundException fnfe) {
			System.err.println("File not found: "+filename);
			fnfe.printStackTrace();
			return null;
		}
		return svg_file;
	}
	
	/** Performs the SVG related painting onto the specified graphics object
	 * 
	 * @param gg the graphics on which to paint
	 */
	public void paintSVG(Graphics2D g) {
		
		SVGDiagram diagram = svgUniverse.getDiagram(svgURI);
		if (diagram == null) return;
		diagram.setIgnoringClipHeuristic(true);
				
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        final int width = this.width;
        final int height = this.height;
        
        final Rectangle2D.Double rect = new Rectangle2D.Double();
        diagram.getViewRect(rect);

        // Transform
		AffineTransform scaleXform = new AffineTransform();
		double scale_x = width / rect.width;
		double scale_y = height / rect.height;
		double scale = Math.min(scale_x, scale_y);
		scaleXform.setToScale(scale, scale);
		
		double trans_x=0; double trans_y = 0;
		
		// Center in x
		if(!(scale_x == scale) && center_x) {
			trans_x = ((width/scale)-rect.width)/2.0;
		}
		
		// Center in y
		if(!(scale_y == scale) && center_y) {
			trans_y = ((height/scale)-rect.height)/2.0;
		}
		scaleXform.translate(trans_x, trans_y);

        AffineTransform oldXform = g.getTransform();
        g.transform(scaleXform);

        try
        {
            diagram.render(g);
        }
        catch (SVGException e)
        {
            throw new RuntimeException(e);
        }

        g.setTransform(oldXform);
        
	}

	/** Generates a properly-sized icon and stores it into the buffered image
	 * for painting later.
	 */
	private void generateIcon() {
		// Generate the image
		this.icon_image = new BufferedImage(this.getIconWidth(),this.getIconHeight(),BufferedImage.TYPE_INT_ARGB);
		
		// Paint to the image
		this.paintSVG(this.icon_image.createGraphics());
	}

	public boolean isFixedSize() {
		return fixedSize;
	}

	public void setFixedSize(boolean fixedSize) {
		this.fixedSize = fixedSize;
	}

}
