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

import java.util.*;
import java.io.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import javax.swing.*;
import jp.riken.brain.ni.samuraigraph.base.*;
import jp.riken.brain.ni.samuraigraph.data.*;
import jp.riken.brain.ni.samuraigraph.figure.*;


/**
 *
 */
public abstract class SGElementGroupBar extends SGElementGroupRectangle
{


	/**
	 * 
	 */
	protected double mBaselineValue;



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



	/**
	 * 
	 */
	public double getBaseLineValue()
	{
		return this.mBaselineValue;
	}


	/**
	 * 
	 */
	public boolean setBaseLineValue( final double value )
	{
		this.mBaselineValue = value;
		return true;
	}




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

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

		SGDrawingElementBar bar = (SGDrawingElementBar)element;
		this.setBaseLineValue( bar.getReferenceValue() );

		return true;
	}



	/**
	 * 
	 */
	public boolean paintElement( final Graphics2D g2d )
	{
		if( this.mDrawingElementArray!=null )
		{
//System.out.println("<< SGElementGroupBar::paintElement >>");

			final float width = mMagnification*this.mEdgeLineWidth;

			for( int ii=0; ii<this.mDrawingElementArray.length; ii++ )
			{
//System.out.println("ii="+ii);

				SGDrawingElementBar2D el
					= (SGDrawingElementBar2D)mDrawingElementArray[ii];

				if( el.isVisible() == false )
				{
					continue;
				}


				final float x = el.getX();
				final float y = el.getY();
				final float w = el.getWidth();
				final float h = el.getHeight();

				Rectangle2D dRect = new Rectangle2D.Float( x, y, w, h );

//System.out.println(dRect);

				// fill the rectangles
				final int cNum = this.mColorList.size();
				if( cNum > 1 )
				{
					//
					// 複数の色を持つ場合には、GradientPaintを用いる
					//

					// X座標値
					final float gX = x + 0.50f*w;

					// 高さを色数で割った値
					final float diff = h/cNum;

					// グラデーションを付ける幅
//					final float delta = diff/10.0f;
final float delta = 5.0f;

					// rectangleを分割する（色数+1）
					Rectangle2D[] rectArray = new Rectangle2D[cNum+1];
					rectArray[0] = new Rectangle2D.Float( x, y, w, 0.50f*diff );	// 上端
					rectArray[rectArray.length-1]
						= new Rectangle2D.Float(
							x, y + h - 0.50f*diff, w, 0.50f*diff );		// 下端
					for( int jj=1; jj<rectArray.length-1; jj++ )
					{
						final float yy = y+ 0.50f*diff + (jj-1)*diff;
						rectArray[jj] = new Rectangle2D.Float(
							x, yy, w, diff );
					}


					// 区切り点のY座標値の配列（色数-1）
					float[] gYArray = new float[cNum-1];
					for( int jj=0; jj<gYArray.length; jj++ )
					{
						gYArray[jj] = y + (jj+1)*diff;
					}


					// 分割した矩形を塗りつぶす
					g2d.setPaint( (Color)this.getColorList().get(0) );
					g2d.fill(rectArray[0]);

					for( int jj=0; jj<gYArray.length; jj++ )
					{
						Color c1 = (Color)this.mColorList.get(jj);
						Color c2 = (Color)this.mColorList.get(jj+1);
						final float y1 = gYArray[jj] - delta;
						final float y2 = gYArray[jj] + delta;
						GradientPaint gPaint = new GradientPaint(
							gX, y1, c1, gX, y2, c2 );
						g2d.setPaint( gPaint );
						g2d.fill(rectArray[jj+1]);
					}

					g2d.setPaint( (Color)this.getColorList().get(cNum-1) );
					g2d.fill(rectArray[rectArray.length-1]);

				}
				else
				{
					g2d.setPaint(this.getColor(0));
					g2d.fill(dRect);
				}



				// draw edge lines
				g2d.setStroke(
					new BasicStroke
					(
						width,
						BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER
					)
				);
				g2d.setPaint(this.mEdgeLineColor);
				g2d.draw(dRect);

			}

//System.out.println();

		}

		return true;
	}



	/**
	 * 
	 */
	public SGDrawingElement getDrawingElement()
	{
		SGDrawingElementBar rect = new SGDrawingElementBar2D();
		rect.setVisible( this.mVisibleFlag );
		rect.setWidth( this.mRectangleWidth );
		rect.setHeight( this.mRectangleHeight );
		rect.setEdgeLineWidth( this.mEdgeLineWidth );
		rect.setEdgeLineColor( this.mEdgeLineColor );
		rect.setColorList( this.mColorList );
		rect.setReferenceValue( this.mBaselineValue );

		return rect;
	}


	public static final String BAR_TITLE = "<Bar>";
	public static final String KEY_BAR_WIDTH = "Width";
	public static final String KEY_EDGE_LINE_WIDTH = "Edge Line Width";
	public static final String KEY_EDGE_LINE_COLOR = "Edge Line Color";
	public static final String KEY_BASELINE_VALUE = "Baseline Value";


	/**
	 * 
	 */
	public boolean writePropertyOfData( final Writer writer ) throws IOException
	{

		writer.write( BAR_TITLE + "\n" );

		SGUtilityText.writePropertyLine( writer, KEY_VISIBLE, new Boolean( this.mVisibleFlag ) );
		SGUtilityText.writePropertyLine( writer, KEY_BAR_WIDTH, new Float( this.mRectangleWidth*SGConstants.CM_POINT_RATIO ) );
		SGUtilityText.writeColorListPropertyLine( writer, KEY_COLOR_LIST, this.mColorList );
		SGUtilityText.writePropertyLine( writer, KEY_EDGE_LINE_WIDTH, new Float( this.mEdgeLineWidth ) );
		SGUtilityText.writePropertyLine( writer, KEY_BASELINE_VALUE, new Double( this.mBaselineValue ) );
		SGUtilityText.writeColorPropertyLine( writer, KEY_EDGE_LINE_COLOR, this.mEdgeLineColor );

		writer.write("\n");

		return true;
	}



	/**
	 * 
	 */
	public SGProperties readProperties( final BufferedReader br ) throws IOException
	{
		BarProperties p = new BarProperties();

		String line = null;


		// visible
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		Boolean bVisible = SGUtilityText.getBooleanPropertyFromLine(line,KEY_VISIBLE);
		if( bVisible == null )
		{
			return null;
		}
		p.setVisible( bVisible.booleanValue() );


		// width of the bar
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		Double dBarWidth = SGUtilityText.getDoublePropertyFromLine(line,KEY_BAR_WIDTH);
		if( dBarWidth == null )
		{
			return null;
		}
		p.setBarWidth( dBarWidth.floatValue()/SGConstants.CM_POINT_RATIO );


		// inner color list
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		ArrayList colorList = SGUtilityText.getColorListFromLine(line,KEY_COLOR_LIST);
		if( colorList == null )
		{
			return null;
		}
		p.setColorList( colorList );


		// edge line width
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		Double dEdgeLineWidth = SGUtilityText.getDoublePropertyFromLine(line,KEY_EDGE_LINE_WIDTH);
		if( dEdgeLineWidth == null )
		{
			return null;
		}
		p.setEdgeLineWidth( dEdgeLineWidth.floatValue() );


		// baseline value
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		Double dBaselineValue = SGUtilityText.getDoublePropertyFromLine(line,KEY_BASELINE_VALUE);
		if( dBaselineValue == null )
		{
			return null;
		}
		p.setBaselineValue( dBaselineValue.doubleValue() );


		// edge line color
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		Color edgeLineColor = SGUtilityText.getColorPropertyFromLine(line,KEY_EDGE_LINE_COLOR);
		if( edgeLineColor == null )
		{
			return null;
		}
		p.setEdgeLineColor( edgeLineColor );


		return p;

	}



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


	/**
	 * 
	 * @return
	 */
	protected boolean initDrawingElement( final SGTuple2f[] array )
	{
		final int num = array.length;
		SGDrawingElementBar2D[] bArray = new SGDrawingElementBar2D[num];
		for( int ii=0; ii<num; ii++ )
		{
			bArray[ii] = new SGDrawingElementBar2D();
			bArray[ii].setLocation( array[ii].x, array[ii].y );
		}
		this.mDrawingElementArray = bArray;
		return true;
	}


	/**
	 * 
	 */
	public boolean setLocation(
		final SGTuple2f[] pointArray )
	{

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

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

		// 棒グラフの描画要素を作成
		for( int ii=0; ii<this.mDrawingElementArray.length; ii++ )
		{
			SGDrawingElementBar2D bar
				= (SGDrawingElementBar2D)this.mDrawingElementArray[ii];
			final boolean eff = !( pointArray[ii].isInfinite() || pointArray[ii].isNaN() );
			bar.setVisible( eff );
			if( eff )
			{
				bar.setBounds(
					pointArray[ii].x, pointArray[ii].y,
					this.mRectangleWidth, this.mRectangleHeight );
				bar.setLocation( pointArray[ii] );
			}
		}

		return true;
	}



	/**
	 * 
	 * @return
	 */
	public boolean setPropertiesOfDrawingElements()
	{
		for( int ii=0; ii<this.mDrawingElementArray.length; ii++ )
		{
			SGDrawingElementBar2D bar
				= (SGDrawingElementBar2D)this.mDrawingElementArray[ii];
			bar.setMagnification( this.mMagnification );
			bar.setColorList( this.mColorList );
			bar.setEdgeLineWidth( this.mEdgeLineWidth );
			bar.setEdgeLineColor( this.mEdgeLineColor );
		}
		return true;
	}



	/**
	 * 
	 */
	public SGProperties getProperties()
	{
		BarProperties p = new BarProperties();
		this.getProperties(p);
		return p;
	}


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

		super.getProperties(p);

		BarProperties bp = (BarProperties)p;
		bp.setBarWidth( this.getRectangleWidth() );
		bp.setEdgeLineWidth( this.getEdgeLineWidth() );
		bp.setEdgeLineColor( this.getEdgeLineColor() );
		bp.setBaselineValue( this.getBaseLineValue() );

		return true;
	}


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

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

		BarProperties bp = (BarProperties)p;

		Float width = bp.getBarWidth();
		if( width==null )
		{
			return false;
		}
		this.setRectangleWidth( width.floatValue() );

		Float edgeLineWidth = bp.getEdgeLineWidth();
		if( edgeLineWidth==null )
		{
			return false;
		}
		this.setEdgeLineWidth( edgeLineWidth.floatValue() );

		Color edgeLineColor = bp.getEdgeLineColor();
		if( edgeLineColor==null )
		{
			return false;
		}
		this.setEdgeLineColor( edgeLineColor );

		Double baselineValue = bp.getBaselineValue();
		if( baselineValue==null )
		{
			return false;
		}
		this.setBaseLineValue( baselineValue.doubleValue() );

		return true;
	}




	/**
	 * 
	 */
	public static class BarProperties extends ElementGroupProperties
	{
//		float width;
//		float edgeLineWidth;
//		Color edgeLineColor;
//		double baselineValue;


		public static final String[] keys = {
			KEY_BAR_WIDTH, KEY_EDGE_LINE_WIDTH, KEY_EDGE_LINE_COLOR, KEY_BASELINE_VALUE
		};


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


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

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

			BarProperties p = (BarProperties)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 getBarWidth()
		{
			final String value = this.getProperty(KEY_BAR_WIDTH);
			return SGUtilityText.getFloat(value);
		}

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

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

		public Double getBaselineValue()
		{
			final String value = this.getProperty(KEY_BASELINE_VALUE);
			return SGUtilityText.getDouble(value);
		}


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


		public boolean setBaselineValue( final double value )
		{
			this.setProperty( KEY_BASELINE_VALUE, new Double(value).toString() );
			return true;
		}


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

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





		/**
		 * 
		 */
/*		public String toString()
		{
			String str = new String("[");
			str += new String("visible="+visible+", ");
			str += new String("colorList="+colorList+", ");
			str += new String("width="+width+", ");
			str += new String("edgeLineWidth="+edgeLineWidth+", ");
			str += new String("edgeLineColor="+edgeLineColor+", ");
			str += new String("baselineValue="+baselineValue+", ");
			str += new String("]");

			return str;
		}
*/
	}

}
