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

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.util.ArrayList;

import jp.riken.brain.ni.samuraigraph.base.SGAxis;
import jp.riken.brain.ni.samuraigraph.base.SGData;
import jp.riken.brain.ni.samuraigraph.base.SGDefaultValues;
import jp.riken.brain.ni.samuraigraph.base.SGDrawingElement;
import jp.riken.brain.ni.samuraigraph.base.SGILegendElement;
import jp.riken.brain.ni.samuraigraph.base.SGProperties;
import jp.riken.brain.ni.samuraigraph.base.SGPropertyDialog;
import jp.riken.brain.ni.samuraigraph.base.SGTuple2d;
import jp.riken.brain.ni.samuraigraph.base.SGTuple2f;
import jp.riken.brain.ni.samuraigraph.data.SGVXYData;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementArrow;

import org.w3c.dom.Element;



/**
 * 2次元ベクトル型データのグラフのクラス
 */
public class SGVXYGraphElement extends SGGraphElement
{

	/**
	 *
	 */
	protected final int ARROW_GRAPH = 0;


	/**
	 * コンストラクタ
	 */
	public SGVXYGraphElement()
	{
		super();
	}



	/**
	 * 
	 * @return
	 */
	public String getClassDescription()
	{
		return "VXY Graph";
	}



	/**
	 * 
	 * @param data
	 * @param name
	 * @param p
	 * @return
	 */
	public boolean addData( final SGData data, final String name, final SGProperties p )
	{
		return true;
	}



	/**
	 * 
	 * @param data
	 * @param name
	 * @return
	 */
	public boolean addData( final SGData data, final String name )
	{
		// データのチェック
		if( !(data instanceof SGVXYData) )
		{
			return false;
		}
		SGVXYData dataVXY = (SGVXYData)data;


		// リストに追加
		mDataList.add(data);


		// get axes list
		final SGAxis bAxis = mAxisElement.getAxisInPlane( SGAxisElement.AXIS_HORIZONTAL_1 );
		final SGAxis tAxis = mAxisElement.getAxisInPlane( SGAxisElement.AXIS_HORIZONTAL_2 );
		final SGAxis lAxis = mAxisElement.getAxisInPlane( SGAxisElement.AXIS_PERPENDICULAR_1 );
		final SGAxis rAxis = mAxisElement.getAxisInPlane( SGAxisElement.AXIS_PERPENDICULAR_2 );
		SGAxis axisX = null;
		SGAxis axisY = null;
		if( SGDefaultValues.SCALE_REFERENCE.equals("Left-Bottom") )
		{
			axisX = bAxis;
			axisY = lAxis;
		}
		else if( SGDefaultValues.SCALE_REFERENCE.equals("Left-Top") )
		{
			axisX = tAxis;
			axisY = lAxis;
		}
		else if( SGDefaultValues.SCALE_REFERENCE.equals("Right-Bottom") )
		{
			axisX = bAxis;
			axisY = rAxis;
		}
		else if( SGDefaultValues.SCALE_REFERENCE.equals("Right-Top") )
		{
			axisX = tAxis;
			axisY = rAxis;
		}
		else
		{
			return false;
		}


		//
		ElementGroupSetInGraph groupSet = null;
		if( data instanceof SGVXYData )
		{
			groupSet = this.createGroupSet( (SGVXYData)data, axisX, axisY, name );
		}
		else
		{
			return false;
		}


		//
		this.mGroupSetList.add( groupSet );


		// update the history after new data elements are added
		if( this.updateHistory() == false )
		{
			return false;
		}

this.notifyToRoot();


		return true;
	}




	/**
	 * 
	 */
	private ElementGroupSetInVXYGraph createGroupSet(
		final SGVXYData data, final SGAxis axisX, final SGAxis axisY,
		final String name )
	{

		final ElementGroupSetInVXYGraph groupSet
			= new ElementGroupSetInVXYGraph();

		groupSet.setName(name);


		// 軸
		groupSet.setXAxis(axisX);
		groupSet.setYAxis(axisY);



		//
		// 新規描画要素の作成
		//

		groupSet.addDrawingElementGroup( ARROW_GRAPH );


		// 倍率
		groupSet.setMagnification( this.mMagnification );


		//
		groupSet.initPropertiesHistory();


		return groupSet;		
	}




