
package jp.riken.brain.ni.samuraigraph.figure.java2d;

import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.Area;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;

import jp.riken.brain.ni.samuraigraph.base.SGTuple2f;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementLine;


/**
 * A class of line for Java2D.
 *
 */
public class SGDrawingElementLine2D extends SGDrawingElementLine
	implements SGIDrawingElementJava2D
{



	/**
	 *
	 */
	public SGDrawingElementLine2D()
	{
		super();
	}


	/**
	 *
	 */
	public SGDrawingElementLine2D(
		final SGTuple2f start,
		final SGTuple2f end )
	{
		super( start, end );
	}



	/**
	 *
	 */
	public SGDrawingElementLine2D(
		final float x1, final float y1,
		final float x2, final float y2 )
	{
		super( x1, y1, x2, y2 );
	}



	/**
	 * The minimum line width used in "contains" method.
	 */
	public static final float MINIMUM_LINE_WIDTH = 2.0f;


	/**
	 *
	 */
	public boolean contains( final int x, final int y )
	{
		float lw = this.getLineWidth()*this.getMagnification();
		if( lw<MINIMUM_LINE_WIDTH )
		{
			lw = MINIMUM_LINE_WIDTH;
		}
		SGTuple2f start = this.getStart();
		SGTuple2f end = this.getEnd();
		final double lensq = Line2D.ptSegDistSq(
			start.x, start.y, end.x, end.y, x, y );
		return ( lensq < lw*lw );
	}
	
	
	/**
	 * 
	 */
	public void paintElement( final Graphics2D g2d )
	{
		if( this.isVisible() == false )
		{
			return;
		}

		g2d.setPaint(this.getColor(0));

		final float width = this.getMagnification()*this.getLineWidth();

		// set stroke
		Stroke stroke = SGUtilityJava2D.getBasicStroke(
			this.getLineType(), width, this.getStrokeCap(),
			this.getStrokeJoin(), this.getStrokeMiterLimit(),
			this.getStrokeDashPhase() );
		g2d.setStroke( stroke );
		
		g2d.draw( this.getLineShape() );

	}


	/**
	 * 
	 * @param g2d
	 * @param clipRect
	 */
	public void paint( Graphics2D g2d, Rectangle2D clipRect )
	{
		if( clipRect==null )
		{
			this.paintElement(g2d);
		}
		else
		{
			if( this.isVisible() == false )
			{
				return;
			}

			Area clipArea = new Area( clipRect );

			Shape shape = this.getLineShape();
			if( shape==null )
			{
				return;
			}

			Shape edge = this.getStroke().createStrokedShape( shape );
			Area sh = new Area( edge );
			sh.intersect( clipArea );
			g2d.setPaint( this.getColor(0) );
			g2d.fill(sh);
		}

	}



	/**
	 * 
	 */
	public Rectangle2D getElementBounds()
	{
		Shape sh = this.getStroke().createStrokedShape( this.getLineShape() );
		return sh.getBounds2D();
	}


	private Stroke getStroke()
	{
		final float width = this.getMagnification()*this.getLineWidth();
		Stroke stroke = SGUtilityJava2D.getBasicStroke(
			this.getLineType(), width, this.getStrokeCap(),
			this.getStrokeJoin(), this.getStrokeMiterLimit(), 
			this.getStrokeDashPhase() );
		return stroke;
	}


	/**
	 * 
	 */
	public Shape getLineShape()
	{
		Line2D line = new Line2D.Float(
			this.getStart().x, this.getStart().y,
			this.getEnd().x, this.getEnd().y );
		return line;
	}


	/**
	 * 
	 * @param line
	 * @return
	 */
	public static Line2D getLine( final SGDrawingElementLine line )
	{
		SGTuple2f start = line.getStart();
		SGTuple2f end = line.getEnd();
		Line2D sh = new Line2D.Float( start.x, start.y, end.x, end.y );
		return sh;
	}


	/**
	 * 
	 * @return
	 */
	public float getAngle()
	{
		SGTuple2f start = this.getStart();
		SGTuple2f end = this.getEnd();
		return SGUtilityJava2D.getAngle(
			start.x, start.y, end.x, end.y );
	}


}

