/*
 * StateImage.java  
 *
 * Copyright 2001
 * College of Computer Science
 * Northeastern University
 * Boston, MA  02115
 *
 * This software may be used for educational purposes as long as
 * this copyright notice is retained intact at the top of all files.
 *
 * Should this software be modified, the words "Modified from 
 * Original" must be included as a comment below this notice.
 *
 * All publication rights are retained.  This software or its 
 * documentation may not be published in any media either in whole
 * or in part without explicit permission.
 *
 * Contact information:
 *   Richard Rasala    rasala@ccs.neu.edu
 *   Viera Proulx      vkp@ccs.neu.edu
 *   Jeff Raab         jmr@ccs.neu.edu
 *   Jennifer McDonald jenimac@ccs.neu.edu
 * 
 * Telephone:          617-373-2462
 *
 * This software was created with support from Northeastern 
 * University and from NSF grant DUE-9950829.
 */

import edu.neu.ccs.*;
import edu.neu.ccs.codec.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.BasicStroke;
import java.awt.font.*;
import java.text.ParseException;	


public class StateImage implements Stringable {

	// Constant: default color
	protected static final Color DEFAULT_COLOR = Color.black;
	
	// Constant: default font 
	private static final int FONT_SIZE = 16;
	private Font font = new Font("SansSerif", Font.BOLD, FONT_SIZE);

	// Constant: animation highligt width
	private static final int HIGHLIGHT_WIDTH = 5;

	// Center of the state in the buffered panel
	private Point center = new Point();

	// Size of the state
	private int radius = 0;
	
	// Default color of the state
	private Color color = null;
	
	// constructors
	public StateImage(String data) throws ParseException {
		fromStringData(data);
	}	
	
	public StateImage(Point p, int r, Color c) {
		center = p;
		radius = r;
		color = c;
	}	
	
	public void fromStringData(String data) throws ParseException{
	
		String[] terms = CodecUtilities.decode(data);
		
		center = new Point((XInt.parseInt(terms[0])), 
				 (XInt.parseInt(terms[1])));	
		radius = XInt.parseInt(terms[2]);

		color = XColor.parseColor(terms[3]);
	}
	
	public String toStringData() {
	 	return CodecUtilities.encode(
            new String[] {center.getX() + "",
            			  center.getY() + "",
            			  radius + "", 
            			  (new XColor(color)).toStringData()});
	}
	
	// Method to build the ellipse to represent the state	
	public Ellipse2D.Double buildEllipse() {
		
		double xCorner = (double) center.getX() - 
						 (double) radius/2;
						 
		double yCorner = (double) center.getY() - 
						 (double) radius/2;
		
		Ellipse2D.Double e = new Ellipse2D.Double(xCorner,
												  yCorner,
												  radius,
												  radius);
		return e;
	}
	
	
	// Method to paint the state in the buffered panel
	public void draw(Graphics2D g, Color c, 
					 String name, boolean isFinal, 
					 boolean isStart) {
					 
		g.setFont(font);
	
		Ellipse2D.Double e = buildEllipse();
		
		if (isStart) 
			paintStart(g, e.getBounds2D());
		
		// if the caller specifies a color,
		// draw a highlighted oval around the state
       	if (c != null) {
			g.draw(activeShape(g, c, e));
			
			// reset stroke back to normal now that
			// stroked shape is created
			g.setStroke(new BasicStroke());
		}
		

		// reset color and fill as usual
		g.setPaint(color);
        g.fill(e);
       
       	// set paint color to the default color
        // to outline the state and add the label
        g.setPaint(DEFAULT_COLOR);

        g.draw(e);
	
		// add the label
		Point p = centerAnnotation(g, name);
		
		g.drawString(name, (int) p.getX(), (int) p.getY());
		
		// add a second oval if final state
		if(isFinal) {
			g.drawOval((int) e.getX() + 4,
					   (int) e.getY() + 4,
					   (int) e.getHeight() - 8,
					   (int) e.getWidth()  - 8);
		}
	}
	
	
	// draws line with "Start" label pointing to the start state
	public void paintStart(Graphics2D g, Rectangle2D bounds) {
	
		g.setPaint(DEFAULT_COLOR);
	
		g.drawLine((int) bounds.getMinX() - 50 ,(int) bounds.getCenterY(),
				   (int) bounds.getMinX(), (int) bounds.getCenterY());
			
			g.drawString("Start", (int) bounds.getMinX() - 45, 
						 (int) bounds.getCenterY());		
			
	}
		
	public Point getCenter() {
		return center;
	}

	public int getRadius() {
		return radius;
	}

	public Color getColor() {
		return color;
	}
	
	// Creates a stroked version of the state's ellipse
	// in the color specified in order to highlight an 
	// active state during animation
	public Shape activeShape(Graphics2D g, Color c, Ellipse2D.Double e) {
	
		g.setPaint(c);
       	g.setStroke(new BasicStroke(HIGHLIGHT_WIDTH, 
       								BasicStroke.CAP_ROUND, 
       								BasicStroke.JOIN_ROUND));
       								
       	Stroke stroke = g.getStroke();
		return stroke.createStrokedShape(e);
	}
	
	public Point centerAnnotation(Graphics2D g, String name) {
	
		FontRenderContext frc =
            g.getFontRenderContext();
            
        Rectangle2D bounds =
            g.getFont().getStringBounds(name, frc);
	
		int x = ((int) center.getX()) - ((int) bounds.getWidth() / 2);
        int y = ((int) center.getY()) + ((int) bounds.getHeight() / 4);
     
        return new Point(x,y);	
	}

}