	/**
	 * 
	 */
	public boolean synchronizeToLegendElement( final SGILegendElement lElement )
	{

		boolean flag = super.synchronizeToLegendElement(lElement);
		if( !flag )
		{
			return flag;
		}


		for( int ii=0; ii<mDataList.size(); ii++ )
		{
			ElementGroupSetInVXYGraph groupSet
				= (ElementGroupSetInVXYGraph)this.mGroupSetList.get(ii);
			ArrayList groupList = groupSet.mDrawingElementGroupList;
			groupList.clear();

			SGData data = (SGData)mDataList.get(ii);

			// name of the data
			String name = lElement.getDataName(data);
			groupSet.setName(name);

			// properties of the data
			ArrayList dElementList = lElement.getDrawingElementList(data);
			for( int jj=0; jj<dElementList.size(); jj++ )
			{
				SGDrawingElement dElement = (SGDrawingElement)dElementList.get(jj);
				groupSet.addDrawingElementGroup(dElement);
			}

		}

		this.setAllDrawingElementsLocation();


		return flag;
	}



	/**
	 * プロパティダイアログの作成
	 */
	protected boolean createDataDialog()
	{
		return true;
	}


	
	/**
	 * 
	 */
	protected boolean setAllDrawingElementsLocation()
	{

		for( int ii=0; ii<this.mGroupSetList.size(); ii++ )
		{
			final ElementGroupSetInGraph groupSet
				= (ElementGroupSetInGraph)this.mGroupSetList.get(ii);

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

			final SGData data = (SGData)this.mDataList.get(ii);

			// calculate coordinates in graph
			if( ((ElementGroupSetInVXYGraph)groupSet).createPointList(data) == false )
			{
				return false;
			}

			// create drawing elements
			if( groupSet.createDrawingElements() == false )
			{
				return false;
			}

		}


		return true;
	}




	/**
	 * 
	 */
	public void paintGraphics( Graphics g, boolean clip )
	{
		final Graphics2D g2d = (Graphics2D)g;

		// グラフ描画領域のクリッピング
		if( clip )
		{
			SGUtilityForFigureElement.clipGraphRect(this,g2d);
		}

		// グラフの描画
		for( int ii=0; ii<this.mGroupSetList.size(); ii++ )
		{
			ElementGroupSetInVXYGraph groupSet = (ElementGroupSetInVXYGraph)this.mGroupSetList.get(ii);

			ArrayList groupList = groupSet.mDrawingElementGroupList;

			for( int jj=0; jj<groupList.size(); jj++ )
			{
				SGElementGroup group = (SGElementGroup)groupList.get(jj);
				group.paintElement( g2d );
			}
		}

		if( clip )
		{
			g2d.setClip( this.getComponent().getBounds() );
		}

	}






	/**
	 * 
	 */
	class ElementGroupSetInVXYGraph extends ElementGroupSetInGraph
	{

		/**
		 * 
		 */
		protected ElementGroupSetInVXYGraph()
		{
			super();
		}

		
		/**
		 * 
		 * @return
		 */
		public String getClassDescription()
		{
			return "";
		}


		/**
		 * 
		 */
		protected boolean createDrawingElements()
		{
			return true;
		}


		/**
		 * 
		 */
		public boolean addDrawingElementGroup( final int type )
		{

			SGElementGroupVXY group = null;
			if( type == ARROW_GRAPH )
			{
				group = new ElementGroupArrow();
			}
			else
			{
				throw new Error("");
			}

			group.setMagnification(this.mMagnification);

			this.addDrawingElementGroup(group);

			return true;
		}



		/**
		 * 
		 */
		public boolean addDrawingElementGroup( final SGDrawingElement element )
		{

			SGElementGroupVXY group = null;
			if( element instanceof SGDrawingElementArrow )
			{
				group = new ElementGroupArrow();
			}
			else
			{
				throw new Error("");
			}

			group.setProperty( element );
			group.setMagnification(this.mMagnification);

			this.addDrawingElementGroup(group);

			return true;
		}



