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

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Shape;

import jp.riken.brain.ni.samuraigraph.base.SGDrawingElement;
import jp.riken.brain.ni.samuraigraph.base.SGIConstants;
import jp.riken.brain.ni.samuraigraph.base.SGProperties;
import jp.riken.brain.ni.samuraigraph.base.SGTuple2f;
import jp.riken.brain.ni.samuraigraph.base.SGUtilityNumber;
import jp.riken.brain.ni.samuraigraph.base.SGUtilityText;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementArrow;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementSymbol;
import jp.riken.brain.ni.samuraigraph.figure.SGIArrowConstants;

import org.w3c.dom.Element;


/**
 * 
 */
public abstract class SGElementGroupArrow extends SGElementGroupVXY
	implements SGIArrowConstants, SGIElementGroupConstants
{

	/**
	 *
	 */
	protected int mLineType;


	/**
	 * 倍率100%のときの線幅
	 */
	protected float mLineWidth;


	/**
	 * 全体の中での矢尻の長さ
	 */
	protected float mHeadSize;


	/**
	 * 矢尻の開き角度
	 */
	protected float mHeadOpenAngle;


	/**
	 * 矢尻の閉じ角度
	 */
	protected float mHeadCloseAngle;


	/**
	 * 
	 */
	protected float mHeadEdgeLineWidth;


	/**
	 * 
	 */
	protected Color mHeadEdgeLineColor;


	/**
	 * 
	 */
	protected int mStartHeadType;


	/**
	 * 
	 */
	protected int mEndHeadType;


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



	/**
	 * 
	 */
	public int getLineType()
	{
		return this.mLineType;
	}
	
	
	/**
	 * 
	 */
	public float getLineWidth()
	{
		return this.mLineWidth;
	}


	/**
	 * 
	 */
	public float getHeadSize()
	{
		return this.mHeadSize;
	}


	/**
	 * 
	 */
	public float getHeadOpenAngle()
	{
		return this.mHeadOpenAngle;
	}


	/**
	 * 
	 */
	public float getHeadCloseAngle()
	{
		return this.mHeadCloseAngle;
	}


	/**
	 * 
	 */
	public float getHeadEdgeLineWidth()
	{
		return this.mHeadEdgeLineWidth;
	}


	/**
	 * 
	 */
	public Color getHeadEdgeLineColor()
	{
		return this.mHeadEdgeLineColor;
	}


	/**
	 * 
	 */
	public int getStartHeadType()
	{
		return this.mStartHeadType;
	}


	/**
	 * 
	 */
	public int getEndHeadType()
	{
		return this.mEndHeadType;
	}


	/**
	 * 
	 */
	public boolean setLineType( final int type )
	{
		mLineType = type;
		if( this.mDrawingElementArray!=null )
		{
			for( int ii=0; ii<this.mDrawingElementArray.length; ii++ )
			{
				SGDrawingElementArrow2D el = (SGDrawingElementArrow2D)this.mDrawingElementArray[ii];
				el.setLineType(mLineType);
			}
		}
		return true;
	}


	/**
	 * 
	 */
	public boolean setLineWidth( final float width )
	{
		mLineWidth = width;
		if( this.mDrawingElementArray!=null )
		{
			for( int ii=0; ii<mDrawingElementArray.length; ii++ )
			{
				SGDrawingElementArrow2D el = (SGDrawingElementArrow2D)this.mDrawingElementArray[ii];
				el.setLineWidth(mLineWidth);
			}
		}
		return true;
	}


	/**
	 * 
	 */
	public boolean setHeadSize( final float size )
	{
		mHeadSize = size;
		if( this.mDrawingElementArray!=null )
		{
			for( int ii=0; ii<mDrawingElementArray.length; ii++ )
			{
				SGDrawingElementArrow2D el = (SGDrawingElementArrow2D)this.mDrawingElementArray[ii];
				el.setHeadSize(mHeadSize);
			}
		}
		return true;
	}


	/**
	 * 
	 */
	public boolean setHeadOpenAngle( final float angle )
	{
		mHeadOpenAngle = angle;
		if( this.mDrawingElementArray!=null )
		{
			for( int ii=0; ii<mDrawingElementArray.length; ii++ )
			{
				SGDrawingElementArrow2D el = (SGDrawingElementArrow2D)this.mDrawingElementArray[ii];
				el.setHeadOpenAngle(mHeadOpenAngle);
			}
		}
		return true;
	}


	/**
	 * 
	 */
	public boolean setHeadCloseAngle( final float angle )
	{
		mHeadCloseAngle = angle;
		if( this.mDrawingElementArray!=null )
		{
			for( int ii=0; ii<mDrawingElementArray.length; ii++ )
			{
				SGDrawingElementArrow2D el = (SGDrawingElementArrow2D)this.mDrawingElementArray[ii];
				el.setHeadCloseAngle(mHeadCloseAngle);
			}
		}
		return true;
	}



	/**
	 * 
	 */
	public boolean setHeadEdgeLineWidth( final float width )
	{
		mHeadEdgeLineWidth = width;
		if( this.mDrawingElementArray!=null )
		{
			for( int ii=0; ii<mDrawingElementArray.length; ii++ )
			{
				SGDrawingElementArrow2D el = (SGDrawingElementArrow2D)this.mDrawingElementArray[ii];
				el.setHeadEdgeLineWidth(width);
			}
		}
		return true;
	}



	/**
	 * 
	 */
	public boolean setHeadEdgeLineColor( final Color color )
	{
		mHeadEdgeLineColor = color;
		if( this.mDrawingElementArray!=null )
		{
			for( int ii=0; ii<mDrawingElementArray.length; ii++ )
			{
				SGDrawingElementArrow2D el = (SGDrawingElementArrow2D)this.mDrawingElementArray[ii];
				el.setHeadEdgeLineColor(color);
			}
		}
		return true;
	}


	/**
	 * 
	 */
	public boolean setStartHeadType( final int type )
	{
		mStartHeadType = type;
		if( this.mDrawingElementArray!=null )
		{
			for( int ii=0; ii<mDrawingElementArray.length; ii++ )
			{
				SGDrawingElementArrow2D el = (SGDrawingElementArrow2D)this.mDrawingElementArray[ii];
				el.setStartHeadType(type);
			}
		}
		return true;
	}


	/**
	 * 
	 */
	public boolean setEndHeadType( final int type )
	{
		mEndHeadType = type;
		if( this.mDrawingElementArray!=null )
		{
			for( int ii=0; ii<mDrawingElementArray.length; ii++ )
			{
				SGDrawingElementArrow2D el = (SGDrawingElementArrow2D)this.mDrawingElementArray[ii];
				el.setEndHeadType(type);
			}
		}
		return true;
	}


	/**
	 * 
	 */
	public SGDrawingElement getDrawingElement()
	{
		SGDrawingElementArrow arrow = new SGDrawingElementArrow2D();
		arrow.setVisible( this.mVisibleFlag );
		arrow.setLineType( mLineType );
		arrow.setLineWidth( mLineWidth );
		arrow.setColorList( mColorList );
		arrow.setHeadSize( mHeadSize );
		arrow.setHeadOpenAngle( mHeadOpenAngle );
		arrow.setHeadCloseAngle( mHeadCloseAngle );
		arrow.setHeadEdgeLineWidth( mHeadEdgeLineWidth );
		arrow.setHeadEdgeLineColor( mHeadEdgeLineColor );
		arrow.setStartHeadType( mStartHeadType );
		arrow.setEndHeadType( mEndHeadType );

		return arrow;
	}


	/**
	 * 
	 */
	public boolean setProperty( final SGDrawingElement element )
	{
		if( !(element instanceof SGDrawingElementArrow) )
		{
			return false;
		}

		if( super.setProperty( element ) == false )
		{
			return false;
		}

		SGDrawingElementArrow arrow = (SGDrawingElementArrow)element;

		this.mLineType = arrow.getLineType();
		this.mLineWidth = arrow.getLineWidth();
		this.mHeadSize = arrow.getHeadSize();
		this.mHeadOpenAngle = arrow.getHeadOpenAngle();
		this.mHeadCloseAngle = arrow.getHeadCloseAngle();
		this.mHeadEdgeLineWidth = arrow.getHeadEdgeLineWidth();
		this.mHeadEdgeLineColor = arrow.getHeadEdgeLineColor();
		this.mStartHeadType = arrow.getStartHeadType();
		this.mEndHeadType = arrow.getEndHeadType();

		return true;
	}


  /**
   * 
   */
	public boolean paintElement( final Graphics2D g2d )
	{

		if( this.mDrawingElementArray==null )
		{
			return true;
		}


		// body
		final float width = mMagnification*this.mLineWidth;
		switch( this.mLineType )
		{
			case SGDrawingElementLine2D.LINE_TYPE_SOLID :
			{
				g2d.setStroke
				(
					new BasicStroke
					(
						width,
						BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER
					)
				);
				break;
			}

			case SGDrawingElementLine2D.LINE_TYPE_BROKEN :
			{
				final float dash[] = {2.0f*width,width};
				g2d.setStroke
				(
					new BasicStroke
					(
						width,
						BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
						10.0f, dash, 0.0f
					)
				);
				break;
			}

			case SGDrawingElementLine2D.LINE_TYPE_DOT :
			{
				final float dash[] = {width};
				g2d.setStroke
				(
					new BasicStroke
					(
						width,
						BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
						10.0f, dash, 0.0f
					)
				);
				break;
			}
					
			default :
			{
				throw new Error();					
			}

		}


		// body
		g2d.setPaint(this.getColor(0));
		for( int jj=0; jj<this.mDrawingElementArray.length; jj++ )
		{
			SGDrawingElementArrow2D el = (SGDrawingElementArrow2D)mDrawingElementArray[jj];
			Shape shape = el.getBodyShape();
			g2d.draw(shape);
		}



		// head
		final float headLineWidth = mMagnification*this.mHeadEdgeLineWidth;
		g2d.setStroke( new BasicStroke( headLineWidth ) );
		for( int jj=0; jj<this.mDrawingElementArray.length; jj++ )
		{
			SGDrawingElementArrow2D el = (SGDrawingElementArrow2D)mDrawingElementArray[jj];

			Shape startShape = el.getStartHeadShape();
			if( startShape != null )
			{
				g2d.setPaint( this.mHeadEdgeLineColor );
				g2d.draw(startShape);

				g2d.setPaint(this.getColor(0));
				g2d.fill(startShape);
			}

			Shape endShape = el.getEndHeadShape();
			if( endShape != null )
			{
				g2d.setPaint( this.mHeadEdgeLineColor );
				g2d.draw(endShape);

				g2d.setPaint(this.getColor(0));
				g2d.fill(endShape);
			}
		}


//System.out.println();

		return true;
	}



	/**
	 * 
	 */
	public static String getSymbolTypeName( final int type )
	{
//System.out.println("type="+type);

		String typeName = null;
		switch( type )
		{
			case SGDrawingElementSymbol.SYMBOL_TYPE_CIRCLE :
			{
				typeName = SYMBOL_NAME_CIRCLE;
				break;
			}

			case SGDrawingElementSymbol.SYMBOL_TYPE_SQUARE :
			{
				typeName = SYMBOL_NAME_SQUARE;
				break;
			}

			case SGDrawingElementSymbol.SYMBOL_TYPE_TRIANGLE :
			{
				typeName = SYMBOL_NAME_TRIANGLE;
				break;
			}

			case SGDrawingElementSymbol.SYMBOL_TYPE_CROSS :
			{
				typeName = SYMBOL_NAME_CROSS;
				break;
			}

			case SGDrawingElementSymbol.SYMBOL_TYPE_TRANSVERSELINE :
			{
				typeName = SYMBOL_NAME_TRANSVERSE_LINE;
				break;
			}

			case SGDrawingElementArrow.SYMBOL_ARROW_HEAD :
			{
				typeName = SYMBOL_NAME_ARROW_HEAD;
				break;
			}

			case SGDrawingElementSymbol.SYMBOL_TYPE_VOID :
			{
				typeName = NO_SYMBOL;
				break;
			}

			default :
			{
				
			}
		}

		return typeName;
	}






	/**
	 * 
	 * @return
	 */
	public String getTagName()
	{
		return TAG_NAME_ARROW;
	}


	/**
	 * 
	 */
	public boolean writeProperty( final Element el )
	{
		String cm = SGUtilityNumber.cm;
		String pt = SGUtilityNumber.pt;
		String degree = SGUtilityNumber.degree;

		el.setAttribute( KEY_VISIBLE, Boolean.toString( this.mVisibleFlag ) );
		el.setAttribute( KEY_LINE_WIDTH, Float.toString( this.mLineWidth ) + pt );
		el.setAttribute( KEY_LINE_TYPE, Integer.toString( this.mLineType ) );
		el.setAttribute( KEY_HEAD_SIZE, Float.toString( this.mHeadSize*SGIConstants.CM_POINT_RATIO ) + cm );
		el.setAttribute( KEY_START_HEAD_TYPE, Integer.toString( this.mStartHeadType ) );
		el.setAttribute( KEY_END_HEAD_TYPE, Integer.toString( this.mEndHeadType ) );
		el.setAttribute( KEY_HEAD_LINE_WIDTH, Float.toString( this.mHeadEdgeLineWidth ) + pt );
		el.setAttribute( KEY_HEAD_LINE_COLOR, SGUtilityText.getColorString( this.mHeadEdgeLineColor ) );
		el.setAttribute( KEY_HEAD_OPEN_ANGLE, Double.toString( this.mHeadOpenAngle ) + degree );
		el.setAttribute( KEY_HEAD_CLOSE_ANGLE, Double.toString( this.mHeadCloseAngle ) + degree );
		el.setAttribute( KEY_COLOR_LIST, SGUtilityText.getColorListString( this.mColorList ) );
		return true;
	}


	
	/**
	 * 
	 * @param el
	 * @return
	 */
	public SGProperties readProperties( final Element el )
	{
		return null;
	}

	

	/**
	 * 
	 * @return
	 */
	protected boolean initDrawingElement( final int num )
	{
		SGDrawingElementArrow[] array = new SGDrawingElementArrow2D[num];
		for( int ii=0; ii<num; ii++ )
		{
			array[ii] = new SGDrawingElementArrow2D();
		}
		this.mDrawingElementArray = array;
		return true;
	}



	/**
	 * 
	 */
	public boolean setLocation(
		final SGTuple2f[] startArray,
		final SGTuple2f[] endArray )
	{

		if( startArray==null || endArray==null )
		{
			throw new IllegalArgumentException("startArray==null || endArray==null");
		}

		if( startArray.length != endArray.length )
		{
			throw new IllegalArgumentException("startArray.length != endArray.length");
		}

		if( startArray.length != this.mDrawingElementArray.length )
		{
			throw new IllegalArgumentException("startArray.length != this.mDrawingElementArray.length");
		}


		for( int ii=0; ii<this.mDrawingElementArray.length; ii++ )
		{
			SGDrawingElementArrow2D arrow
				= (SGDrawingElementArrow2D)this.mDrawingElementArray[ii];
			final boolean eff = !(
				startArray[ii].isInfinite() || startArray[ii].isNaN() ||
				endArray[ii].isInfinite() || endArray[ii].isNaN() );
			arrow.setVisible( eff );
			if( eff )
			{
				arrow.setTermPoints( startArray[ii], endArray[ii] );
			}
		}

		return true;
	}



	/**
	 * 
	 * @return
	 */
	public boolean setPropertiesOfDrawingElements()
	{
		for( int ii=0; ii<this.mDrawingElementArray.length; ii++ )
		{
			SGDrawingElementArrow2D arrow
				= (SGDrawingElementArrow2D)this.mDrawingElementArray[ii];

			arrow.setMagnification(mMagnification);
			arrow.setColorList( this.mColorList );

			arrow.setLineWidth( this.mLineWidth );
			arrow.setLineType( this.mLineType );

			arrow.setHeadSize( this.mHeadSize );
			arrow.setStartHeadType( this.mStartHeadType );
			arrow.setEndHeadType( this.mEndHeadType );
			arrow.setHeadOpenAngle( this.mHeadOpenAngle );
			arrow.setHeadCloseAngle( this.mHeadCloseAngle );
		}
		return true;
	}


	/**
	 * 
	 */
	public SGProperties getProperties()
	{
		ArrowProperties p = new ArrowProperties();
		this.getProperties(p);

		return p;
	}


	/**
	 * 
	 */
	public boolean getProperties( SGProperties p )
	{
		if( p==null ) return false;
		if( ( p instanceof ArrowProperties ) == false ) return false;

		super.getProperties(p);

		ArrowProperties ap = (ArrowProperties)p;
		ap.setLineWidth( this.getLineWidth() );
		ap.setLineType( this.getLineType() );
		ap.setHeadSize( this.getHeadSize() );
		ap.setHeadLineWidth( this.getHeadEdgeLineWidth() );
		ap.setHeadLineColor( this.getHeadEdgeLineColor() );
		ap.setStartHeadType( this.getStartHeadType() );
		ap.setEndHeadType( this.getEndHeadType() );
		ap.setHeadOpenAngle( this.getHeadOpenAngle() );
		ap.setHeadCloseAngle( this.getHeadCloseAngle() );

		return true;
	}


	/**
	 * 
	 */
	public boolean setProperties( SGProperties p )
	{
		if( ( p instanceof ArrowProperties ) == false ) return false;

		if( super.setProperties(p) == false ) return false;

		ArrowProperties ap = (ArrowProperties)p;

		final Float lineWidth = ap.getLineWidth();
		if( lineWidth==null )
		{
			return false;
		}
		this.setLineWidth( lineWidth.floatValue() );

		final Integer lineType = ap.getLineType();
		if( lineType==null )
		{
			return false;
		}
		this.setLineType( lineType.intValue() );

		final Float headSize = ap.getHeadSize();
		if( headSize==null )
		{
			return false;
		}
		this.setHeadSize( headSize.floatValue() );

		final Float headLineWidth = ap.getHeadLineWidth();
		if( headLineWidth==null )
		{
			return false;
		}
		this.setHeadEdgeLineWidth( headLineWidth.floatValue() );

		Color headLineColor = ap.getHeadLineColor();
		if( headLineColor==null )
		{
			return false;
		}
		this.setHeadEdgeLineColor( headLineColor );

		final Integer startHeadType = ap.getStartHeadType();
		if( startHeadType==null )
		{
			return false;
		}
		this.setStartHeadType( startHeadType.intValue() );

		final Integer endHeadType = ap.getEndHeadType();
		if( endHeadType==null )
		{
			return false;
		}
		this.setEndHeadType( endHeadType.intValue() );

		final Float headOpenAngle = ap.getHeadOpenAngle();
		if( headOpenAngle==null )
		{
			return false;
		}
		this.setHeadOpenAngle( headOpenAngle.floatValue() );

		final Float headCloseAngle = ap.getHeadCloseAngle();
		if( headCloseAngle==null )
		{
			return false;
		}
		this.setHeadCloseAngle( headCloseAngle.floatValue() );

		return true;
	}





	/**
	 * 
	 */
	public static class ArrowProperties extends ElementGroupProperties
	{

/*		float lineWidth;
		int lineType;
		float headSize;
		int startHeadType;
		int endHeadType;
		float headLineWidth;
		Color headLineColor;
		double headOpenAngle;
		double headCloseAngle;
*/

		public static final String[] keys = {
			KEY_LINE_WIDTH,
			KEY_LINE_TYPE,
			KEY_HEAD_SIZE,
			KEY_START_HEAD_TYPE,
			KEY_END_HEAD_TYPE,
			KEY_HEAD_LINE_WIDTH,
			KEY_HEAD_LINE_COLOR,
			KEY_HEAD_OPEN_ANGLE,
			KEY_HEAD_CLOSE_ANGLE
		};



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



		/**
		 * 
		 */
		public boolean equals( final Object obj )
		{

			if( ( obj instanceof ArrowProperties ) == false )
			{
				return false;
			}

			if( super.equals(obj) == false ) return false;

//System.out.println(obj);

			ArrowProperties p = (ArrowProperties)obj;
			for( int ii=0; ii<keys.length; ii++ )
			{
				if( this.getProperty(keys[ii]).equals(p.getProperty(keys[ii])) == false )
				{
					return false;
				}
			}

			return true;
		}



		public Float getLineWidth()
		{
			final String value = this.getProperty(KEY_LINE_WIDTH);
			return SGUtilityText.getFloat(value);
		}

		public Integer getLineType()
		{
			final String value = this.getProperty(KEY_LINE_TYPE);
			return SGUtilityText.getInteger(value);
		}

		public Float getHeadLineWidth()
		{
			final String value = this.getProperty(KEY_HEAD_LINE_WIDTH);
			return SGUtilityText.getFloat(value);
		}

		public Float getHeadSize()
		{
			final String value = this.getProperty(KEY_HEAD_SIZE);
			return SGUtilityText.getFloat(value);
		}

		public Color getHeadLineColor()
		{
			final String value = this.getProperty(KEY_HEAD_LINE_COLOR);
			return SGUtilityText.getColorFromString(value);
		}

		public Integer getStartHeadType()
		{
			final String value = this.getProperty(KEY_START_HEAD_TYPE);
			return SGUtilityText.getInteger(value);
		}

		public Integer getEndHeadType()
		{
			final String value = this.getProperty(KEY_END_HEAD_TYPE);
			return SGUtilityText.getInteger(value);
		}

		public Float getHeadOpenAngle()
		{
			final String value = this.getProperty(KEY_HEAD_OPEN_ANGLE);
			return SGUtilityText.getFloat(value);
		}

		public Float getHeadCloseAngle()
		{
			final String value = this.getProperty(KEY_HEAD_CLOSE_ANGLE);
			return SGUtilityText.getFloat(value);
		}


		public boolean setLineWidth( final float width )
		{
			if( width<0.0f )
			{
				return false;
			}
			this.setProperty( KEY_LINE_WIDTH, new Float(width).toString() );
			return true;
		}

		public boolean setLineType( final int num )
		{
			this.setProperty( KEY_LINE_TYPE, new Integer(num).toString() );
			return true;
		}

		public boolean setHeadLineWidth( final float width )
		{
			if( width<0.0f )
			{
				return false;
			}
			this.setProperty( KEY_HEAD_LINE_WIDTH, new Float(width).toString() );
			return true;
		}

		public boolean setStartHeadType( final int num )
		{
			this.setProperty( KEY_START_HEAD_TYPE, new Integer(num).toString() );
			return true;
		}

		public boolean setEndHeadType( final int num )
		{
			this.setProperty( KEY_END_HEAD_TYPE, new Integer(num).toString() );
			return true;
		}

		public boolean setHeadSize( final float size )
		{
			if( size<0.0f )
			{
				return false;
			}
			this.setProperty( KEY_HEAD_SIZE, new Float(size).toString() );
			return true;
		}

		public boolean setHeadLineColor( final Color cl )
		{
			if( cl==null )
			{
				return false;
			}
			String str = SGUtilityText.getColorString(cl);
			if( str==null )
			{
				return false;
			}
			this.setProperty( KEY_HEAD_LINE_COLOR, str );
			return true;
		}

		public boolean setHeadOpenAngle( final float value )
		{
			this.setProperty( KEY_HEAD_OPEN_ANGLE, new Float(value).toString() );
			return true;
		}

		public boolean setHeadCloseAngle( final float value )
		{
			this.setProperty( KEY_HEAD_CLOSE_ANGLE, new Float(value).toString() );
			return true;
		}


		/**
		 * 
		 */
/*		public String toString()
		{
			String str = new String("[");
			str += new String("visible="+visible+", ");
			str += new String("colorList="+colorList+", ");
			str += new String("lineWidh="+lineWidth+", ");
			str += new String("headSize="+headSize+", ");
			str += new String("startHeadType="+startHeadType+", ");
			str += new String("endHeadType="+endHeadType+", ");
			str += new String("headLineWidth="+headLineWidth+", ");
			str += new String("headLineColor="+headLineColor+", ");
			str += new String("headOpenAngle="+headOpenAngle+", ");
			str += new String("headCloseAngle="+headCloseAngle+", ");
			str += new String("]");

			return str;
		}
*/


	}



}
