
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 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.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_FULL;


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



	/**
	 * 
	 * @return
	 */
	protected boolean initDrawingElement( final int num )
	{
		SGDrawingElementErrorBar2D[] array = new SGDrawingElementErrorBar2D[num];
		for( int ii=0; ii<num; ii++ )
		{
			array[ii] = new SGDrawingElementErrorBar2D();
		}
		this.mDrawingElementArray = array;
		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");
		}


		SGDrawingElementErrorBar2D[] array = (SGDrawingElementErrorBar2D[])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 )
			{
				array[ii].setTermPoints( startArray[ii], endArray[ii] );
			}
		}

		return true;

	}



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


	/**
	 * 
	 * @param width
	 */
	public void setLineWidth( final float width )
	{
		this.mLineWidth = width;
		SGDrawingElementErrorBar2D[] array
			= (SGDrawingElementErrorBar2D[])this.mDrawingElementArray;
		if( array==null )
		{
			return;
		}

		for( int ii=0; ii<array.length; ii++ )
		{
			array[ii].setLineWidth( width );
		}
	}


//	/**
//	 * 
//	 * @return
//	 */
//	public int getLineType()
//	{
//		return this.mLineType;
//	}


	/**
	 * 
	 * @param type
	 */
//	public void setLineType( final int type )
//	{
//		this.mLineType = type;
//		SGDrawingElementErrorBar2D[] array
//			= (SGDrawingElementErrorBar2D[])this.mDrawingElementArray;
//		if( array==null )
//		{
//			return;
//		}
//
//		for( int ii=0; ii<array.length; ii++ )
//		{
//			array[ii].setLineType( type );
//		}
//	}

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


	/**
	 * 
	 * @param size
	 */
	public void setHeadSize( final float size )
	{
		this.mHeadSize = size;
		SGDrawingElementErrorBar2D[] array
			= (SGDrawingElementErrorBar2D[])this.mDrawingElementArray;
		if( array==null )
		{
			return;
		}

		for( int ii=0; ii<array.length; ii++ )
		{
			array[ii].setHeadSize( size );
		}
	}


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


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

		for( int ii=0; ii<array.length; ii++ )
		{
			array[ii].setErrorBarStyle( style );
		}
	}


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


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

		el.setAttribute( KEY_VISIBLE, Boolean.toString( this.mVisibleFlag ) );
		el.setAttribute( KEY_ERROR_BAR_STYLE, SGDrawingElementErrorBar.getErrorBarStyleName( this.mErrorBarStyle ) );
		el.setAttribute( KEY_LINE_WIDTH, Float.toString( this.mLineWidth ) + pt );
		el.setAttribute( KEY_HEAD_SIZE, Float.toString( this.mHeadSize*SGIConstants.CM_POINT_RATIO ) + 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 SGProperties readProperties( final Element el )
	{
		final String cm = SGUtilityNumber.cm;
		final String pt = SGUtilityNumber.pt;
		final float ratio = SGIConstants.CM_POINT_RATIO;

		String str = null;
		Number num = null;
		Color cl = null;
		Boolean b = null;
		ArrayList list = null;

		ErrorBarProperties p = new ErrorBarProperties();


		// visible
		str = el.getAttribute( KEY_VISIBLE );
		if( str.length()==0 )
		{
			return null;
		}
		b = SGUtilityText.getBoolean(str);
		if( b==null )
		{
			return null;
		}
		p.setVisible( b.booleanValue() );

		
		// color
		str = el.getAttribute( KEY_COLOR_LIST );
		if( str.length()==0 )
		{
			return null;
		}
		list = SGUtilityText.getColorList(str);
		if( list==null )
		{
			return null;
		}
		p.setColorList( list );


		// 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 null;
			}
		}
		num = SGUtilityText.getFloat(str,pt);
		if( num==null )
		{
			return null;
		}
		final float lineWidth = num.floatValue();
		p.setLineWidth( lineWidth );


		// head size
		str = el.getAttribute( KEY_HEAD_SIZE );
		if( str.length()==0 )
		{
			return null;
		}
		num = SGUtilityText.getFloat(str,cm);
		if( num==null )
		{
			return null;
		}
		p.setHeadSize( num.floatValue()/ratio );

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


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

		p.setHeadType( symbolType );

//		switch( style )
//		{
//			case SGElementGroupErrorBar.ERROR_BAR_FULL :
//			{
//				p.setStartHeadType( symbolType );
//				p.setEndHeadType( symbolType );
//				break;
//			}
//				
//			case SGElementGroupErrorBar.ERROR_BAR_UPPER_ONLY :
//			{
//				p.setStartHeadType( SGDrawingElementSymbol.SYMBOL_TYPE_VOID );
//				p.setEndHeadType( symbolType );
//				break;
//			}
//
//			case SGElementGroupErrorBar.ERROR_BAR_LOWER_ONLY :
//			{
//				p.setStartHeadType( symbolType );
//				p.setEndHeadType( SGDrawingElementSymbol.SYMBOL_TYPE_VOID );
//				break;
//			}
//
//			default :
//			{
//
//			}
//		}
		
		
		// not from Element object
//		p.setLineType( SGDrawingElementLine.LINE_TYPE_SOLID );
//		p.setHeadLineColor( (Color)list.get(0) );
//		p.setHeadLineWidth( lineWidth );

		return p;
	}

	

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


	/**
	 * 
	 */
	public void setHeadType( int type )
	{
		this.mHeadType = type;
		SGDrawingElementErrorBar2D[] array
			= (SGDrawingElementErrorBar2D[])this.mDrawingElementArray;
		if( array==null )
		{
			return;
		}

		for( int ii=0; ii<array.length; ii++ )
		{
			array[ii].setHeadType(type);
		}
	}




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

		return bar;
	}



//	/**
//	 * 
//	 */
//	public boolean paintElement( Graphics2D g2d, Rectangle2D rect )
//	{
//		SGDrawingElementErrorBar2D[] array
//			= (SGDrawingElementErrorBar2D[])this.mDrawingElementArray;
//		for( int ii=0; ii<array.length; ii++ )
//		{
//			array[ii].paint( g2d, rect );
//		}
//		return true;
//	}
	
	/**
	 * 
	 */
	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()
	{
		SGDrawingElementErrorBar2D[] array
			= (SGDrawingElementErrorBar2D[])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++ )
		{
			SGDrawingElementErrorBar2D bar = array[ii];
			bar.setErrorBarStyle( style );
			bar.setMagnification( mag );
			bar.setColor( 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;
	}



	/**
	 * 
	 */
	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 setColorList( final ArrayList list )
		{
			super.setColorList( 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 );
		}

	}



}