		/**
		 * 
		 */
		private boolean addDrawingElementGroup( final SGElementGroupVXY group )
		{
			group.mGroupSet = this;

			SGVXYData dataVXY = (SGVXYData)getData(this);
			final int num = dataVXY.getStartArray().length;

			//
			group.initDrawingElement(num);


			// get the list of positions of datas
			SGTuple2f[] startLocationArray = new SGTuple2f[num];
			SGTuple2f[] endLocationArray = new SGTuple2f[num];
			for( int ii=0; ii<num; ii++ )
			{
				startLocationArray[ii] = new SGTuple2f();
				endLocationArray[ii] = new SGTuple2f();
			}
			calcLocationOfVXYData(
				dataVXY.getStartArray(),
				dataVXY.getEndArray(),
				this.getXAxis(),
				this.getYAxis(),
				startLocationArray,
				endLocationArray
			);


			// 描画要素の作成
			group.setLocation(
				startLocationArray,
				endLocationArray );


			// 倍率
			group.setMagnification( mMagnification );


			// グループをデータのリストに追加
			this.mDrawingElementGroupList.add( group );


			return true;
		}


		private SGTuple2f[] mStartPointsArray = null;
		private SGTuple2f[] mEndPointsArray = null;


		/**
		 * 
		 */
		public boolean createPointList( final SGData data )
		{

			if( ( data instanceof SGVXYData ) == false )
			{
				return false;
			}

			SGVXYData dataVXY = (SGVXYData)data;
			final int num = dataVXY.getStartArray().length;

			SGTuple2d[] startValueArray = dataVXY.getStartArray();
			SGTuple2d[] endValueArray = dataVXY.getEndArray();

			SGTuple2f[] startPointsArray = new SGTuple2f[num];
			SGTuple2f[] endPointsArray = new SGTuple2f[num];
			for( int ii=0; ii<num; ii++ )
			{
				startPointsArray[ii] = new SGTuple2f();
				endPointsArray[ii] = new SGTuple2f();
			}

			boolean flag = calcLocationOfVXYData(
				startValueArray,
				endValueArray,
				this.getXAxis(),
				this.getYAxis(),
				startPointsArray,
				endPointsArray
			);

			if( !flag )
			{
				return false;
			}

			this.mStartPointsArray = startPointsArray;
			this.mEndPointsArray = endPointsArray;


			return true;
		}




		/**
		 * 
		 */
		public void paintGraphics2D(
			final Graphics2D g2d )
		{

		}



		/**
		 * 
		 */
		public boolean prepare()
		{
			return true;
		}


		/**
		 * Returns a property dialog.
		 * @return property dialog
		 */
		public SGPropertyDialog getPropertyDialog()
		{
			return null;
		}


		/**
		 * 
		 */
		protected boolean clickDrawingElements( final MouseEvent e )
		{
			return false;
		}


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


		/**
		 * 
		 */
		public boolean writeProperty( final Element el )
		{
			return true;
		}

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

			super.writePropertyOfData(writer);


			// 軸の配置の出力
			int configX = mAxisElement.getConfigurationInCube( this.mXAxis );
			int configY = mAxisElement.getConfigurationInCube( this.mYAxis );
			
			writer.write("configX "+configX+"\n" );
			writer.write("configY "+configY+"\n" );


			// 各データが持つ描画要素群にプロパティを出力させる
			for( int ii=0; ii<this.mDrawingElementGroupList.size(); ii++ )
			{
				SGElementGroup group = (SGElementGroup)this.mDrawingElementGroupList.get(ii);
				group.writePropertyOfData(writer);
			}


			return true;
		}
*/

	}


	/**
	 *
	 */
	class ElementGroupArrow extends SGElementGroupArrow
	{

		/**
		 *
		 */
		protected ElementGroupArrow()
		{
			super();
		}


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


		/**
		 * 
		 */
		protected boolean setDialogProperty()
		{
			super.setDialogProperty();

			return true;
		}


	}


}

