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

import java.awt.BasicStroke;
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.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;

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.mLineWidth*this.mMagnification;
		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 boolean paintElement( final Graphics2D g2d )
	{
		if( g2d==null )
		{
			return false;
		}

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

		final float width = this.mMagnification*this.mLineWidth;

		// set stroke
		Stroke stroke = SGUtilityJava2D.getBasicStroke(
			this.mLineType, width, this.mCap,
			this.mJoin, this.mMiterLimit, this.mDashPhase );
		g2d.setStroke( stroke );
		
		g2d.draw( this.getShape() );

		return true;
	}


	/**
	 * 
	 * @param g2d
	 * @param clipRect
	 */
	void paint( Graphics2D g2d, Rectangle2D clipRect )
	{
		Shape shape = this.getShape();
		if( shape==null )
		{
			return;
		}

		Stroke stroke = new BasicStroke(
			this.mMagnification*this.mLineWidth,
			BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER );

		if( clipRect==null )
		{
			g2d.setPaint( this.getColor(0) );
			g2d.setStroke( stroke );
			g2d.draw(shape);
		}
		else
		{
			Area clipArea = new Area( clipRect );
			Shape edge = stroke.createStrokedShape( shape );
			Area sh = new Area( edge );
			sh.intersect( clipArea );
			g2d.setPaint( this.getColor(0) );
			g2d.fill(sh);
		}

	}



	/**
	 * 
	 */
	public Rectangle2D getElementBounds()
	{
		SGTuple2f start = this.getStart();
		SGTuple2f end = this.getEnd();
		Rectangle2D rect = new Rectangle2D.Float( start.x, start.y, 0.0f, 0.0f );
		rect.add( new Point2D.Float( end.x, end.y ) );
		return rect;
	}



	/**
	 * 
	 */
	public Shape getShape()
	{
		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;
	}



	/**
	 * 
	 */
	public ArrayList getShapeList()
	{
		ArrayList list = new ArrayList();
		list.add( this.getShape() );
		return list;
	}



	/**
	 * 
	 */
	public Object copy()
	{
		SGDrawingElementLine2D el = new SGDrawingElementLine2D();
		return el;
	}



	/**
	 * 
	 * @param el
	 * @return
	 */
	protected boolean setForCopy( SGDrawingElementLine2D el )
	{
		el.setProperties( this.getProperties() );
		SGTuple2f start = this.getStart();
		SGTuple2f end = this.getEnd();
		el.setTermPoints( start.x, start.y, end.x, end.y );
		el.setMagnification( this.mMagnification );
		return true;
	}



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


}

