import edu.neu.ccs.*;
import edu.neu.ccs.codec.*;
import java.awt.*;
import java.awt.geom.*;
import java.text.ParseException;

public class ArrowImage implements Stringable{

	// Constant -- default color
	private static final Color DEFAULT_COLOR = Color.black;

	// Constant: font
	private static final int FONT_SIZE = 12;
	private Font font = new Font("SansSerif", Font.BOLD, FONT_SIZE);
	
	private Point sourceCenter = null;
	private Point targetCenter = null;
	private int   radius = 0;

	public ArrowImage(String data) throws ParseException {
		fromStringData(data);
	}	
	
	public ArrowImage() {
		this(new Point(0,0), new Point(0,0), 0);
	}
	
	public ArrowImage(Point s, Point t, int r) {
	
		sourceCenter = s;
		targetCenter = t;
		radius = r;
	}
	
	public void fromStringData(String data) 
						throws ParseException{
	
		String[] terms = CodecUtilities.decode(data);
		
		sourceCenter = new Point((XInt.parseInt(terms[0])), 
				 				(XInt.parseInt(terms[1])));	
				 				
		targetCenter = new Point((XInt.parseInt(terms[2])),
								 (XInt.parseInt(terms[3])));
								 
		radius = XInt.parseInt(terms[4]);
	}
	
	public String toStringData() {
	 	return CodecUtilities.encode(
            new String[] {sourceCenter.getX() + "",
            			  sourceCenter.getY() + "",
            			  targetCenter.getX() + "",
            			  targetCenter.getY() + "",
            			  radius + "" });
	}


	// returns the proper position for a transition label
	public Point locate(int index) {
		
		int offset = getLabelOffset() * (index + 1);
		Point boundPoint = getLabelBounds();
		
		return new Point((int) boundPoint.getX(), 
						(int) boundPoint.getY() + offset);	
	}
	
	
	public void draw(Graphics2D g, Color c) {
		
		Shape shape = getArrowShape();
		
		g.setPaint(DEFAULT_COLOR);
		g.setFont(font);
		
		if (c != null) 
			g.setPaint(c);
			
		// draw arrow
		g.draw(shape);

	}
	
	public Shape getArrowShape() {
		
		// if the origin and destination are the same, 
		// the arrow shape should be a loop
		if (sourceCenter.getX() == targetCenter.getX()) {
		
			return new Ellipse2D.Double(sourceCenter.getX(), 
										sourceCenter.getY(),
										radius*.75, 
										radius*.75);
		}
			
		// otherwise create a line from the center
		// of the origin to the center of the destination
		return new Line2D.Double(sourceCenter, targetCenter);	
	}
	
	public Point getLabelBounds() {
	
		
		Rectangle2D boundingBox = getArrowShape().getBounds2D();
		
		if (getArrowShape() instanceof Ellipse2D.Double) 
		
			return new Point((int) boundingBox.getMaxX()+2, 
						 	 (int) boundingBox.getCenterY());	
		else
			return new Point((int) boundingBox.getCenterX(),
							 (int) boundingBox.getCenterY());
	}
	
	
	public int getLabelOffset() {
		
		if(sourceCenter.getX() > targetCenter.getX())
			return FONT_SIZE;
		
		if(sourceCenter.getX() < targetCenter.getX())
			return (-1 * FONT_SIZE);
		
		if(sourceCenter.getY() > targetCenter.getY())
			return FONT_SIZE;
			
		if(sourceCenter.getY() < targetCenter.getY())
			return (-1 * FONT_SIZE);
			
		return FONT_SIZE; 
	}	
}
