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

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


/**
 * 
 */
public abstract class SGElementGroupLine extends SGElementGroupSXY
{

	/**
	 *
	 */
	protected float mLineWidth = 0.10f/SGConstants.CM_POINT_RATIO;


	/**
	 *
	 */
	protected int mLineType = SGDrawingElementLine.LINE_TYPE_SOLID;


	/**
	 * 
	 */
	protected int mCap = BasicStroke.CAP_BUTT;


	/**
	 * 
	 */
	protected int mJoin = BasicStroke.JOIN_ROUND;


	/**
	 * 
	 */
	protected float mMiterLimit = 1.0f;


	/**
	 * 
	 */
	protected float mDashPhase = 0.0f;



	/**
	 * 
	 */
	protected GeneralPath mConnectedPath = null;


	/**
	 * 
	 */
	protected int[] mXPoints = null;
	protected int[] mYPoints = null;
	protected int mNPoints = 0;


	/**
	 * 
	 */
	public static final String PF_LINE_TITLE = "<Line>";
	public static final String KEY_LINE_WIDTH = "Width";
	public static final String KEY_LINE_TYPE = "Type";
	public static final String PF_LINE_COLOR_LIST = "Color List";




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


	/**
	 *
	 */
	public boolean setLineWidth( final float width )
	{
		if( width<0.0f )
		{
			throw new IllegalArgumentException("width<0.0f");
		}
		mLineWidth = width;
		for( int ii=0; ii<mDrawingElementList.size(); ii++ )
		{
			SGDrawingElementLine2D el = (SGDrawingElementLine2D)mDrawingElementList.get(ii);
			el.setLineWidth( mLineWidth );
		}
		return true;
	}


	/**
	 *
	 */
	public boolean setLineType( final int type )
	{
		mLineType = type;
		for( int ii=0; ii<mDrawingElementList.size(); ii++ )
		{
			SGDrawingElementLine2D el = (SGDrawingElementLine2D)mDrawingElementList.get(ii);
			el.setType( mLineType );
		}

		return true;
	}



	/**
	 * 
	 * @param cap
	 * @return
	 */
	public boolean setBasicStrokeProperty(
		final int cap, final int join, final float miterlimit, final float dash_phase )
	{

		if( cap!=BasicStroke.CAP_BUTT && cap!=BasicStroke.CAP_ROUND
			&& cap!=BasicStroke.CAP_SQUARE )
		{
			throw new IllegalArgumentException("The argument is invalid.");
		}

		if( join!=BasicStroke.JOIN_BEVEL && join!=BasicStroke.JOIN_MITER
			&& join!=BasicStroke.JOIN_ROUND )
		{
			throw new IllegalArgumentException("The argument is invalid.");
		}

		if( miterlimit<1.0f && join==BasicStroke.JOIN_MITER )
		{
			throw new IllegalArgumentException("The argument is invalid.");
		}

		if( dash_phase<0.0f )
		{
			throw new IllegalArgumentException("The argument is invalid.");
		}

		this.mCap = cap;
		this.mJoin = join;
		this.mMiterLimit = miterlimit;
		this.mDashPhase = dash_phase;

		return true;
	}



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


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


	/**
	 * 
	 * @return
	 */
	public int getCap()
	{
		return this.mCap;
	}



	/**
	 * 
	 */
	public int getJoin()
	{
		return this.mJoin;
	}


	/**
	 * 
	 * @return
	 */
	public float getMiterLimit()
	{
		return this.mMiterLimit;
	}


	/**
	 * 
	 */
	public SGDrawingElement getDrawingElement()
	{
		// line
		SGDrawingElementLine line = new SGDrawingElementLine2D();
		line.setLineWidth( mLineWidth );
		line.setType( mLineType );
		line.setColorList( mColorList );

		return line;		
	}


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

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

		SGDrawingElementLine line = (SGDrawingElementLine)element;

		this.setLineType( line.getLineType() );
		this.setLineWidth( line.getLineWidth() );
	
		return true;
	}





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

		if( this.mConnectedPath==null || g2d==null )
		{
			return false;
		}


//System.out.println("paint");

/*
		ArrayList colorList = new ArrayList(this.mColorList);
//System.out.println(this.mEnteredFlag);
//System.out.println("start:"+this.mColorList);
		if( this.mEnteredFlag )
		{
			ArrayList colorList_ = new ArrayList();
			for( int ii=0; ii<colorList.size(); ii++ )
			{
				Color colorOld = ((Color)colorList.get(ii));

//				Color color_ = new Color(
//					255 - colorOld.getRed(),
//					255 - colorOld.getGreen(),
//					255 - colorOld.getBlue()
//				);
		
				Color color_ = new Color(
					colorOld.getRed(),
					colorOld.getGreen(),
					colorOld.getBlue(),
					128
				);
		
//Color color_ = Color.RED;
		
				colorList_.add(color_);
			}
			this.setColorList(colorList_);
		}


		// 選択されている場合には色を変化
		if( this.mSelectedFlag )
		{
//this.start();
//			this.shiftColorList();
		}
*/


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

//System.out.println(this.getColor(0));

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

