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


import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Area;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
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.SGUtilityText;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementErrorBar;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementSymbol;
import jp.riken.brain.ni.samuraigraph.figure.SGIArrowConstants;
import jp.riken.brain.ni.samuraigraph.figure.SGIErrorBarConstants;
import jp.riken.brain.ni.samuraigraph.figure.SGILineConstants;
import jp.riken.brain.ni.samuraigraph.figure.SGISymbolConstants;
import org.w3c.dom.Element;



/**
 *
 *
 */
public abstract class SGElementGroupErrorBar extends SGElementGroupVXY
	implements SGILineConstants, SGISymbolConstants, SGIErrorBarConstants, SGIArrowConstants
{

	/**
	 * 
	 */
	protected float mLineWidth;


	/**
	 * 
	 */
	protected int mLineType;


	/**
	 * 
	 */	
	protected float mHeadSize;


	/**
	 * 
	 */
	protected int mHeadType = -1;


	/**
	 * 
	 */
	protected int mErrorBarStyle = ERROR_BAR_BOTHSIDES;


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


	/**
	 * 
	 * @return
	 */
	protected SGDrawingElement createDrawingElementInstance()
	{
		return new SGDrawingElementErrorBar2D();
	}


	/**
	 * 
	 * @return
	 */
	protected boolean initDrawingElement(
		final SGTuple2f[] startArray, final SGTuple2f[] endArray )
	{
		final int num = startArray.length;
		if( this.initDrawingElement(num) == false )
		{
			return false;
		}
		
		SGDrawingElement[] sArray = this.mDrawingElementArray;
		for( int ii=0; ii<num; ii++ )
		{
			((SGDrawingElementErrorBar)sArray[ii]).setTermPoints( startArray[ii], endArray[ii] );
		}
		return true;
	}



	/**
	 * Set the location of points.
	 * 
	 */
	public boolean setLocation(
		SGTuple2f[] startArray, 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");
		}


		SGDrawingElement[] array = this.mDrawingElementArray;
		if( array==null )
		{
			return false;
		}

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

		return true;

	}



	/**
	 * 
	 * @return
	 */
	public float getLineWidth()
	{
		return this.mLineWidth;
	}


	/**
	 * 
	 * @param unit
	 * @return
	 */
	public float getLineWidth( final String unit )
	{
		return (float)SGUtilityText.convertFromPoint( this.getLineWidth(), unit );
	}


	/**
	 * 
	 * @param width
	 */
	public boolean setLineWidth( final float width )
	{
		this.mLineWidth = width;
		SGDrawingElement[] array = this.mDrawingElementArray;
		if( array!=null )
		{
			for( int ii=0; ii<array.length; ii++ )
			{
				if( ((SGDrawingElementErrorBar)array[ii]).setLineWidth( width ) == false )
				{
					return false;
				}
			}
		}

		return true;
	}


	/**
	 * 
	 * @param width
	 * @param unit
	 * @return
	 */
	public boolean setLineWidth( final float width, final String unit )
	{
		final double lw = SGUtilityText.convertToPoint( width, unit );
		if( this.setLineWidth( (float)lw ) == false )
		{
			return false;
		}

		return true;
	}



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


	/**
	 * 
	 * @return
	 */
	public float getHeadSize( final String unit )
	{
		return (float)SGUtilityText.convertFromPoint( this.getHeadSize(), unit );
	}


	/**
	 * 
	 * @param size
	 */
	public boolean setHeadSize( final float size )
	{
		this.mHeadSize = size;
		SGDrawingElement[] array = this.mDrawingElementArray;
		if( array!=null )
		{
			for( int ii=0; ii<array.length; ii++ )
			{
				if( ((SGDrawingElementErrorBar)array[ii]).setHeadSize( size ) == false )
				{
					return false;
				}
			}
		}

		return true;
	}


	/**
	 * 
	 * @param width
	 * @param unit
	 * @return
	 */
	public boolean setHeadSize( final float size, final String unit )
	{
		final double s = SGUtilityText.convertToPoint( size, unit );
		if( this.setHeadSize( (float)s ) == false )
		{
			return false;
		}

		return true;
	}


	/**
	 * 
	 * @return
	 */
	public int getErrorBarStyle()
	{
		return this.mErrorBarStyle;
	}


	/**
	 * 
	 * @param style
	 */
	public boolean setErrorBarStyle( final int style )
	{
		this.mErrorBarStyle = style;
		SGDrawingElement[] array = this.mDrawingElementArray;
		if( array==null )
		{
			return true;
		}

		for( int ii=0; ii<array.length; ii++ )
		{
			if( ((SGDrawingElementErrorBar)array[ii]).setErrorBarStyle( style ) == false )
			{
				return false;
			}
		}
		
		return true;
	}


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


	/**
	 * 
	 */
	public boolean writeProperty( final Element el )
	{
		el.setAttribute( KEY_ERROR_BAR_STYLE, SGDrawingElementErrorBar.getErrorBarStyleName( this.mErrorBarStyle ) );
		el.setAttribute( KEY_LINE_WIDTH, Float.toString( this.mLineWidth ) + SGIConstants.pt );
		el.setAttribute( KEY_HEAD_SIZE, Float.toString( this.mHeadSize*SGIConstants.CM_POINT_RATIO ) + SGIConstants.cm );
		el.setAttribute( KEY_ERROR_BAR_HEAD_TYPE, SGDrawingElementSymbol.getSymbolTypeName( this.getHeadType() ) );
		el.setAttribute( KEY_COLOR_LIST, SGUtilityText.getColorListString( this.mColorList ) );
		return true;
	}


	
	/**
	 * 
	 * @param el
	 * @return
	 */
	public boolean readProperty( final Element el )
	{
		String str = null;
		Number num = null;
		Color cl = null;
		Boolean b = null;
		List list = null;

		// color
		str = el.getAttribute( KEY_COLOR_LIST );
		if( str.length()==0 )
		{
			return false;
		}
		list = SGUtilityText.getColorList(str);
		if( list==null )
		{
			return false;
		}
		if( list.size()<1 )
		{
			return false;
		}
		final Color color = (Color)list.get(0);


		// line width
		str = el.getAttribute( KEY_LINE_WIDTH );
		if( str.length()==0 )
		{
			// to maintain downward compatibility with old versions before 0.6.1
			str = el.getAttribute( "LineWidth" );
			if( str.length()==0 )
			{
				return false;
			}
		}
		StringBuffer uLineWidth = new StringBuffer();
		num = SGUtilityText.getNumber( str, uLineWidth );
		if( num==null )
		{
			return false;
		}
		final float lineWidth = num.floatValue();


		// head size
		str = el.getAttribute( KEY_HEAD_SIZE );
		if( str.length()==0 )
		{
			return false;
		}
		StringBuffer uHeadSize = new StringBuffer();
		num = SGUtilityText.getNumber( str, uHeadSize );
		if( num==null )
		{
			return false;
		}
		final float headSize = num.floatValue();

		
		// style of error bars
		str = el.getAttribute( KEY_ERROR_BAR_STYLE );
		if( str.length()==0 )
		{
			return false;
		}
		num = SGDrawingElementErrorBar.getErrorBarStyleFromName( str );
		if( num==null )
		{
			return false;
		}
		final int style = num.intValue();


		// head type
		str = el.getAttribute( KEY_ERROR_BAR_HEAD_TYPE );
		if( str.length()==0 )
		{
			return false;
		}
		final Integer type = SGDrawingElementErrorBar.getHeadTypeFromName(str);
		if( type==null )
		{
			return false;
		}
		final int headType = type.intValue();


		//
		// set properties
		//

		if( this.setLineWidth( lineWidth, uLineWidth.toString() ) == false )
		{
			return false;
		}
		
		if( this.setColor( color ) == false )
		{
			return false;
		}

		if( this.setErrorBarStyle( style ) == false )
		{
			return false;
		}

		if( this.setHeadType( headType ) == false )
		{
			return false;
		}

		return true;
	}

	

	/**
	 * 
	 */
	public int getHeadType()
	{
		return this.mHeadType;
	}


	/**
	 * 
	 */
	public boolean setHeadType( int type )
	{
		this.mHeadType = type;
		SGDrawingElement[] array = this.mDrawingElementArray;
		if( array!=null )
		{
			for( int ii=0; ii<array.length; ii++ )
			{
				if( ((SGDrawingElementErrorBar)array[ii]).setHeadType(type) == false )
				{
					return false;
				}
			}
		}

		return true;
	}




	/**
	 * 
	 */
	public SGDrawingElement getDrawingElement()
	{
		SGDrawingElementErrorBar bar
			= (SGDrawingElementErrorBar)this.createDrawingElementInstance();
		bar.setVisible( this.isVisible() );
		bar.setLineWidth( this.getLineWidth() );
		bar.setColorList( this.getColorList() );
		bar.setHeadSize( this.getHeadSize() );
		bar.setHeadType( this.getHeadType() );
		bar.setErrorBarStyle( this.getErrorBarStyle() );

		return bar;
	}



	/**
	 * 
	 */
	public boolean paintElement(
		final Graphics2D g2d, final Rectangle2D clipRect )
	{
		Area clipArea = null;
		if( clipRect!=null )
		{
			clipArea = new Area( clipRect );
		}
		SGDrawingElement[] array = this.mDrawingElementArray;
		if( array!=null )
		{
			for( int ii=0; ii<array.length; ii++ )
			{
				SGDrawingElementErrorBar2D el
					= (SGDrawingElementErrorBar2D)array[ii];
				if( el.isVisible() == false )
				{
					continue;
				}

				el.paint( g2d, clipRect );
			}
		}

		return true;
	}


	/**
	 * 
	 */
	public SGProperties getProperties()
	{
		ErrorBarProperties p = new ErrorBarProperties();
		if( this.getProperties(p) == false ) return null;
		return p;
	}



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

		if( ( p instanceof ErrorBarProperties ) == false ) return false;

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

		ErrorBarProperties ep = (ErrorBarProperties)p;

		ep.setLineWidth( this.getLineWidth() );
		ep.setHeadSize( this.getHeadSize() );
		ep.setHeadType( this.getHeadType() );
		ep.setErrorBarStyle( this.getErrorBarStyle() );

		return true;
	}



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

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

		ErrorBarProperties ep = (ErrorBarProperties)p;

		this.setLineWidth( ep.getLineWidth().floatValue() );
		this.setHeadSize( ep.getHeadSize().floatValue() );
		this.setHeadType( ep.getHeadType().intValue() );

		Integer style = ep.getErrorBarStyle();
		if( style==null )
		{
			return false;
		}
		this.setErrorBarStyle( style.intValue() );

		return true;
	}



	/**
	 * 
	 * @return
	 */
	public boolean setPropertiesOfDrawingElements()
	{
		SGDrawingElement[] array = this.mDrawingElementArray;
		final float mag = this.getMagnification();
		final ArrayList cList = this.getColorList();
		final float lineWidth = this.getLineWidth();
		final float headSize = this.getHeadSize();
		final int headType = this.getHeadType();
		final int style = this.getErrorBarStyle();

		for( int ii=0; ii<array.length; ii++ )
		{
			SGDrawingElementErrorBar bar = (SGDrawingElementErrorBar)array[ii];
			bar.setErrorBarStyle( style );
			bar.setMagnification( mag );
			bar.setColorList( cList );
			bar.setLineWidth( lineWidth );
			bar.setHeadSize( headSize );
			bar.setHeadType( headType );
		}
		return true;
	}



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

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

		SGDrawingElementErrorBar bar = (SGDrawingElementErrorBar)element;
		this.setLineWidth( bar.getLineWidth() );
		this.setHeadSize( bar.getHeadSize() );
		this.setLineWidth( bar.getLineWidth() );
		this.setHeadType( bar.getHeadType() );
		this.setErrorBarStyle( bar.getErrorBarStyle() );

		return true;
	}



	/**
	 * @author  okumura
	 */
	public static class ErrorBarProperties extends ElementGroupProperties
	{

		private SGDrawingElementErrorBar.ErrorBarProperties mErrorBarProperties
			= new SGDrawingElementErrorBar.ErrorBarProperties();


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


		/*
		 * 
		 */
		public boolean equals( final Object obj )
		{
			if( ( obj instanceof ErrorBarProperties ) == false ) return false;

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

			ErrorBarProperties p = (ErrorBarProperties)obj;

			if( this.mErrorBarProperties.equals(p.mErrorBarProperties) == false ) return false;

			return true;
		}


		public Float getLineWidth()
		{
			return this.mErrorBarProperties.getLineWidth();
		}

		public Float getHeadSize()
		{
			return this.mErrorBarProperties.getHeadSize();
		}
		
		public Integer getHeadType()
		{
			return this.mErrorBarProperties.getHeadType();
		}

		public void setColor( final ArrayList list )
		{
			super.setColor( list );
			this.mErrorBarProperties.setColor( list );
		}
		
		public void setLineWidth( final float width )
		{
			this.mErrorBarProperties.setLineWidth( width );
		}
		
		public void setHeadSize( final float size )
		{
			this.mErrorBarProperties.setHeadSize( size );
		}
		
		public void setHeadType( final int type )
		{
			this.mErrorBarProperties.setHeadType( type );
		}


		public Integer getErrorBarStyle()
		{
			return this.mErrorBarProperties.getErrorBarStyle();
		}

		public void setErrorBarStyle( final int style )
		{
			this.mErrorBarProperties.setErrorBarStyle( style );
		}

	}



}