//System.out.println(width);
//System.out.println();

		switch( this.mLineType )
		{
			case SGDrawingElementLine2D.LINE_TYPE_SOLID :
			{
				g2d.setStroke
				(
					new BasicStroke
					(
						width,
						this.mCap,
						this.mJoin
					)
				);
				break;
			}
					
			case SGDrawingElementLine2D.LINE_TYPE_BROKEN :
			{
				final float[] dash = {2.0f*width,width};
				g2d.setStroke
				(
					new BasicStroke
					(
						width,
						this.mCap,
						this.mJoin,
						this.mMiterLimit,
						dash,
						this.mDashPhase
					)
				);
				break;
			}

			case SGDrawingElementLine2D.LINE_TYPE_DOT :
			{
				final float[] dash = {width};
				g2d.setStroke
				(
					new BasicStroke
					(
						width,
						this.mCap,
						this.mJoin,
						this.mMiterLimit,
						dash,
						this.mDashPhase
					)
				);
				break;
			}
					
			default :
			{
						
			}

		}


		// 描画
		g2d.draw( this.mConnectedPath );


//		this.setColorList(colorList);

		return true;
	}






	/**
	 * 
	 */
	public boolean writePropertyOfData( final Writer writer ) throws IOException
	{
		writer.write( PF_LINE_TITLE + "\n" );

		SGUtilityText.writePropertyLine( writer, KEY_VISIBLE, new Boolean( this.mVisibleFlag ) );
		SGUtilityText.writePropertyLine( writer, KEY_LINE_WIDTH, new Float( this.mLineWidth ) );
		SGUtilityText.writePropertyLine( writer, KEY_LINE_TYPE, SGDrawingElementLine.getLineTypeName( this.mLineType ) );
		SGUtilityText.writeColorListPropertyLine( writer, PF_LINE_COLOR_LIST, this.mColorList );

		writer.write("\n");

		return true;
	}



	/**
	 * 
	 */
	public SGProperties readProperties( final BufferedReader br ) throws IOException
	{

		LineProperties p = new LineProperties();

		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() );


		// line width
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		Double dLineWidth = SGUtilityText.getDoublePropertyFromLine(line,KEY_LINE_WIDTH);
		if( dLineWidth == null )
		{
			return null;
		}
		p.setLineWidth( dLineWidth.floatValue() );


		// line type
		if( ( line = SGUtilityText.readLine(br) ) == null )
		{
			return null;
		}
		String strLineType = SGUtilityText.getPropertyFromLine(line,KEY_LINE_TYPE);
		if( strLineType == null )
		{
			return null;
		}
		Integer nLineType = SGDrawingElementLine.getLineTypeFromName(strLineType);
		if( nLineType == null )
		{
			return null;
		}
		p.setLineType( nLineType.intValue() );


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


		return p;
	}




	/**
	 * 
	 */
	public boolean createDrawingElement(
		final ArrayList pointList )
	{

//System.out.println("GroupLine : createDrawingElement");

long s;
long e;

		this.mDrawingElementList.clear();


		if( pointList.size() < 2 )
		{
			return false;
		}


		final SGTuple2f[] pointArray = new SGTuple2f[pointList.size()];
		for( int ii=0; ii<pointList.size(); ii++ )
		{
			pointArray[ii] = (SGTuple2f)pointList.get(ii);
		}


s = System.currentTimeMillis();
		// 線分の描画要素を作成
		for( int ii=0; ii<pointArray.length-1; ii++ )
		{
			final SGDrawingElementLine line
				= new SGDrawingElementLine2D(
					pointArray[ii], pointArray[ii+1] );
			line.setType( mLineType );
			line.setColorList( mColorList );
			line.setLineWidth( mLineWidth );

			this.addDrawingElement(line);

//System.out.println("ii="+ii+"  "+start+"  "+end);

		}
e = System.currentTimeMillis();
//System.out.println("create : "+(e-s));


s = System.currentTimeMillis();


		// create a general path
		final GeneralPath gp = new GeneralPath();
		Line2D line = new Line2D.Float(
			pointArray[0].x, pointArray[0].y, pointArray[1].x, pointArray[1].y );
		gp.append( line, true );
		if( pointArray.length > 2 )
		{
			for( int ii=2; ii<pointArray.length; ii++ )
			{
				gp.lineTo( pointArray[ii].x, pointArray[ii].y );
			}
		}
		this.mConnectedPath = gp;



e = System.currentTimeMillis();
//System.out.println("polyline : "+(e-s));


		return true;
	}



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


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

		super.getProperties(p);

		LineProperties lp = (LineProperties)p;
		lp.setLineWidth( this.getLineWidth() );
		lp.setLineType( this.getLineType() );

		return true;
	}




	/**
	 * 
	 */
	public boolean setProperties( SGProperties p )
	{

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

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

		LineProperties lp = (LineProperties)p;
		Float width = lp.getLineWidth();
		if( width==null )
		{
			return false;
		}
		Integer type = lp.getLineType();
		if( type==null )
		{
			return false;
		}

		this.setLineWidth( width.floatValue() );
		this.setLineType( type.intValue() );

		return true;
	}





	/**
	 * 
	 */
	public static class LineProperties extends ElementGroupProperties
	{
//		int type;
//		float width;

		public static final String[] keys = {
			KEY_LINE_WIDTH, KEY_LINE_TYPE
		};


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


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

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

			LineProperties p = (LineProperties)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 String toString()
		{
			String str = new String("[");
			str += new String("visible="+visible+", ");
			str += new String("colorList="+colorList+", ");
			str += new String("type="+type+", ");
			str += new String("width="+width+", ");
			str += new String("]");

			return str;
		}
*/

		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 boolean setLineWidth( final float w )
		{
			if( w<0.0f )
			{
				return false;
			}
			this.setProperty( KEY_LINE_WIDTH, new Float(w).toString() );
			return true;
		}

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


	}


}



