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

import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;

import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;

import jp.riken.brain.ni.samuraigraph.base.SGAxis;
import jp.riken.brain.ni.samuraigraph.base.SGData;
import jp.riken.brain.ni.samuraigraph.base.SGDrawingElement;
import jp.riken.brain.ni.samuraigraph.base.SGIAxisBreakElement;
import jp.riken.brain.ni.samuraigraph.base.SGIAxisElement;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElement;
import jp.riken.brain.ni.samuraigraph.base.SGIGraphElement;
import jp.riken.brain.ni.samuraigraph.base.SGIGridElement;
import jp.riken.brain.ni.samuraigraph.base.SGILegendElement;
import jp.riken.brain.ni.samuraigraph.base.SGINode;
import jp.riken.brain.ni.samuraigraph.base.SGIPropertyDialogObserver;
import jp.riken.brain.ni.samuraigraph.base.SGISelectable;
import jp.riken.brain.ni.samuraigraph.base.SGISignificantDifferenceElement;
import jp.riken.brain.ni.samuraigraph.base.SGIStringElement;
import jp.riken.brain.ni.samuraigraph.base.SGITimingLineElement;
import jp.riken.brain.ni.samuraigraph.base.SGIUndoable;
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.SGSXYData;
import jp.riken.brain.ni.samuraigraph.figure.SGFigureElement;

import org.w3c.dom.Document;
import org.w3c.dom.Element;



/**
 * グラフの基本クラス
 */

public abstract class SGGraphElement extends SGFigureElement
	implements SGIGraphElement
{

	/**
	 *
	 */
	protected SGIAxisElement mAxisElement = null;


	/**
	 * 
	 */
	protected ArrayList mGroupSetList = new ArrayList();


	/**
	 * 
	 */
	protected SGPropertyDialog mDialog = null;


	/**
	 * 
	 */
	public static final int MAX_NUMBER_OF_ANCHORS = 8;


	/**
	 * 
	 */
/*	public boolean clearFocusedObjects()
	{
		if( super.clearFocusedObjects() == false )
		{
			return false;
		}

		// notify change
		this.focusedDataChanged();

		return true;
	}
*/

	/**
	 * 
	 * @return
	 */
	public ArrayList getVisibleDataList()
	{
		ArrayList list = new ArrayList();
		for( int ii=0; ii<this.mGroupSetList.size(); ii++ )
		{
			ElementGroupSetInGraph groupSet
				= (ElementGroupSetInGraph)this.mGroupSetList.get(ii);
			if( groupSet.isVisible() )
			{
				list.add( this.mDataList.get(ii) );
			}
		}
		
		return list;
	}



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



	/**
	 * 
	 * @return
	 */
	public String toString()
	{
		return new String("SGGraphElement");
	}



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



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



	/**
	 * 全描画要素の位置を決定
	 */
	protected abstract boolean setAllDrawingElementsLocation();



	/**
	 *
	 */
	public boolean setAxisElement( final SGIAxisElement element )
	{
		mAxisElement = element;
		return true;
	}


	/**
	 * Set the name of a data object.
	 * @param data - the data object to get the name
	 */
	public String getDataName( final SGData data )
	{
		final ElementGroupSetInGraph groupSet = this.getElementGroupSet(data);
		if( groupSet != null )
		{
			return groupSet.getName();
		}
		return null;
	}



	/**
	 * Set the name of a data object.
	 * @param data - the data object to set the name
	 * @return true:succeeded, false:failed
	 */
	public boolean setDataName( String name, SGData data )
	{
		final ElementGroupSetInGraph groupSet = this.getElementGroupSet(data);
		if( groupSet != null )
		{
			groupSet.setName( name );
			return true;
		}
		return false;
	}



	/**
	 * 
	 */
	public SGProperties getDataProperties( SGData data )
	{
		final ElementGroupSetInGraph groupSet = this.getElementGroupSet(data);
		if( groupSet != null )
		{
			return groupSet.getWholeProperties();
		}
		return null;
	}




	/**
	 * 
	 */
	public ArrayList getDrawingElementList( final SGData data )
	{
		final ElementGroupSetInGraph groupSet = this.getElementGroupSet(data);
		if( groupSet != null )
		{
			return groupSet.getDrawingElementList();
		}
		return null;
	}



	/**
	 * 
	 */
	public ArrayList getVisibleFlagList( final SGData data )
	{
		if( data==null )
		{
			throw new IllegalArgumentException("data==null");
		}

		final ElementGroupSetInGraph groupSet = this.getElementGroupSet(data);
		if( groupSet==null )
		{
			throw new Error();
		}
		ArrayList list = groupSet.getVisibleFlagList();		

		return list;
	}


	/**
	 * 
	 * @param data
	 * @return
	 */
	public boolean getVisibleInLegendFlag( SGData data )
	{
		if( data==null )
		{
			throw new IllegalArgumentException("data==null");
		}

		final ElementGroupSetInGraph groupSet = this.getElementGroupSet(data);
		if( groupSet==null )
		{
			throw new Error();
		}

		boolean flag = groupSet.isVisibleInLegend();
		return flag;
	}



	/**
	 * 
	 */
	public SGAxis getXAxis( final SGData data )
	{
		final ElementGroupSetInGraph groupSet = this.getElementGroupSet(data);
		
		if( groupSet != null )
		{
			return groupSet.getXAxis();
		}

		return null;
	}


	/**
	 * 
	 */
	public SGAxis getYAxis( final SGData data )
	{
		final ElementGroupSetInGraph groupSet = this.getElementGroupSet(data);
		
		if( groupSet != null )
		{
			return groupSet.getYAxis();
		}

		return null;
	}


	/**
	 * 
	 */
	public SGAxis getZAxis( final SGData data )
	{
		final ElementGroupSetInGraph groupSet = this.getElementGroupSet(data);
		
		if( groupSet != null )
		{
			return groupSet.mZAxis;
		}

		return null;
	}



	/**
	 * ズーム
	 */
	public boolean zoom( final float ratio )
	{
		super.zoom(ratio);

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

		this.setAllDrawingElementsLocation();

		return true;

	}




	/**
	 * 
	 */
	public boolean removeData( final SGData data )
	{
		SGElementGroupSet groupSet = this.getElementGroupSet(data);
		this.mDataList.remove(data);
		this.mGroupSetList.remove(groupSet);

		return true;
	}


	/**
	 * 
	 */
	public boolean setDataVisible( final SGData data, final boolean flag )
	{
		SGElementGroupSet groupSet = this.getElementGroupSet(data);
		groupSet.setVisible(flag);
		return true;
	}



	/**
	 * 
	 */
	public boolean setGraphRect(
		final float x, final float y, final float width, final float height )
	{
		super.setGraphRect(x,y,width,height);
		if( this.setAllDrawingElementsLocation() == false )
		{
			return false;
		}
		return true;
	}



	/**
	 * 同期を取る
	 */
	public boolean synchronize( final SGIFigureElement element )
	{

		boolean flag = true;
		if( element instanceof SGILegendElement )
		{
			final SGILegendElement lElement = (SGILegendElement)element;
			flag = this.synchronizeToLegendElement( lElement );
		}
		else if( element instanceof SGIAxisElement )
		{
//System.out.println("SGIAxisElement");

			final SGIAxisElement aElement = (SGIAxisElement)element;
			flag = this.synchronizeToAxisElement( aElement );
		}
		else if( element instanceof SGIStringElement )
		{
			
		}
		else if( element instanceof SGIGraphElement )
		{
			
		}
		else if( element instanceof SGIAxisBreakElement )
		{
			
		}
		else if( element instanceof SGISignificantDifferenceElement )
		{
			
		}
		else if( element instanceof SGITimingLineElement )
		{
			
		}
		else if( element instanceof SGIGridElement )
		{

		}
		else
		{
			flag = this.synchronizeArgument( element );
		}


		return flag;

	}




	/**
	 * 
	 */
	protected boolean synchronizeToAxisElement( final SGIAxisElement aElement )
	{
		return this.setAllDrawingElementsLocation();
	}



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

		// レジェンドからデータのリストを取得し、自分の持っているデータリストと
		// 描画要素リストをそれに合わせて並び替える
		final ArrayList dataList = lElement.getDataList();
		if( dataList.size() != this.mDataList.size() )
		{
			throw new Error("dataList.size() != this.mDataList.size()");
		}
		final ArrayList dataListNew = new ArrayList();
		final ArrayList groupSetListNew = new ArrayList();
		for( int ii=0; ii<dataList.size(); ii++ )
		{
			final SGData data = (SGData)dataList.get(ii);
			for( int jj=this.mDataList.size()-1; jj>=0; jj-- )
			{
				final SGData data_ = (SGData)this.mDataList.get(jj);
				if( data.equals(data_) )
				{
					final SGData dataRemoved = (SGData)this.mDataList.remove(jj);
					dataListNew.add(dataRemoved);
					final SGElementGroupSet groupSetRemoved = (SGElementGroupSet)this.mGroupSetList.remove(jj);
					groupSetListNew.add(groupSetRemoved);
					break;
				}
			}
		}
		this.mDataList = dataListNew;
		this.mGroupSetList = groupSetListNew;			

		return true;
	}



	/**
	 * Synchronize the element given by the argument.
	 * @param element An object to be synchronized.
	 */
	public boolean synchronizeArgument( final SGIFigureElement element )
	{
	    // this shouldn't happen
	    throw new Error();
	}



	/**
	 * 
	 */
	protected boolean isInsideAxisRange(
		final SGTuple2d value,
		final SGAxis axisX,
		final SGAxis axisY )
	{
		return ( axisX.insideRange(value.x) && axisY.insideRange(value.y) );
	}




	/**
	 * 
	 */
	protected boolean calcLocationOfSXYData(
//		final SGTuple2d[] valueArray,
		final SGSXYData dataSXY,
		final SGAxis axisX,
		final SGAxis axisY,
		final SGTuple2f[] pointArray )
	{
//System.out.println("<< SGGraphElement::calcLocationOfSXYData >>");

		final int num = dataSXY.getPointsNumber();

		final SGTuple2d rangeX = axisX.getRange();
		final SGTuple2d rangeY = axisY.getRange();
		final double minX = rangeX.x;
		final double maxX = rangeX.y;
		final double minY = rangeY.x;
		final double maxY = rangeY.y;
		final int typeX = axisX.getScaleType();
		final int typeY = axisY.getScaleType();


		// グラフ内での値に変換
		double minXInScale = 0.0;
		double maxXInScale = 0.0;
		double minYInScale = 0.0;
		double maxYInScale = 0.0;
		final double[] xInScale = new double[num];
		final double[] yInScale = new double[num];

		if( typeX == SGAxis.LINEAR_TYPE )
		{
			minXInScale = minX;
			maxXInScale = maxX;
			final double[] array = dataSXY.getXValueArray();
			for( int ii=0; ii<num; ii++)
			{
				xInScale[ii] = array[ii];
			}
		}
		else if( typeX == SGAxis.LOG_TYPE )
		{
			minXInScale = Math.log(minX);
			maxXInScale = Math.log(maxX);
			final double[] array = dataSXY.getXValueArray();
			for( int ii=0; ii<num; ii++)
			{
				xInScale[ii] = Math.log( array[ii] );
			}
		}

		if( typeY == SGAxis.LINEAR_TYPE )
		{
			minYInScale = minY;
			maxYInScale = maxY;
			final double[] array = dataSXY.getYValueArray();
			for( int ii=0; ii<num; ii++)
			{
				yInScale[ii] = array[ii];
			}
		}
		else if( typeY == SGAxis.LOG_TYPE )
		{
			minYInScale = Math.log(minY);
			maxYInScale = Math.log(maxY);
			final double[] array = dataSXY.getYValueArray();
			for( int ii=0; ii<num; ii++)
			{
				yInScale[ii] = Math.log( array[ii] );
			}
		}


		// グラフ領域内でのデータ点の比率を計算
		// グラフ全体での位置を計算
		final float gx = this.mGraphRectX;
		final float gy = this.mGraphRectY;
		final float gw = this.mGraphRectWidth;
		final float gh = this.mGraphRectHeight;
		for( int ii=0; ii<num; ii++ )
		{
			// ratio in the graph area rectangle
			final float xRatio
				= (float)( ( xInScale[ii] - minXInScale )/( maxXInScale - minXInScale ) );
			final float yRatio
				= (float)( 1.0 - ( yInScale[ii] - minYInScale )/( maxYInScale - minYInScale ) );

			// set the location of points
			final float posX = gx + xRatio*gw;
			final float posY = gy + yRatio*gh;
			pointArray[ii].setValues( posX, posY );
		}

		return true;
	}



	/**
	 * 
	 */
	protected boolean calcLocationOfVXYData(
		final SGTuple2d[] startArray,
		final SGTuple2d[] endArray,
		final SGAxis axisX,
		final SGAxis axisY,
		final SGTuple2f[] startLocationArray,
		final SGTuple2f[] endLocationArray )
	{

		if( startArray==null || endArray==null || startLocationArray==null || endLocationArray==null )
		{
			throw new IllegalArgumentException("startArray==null || endArray==null || startLocationArray==null || endLocationArray==null");
		}

		if( startArray.length != endArray.length )
		{
			throw new IllegalArgumentException("startArray.length != endArray.length");
		}

		if( startLocationArray.length != endLocationArray.length )
		{
			throw new IllegalArgumentException("startLocationArray.length != endLocationArray.length");
		}

		final int num = startArray.length;

		final SGTuple2d rangeX = axisX.getRange();
		final SGTuple2d rangeY = axisY.getRange();
		final double minX = rangeX.x;
		final double maxX = rangeX.y;
		final double minY = rangeY.x;
		final double maxY = rangeY.y;
		final int typeX = axisX.getScaleType();
		final int typeY = axisY.getScaleType();



		// グラフ内での値に変換
		double minXInScale = 0.0;
		double maxXInScale = 0.0;
		double minYInScale = 0.0;
		double maxYInScale = 0.0;
		final double[] startXInScale = new double[num];
		final double[] startYInScale = new double[num];
		final double[] endXInScale = new double[num];
		final double[] endYInScale = new double[num];

		if( typeX == SGAxis.LINEAR_TYPE )
		{
			minXInScale = minX;
			maxXInScale = maxX;
			for( int ii=0; ii<num; ii++ )
			{
				startXInScale[ii] = startArray[ii].x;
				endXInScale[ii] = endArray[ii].x;
			}
		}
		else if( typeX == SGAxis.LOG_TYPE )
		{
			minXInScale = Math.log(minX);
			maxXInScale = Math.log(maxX);
			for( int ii=0; ii<num; ii++ )
			{
				startXInScale[ii] = Math.log(startArray[ii].x);
				endXInScale[ii] = Math.log(endArray[ii].x);
			}
		}

		if( typeY == SGAxis.LINEAR_TYPE )
		{
			minYInScale = minY;
			maxYInScale = maxY;
			for( int ii=0; ii<num; ii++ )
			{
				startYInScale[ii] = startArray[ii].y;
				endYInScale[ii] = endArray[ii].y;
			}
		}
		else if( typeY == SGAxis.LOG_TYPE )
		{
			minYInScale = Math.log(minY);
			maxYInScale = Math.log(maxY);
			for( int ii=0; ii<num; ii++ )
			{
				startYInScale[ii] = Math.log(startArray[ii].y);
				endYInScale[ii] = Math.log(endArray[ii].y);
			}
		}


		// グラフ領域内でのデータ点の比率を計算
		final float[] startXRatioArray = new float[num];
		final float[] startYRatioArray = new float[num];
		for( int ii=0; ii<num; ii++ )
		{
			startXRatioArray[ii] = (float)( (startXInScale[ii]-minXInScale)/(maxXInScale-minXInScale) );
			startYRatioArray[ii] = (float)( 1.0 - (startYInScale[ii]-minYInScale)/(maxYInScale-minYInScale) );
		}

		final float[] endXRatioArray = new float[num];
		final float[] endYRatioArray = new float[num];
		for( int ii=0; ii<num; ii++ )
		{
			endXRatioArray[ii] = (float)( (endXInScale[ii]-minXInScale)/(maxXInScale-minXInScale) );
			endYRatioArray[ii] = (float)( 1.0 - (endYInScale[ii]-minYInScale)/(maxYInScale-minYInScale) );
		}


		// グラフ全体に対する比率を計算
		final float gx = this.mGraphRectX;
		final float gy = this.mGraphRectY;
		final float gw = this.mGraphRectWidth;
		final float gh = this.mGraphRectHeight;
		for( int ii=0; ii<num; ii++ )
		{
			startLocationArray[ii].setValues(
				gx + startXRatioArray[ii]*gw,
				gy + startYRatioArray[ii]*gh
			);
		}

		for( int ii=0; ii<num; ii++ )
		{
			endLocationArray[ii].setValues(
				gx + endXRatioArray[ii]*gw,
				gy + endYRatioArray[ii]*gh
			);
		}


		return true;
	}



	/**
	 * 
	 */
	public int getSelectedDataNumber()
	{
		return this.getFocusedObjectsList().size();
	}



	/**
	 * 
	 */
	public boolean getFocusedObjectsList( ArrayList list )
	{
		ArrayList gsList = this.getVisibleElementGroupSetList();
		for( int ii=0; ii<gsList.size(); ii++ )
		{
			SGISelectable s = (SGISelectable)gsList.get(ii);
			if( s.isSelected() )
			{
				list.add(s);
			}
		}
		return true;
	}



	/**
	 * Returns a list of copies of the focused data objects.
	 * @return a list to which the cut data objects are added
	 */
	public ArrayList getFocusedDataList()
	{
		ArrayList fList = this.getFocusedObjectsList();
		ArrayList list = new ArrayList();
		for( int ii=0; ii<fList.size(); ii++ )
		{
			ElementGroupSetInGraph gs = (ElementGroupSetInGraph)fList.get(ii);
			SGData data = this.getData(gs);
			list.add(data);
		}

		return list;
	}



	/**
	 * Cut focused copiable objects.
	 * @return a list of cut objects
	 */
	public ArrayList cutFocusedObjects()
	{
		return new ArrayList();
	}



	/**
	 * Returns a list of the cut data objects.
	 * @return a list to which the cut data objects are added
	 */
	public ArrayList cutFocusedData()
	{
		ArrayList list = this.getFocusedDataList();
		this.hideSelectedData();
		return list;
	}



	/**
	 * 
	 */
	public boolean hideSelectedObject( SGISelectable s )
	{
		ElementGroupSetInGraph el = (ElementGroupSetInGraph)s;
		el.setVisible(false);
		return true;
	}



	/**
	 * 
	 * @param groupSet
	 * @return
	 */
	protected boolean hideGroupSet(  final SGElementGroupSet groupSet )
	{
		// set invisible
		groupSet.setVisible(false);

		return true;
	}



	/**
	 * 
	 */
	protected boolean moveGroupSetToFront( final SGElementGroupSet groupSet )
	{
		SGData data = null;
		for( int ii=0; ii<this.mGroupSetList.size(); ii++ )
		{
			if( groupSet.equals(this.mGroupSetList.get(ii)) )
			{
				mGroupSetList.remove(ii);
				data = (SGData)mDataList.remove(ii);
				break;
			}
		}

		if( data == null )
		{
			return false;
		}

		mGroupSetList.add(mGroupSetList.size(),groupSet);
		mDataList.add(mDataList.size(),data);

		return true;
	}


	/**
	 * 
	 */
	protected boolean moveGroupSetToBack( final SGElementGroupSet groupSet )
	{
		SGData data = null;
		for( int ii=0; ii<this.mGroupSetList.size(); ii++ )
		{
			if( groupSet.equals(this.mGroupSetList.get(ii)) )
			{
				mGroupSetList.remove(ii);
				data = (SGData)mDataList.remove(ii);
				break;
			}
		}

		if( data == null )
		{
			return false;
		}

		mGroupSetList.add(0,groupSet);
		mDataList.add(0,data);

		return true;
	}


	/**
	 * 
	 */
	protected boolean removeGroupSet( final SGElementGroupSet groupSet )
	{
		for( int ii=0; ii<this.mGroupSetList.size(); ii++ )
		{
			if( groupSet.equals(this.mGroupSetList.get(ii)) )
			{
				mGroupSetList.remove(ii);
				mDataList.remove(ii);
				return true;
			}
		}

		return false;
	}



	/**
	 * 
	 */
	protected boolean hideSelectedData()
	{

		ArrayList list = this.getFocusedObjectsList();

		if( list.size() == 0 )
		{
			return true;
		}

		for( int ii=0; ii<list.size(); ii++ )
		{
			final SGElementGroupSet groupSet = (SGElementGroupSet)list.get(ii);
			groupSet.setVisible(false);
		}

		this.clearFocusedObjects();

		notifyChange();

		this.setChanged(true);

		return true;
	}



	/**
	 * 
	 */
	public boolean isDataVisible( SGData data )
	{
		SGElementGroupSet groupSet = this.getElementGroupSet(data);
		return groupSet.isVisible();
	}


	/**
	 * 
	 */
	public boolean removeSelectedData()
	{

		ArrayList list = this.getFocusedObjectsList();
		if( list.size() == 0 )
		{
			return true;
		}

		for( int ii=0; ii<list.size(); ii++ )
		{
			final SGElementGroupSet groupSet
				= (SGElementGroupSet)list.get(ii);
			this.removeGroupSet( groupSet );
		}

		notifyChange();

		this.setChanged(true);

		return true;
	}


	/**
	 * Move the focused objects to front or back.
	 * @param toFront - flag whether to front or back
	 * @return true:succeeded, false:failed
	 */
	public boolean moveFocusedObjects( boolean toFront )
	{
		if( toFront )
		{
			return this.moveSelectedDataToFront();
		}
		else
		{
			return this.moveSelectedDataToBack();
		}
	}



	/**
	 * 
	 */
	public boolean moveSelectedDataToFront()
	{
		ArrayList list = this.getFocusedObjectsList();

		if( list.size() == 0 )
		{
			return true;
		}

		for( int ii=list.size()-1; ii>=0; ii-- )
		{
			final SGElementGroupSet groupSet = (SGElementGroupSet)list.get(ii);
			if( this.moveGroupSetToFront( groupSet ) == false )
			{
				return false;
			}
		}

		notifyChange();

		this.setChanged(true);

		return true;
	}


	/**
	 * 
	 */
	public boolean moveSelectedDataToBack()
	{
		ArrayList list = this.getFocusedObjectsList();

		if( list.size() == 0 )
		{
			return true;
		}

		for( int ii=list.size()-1; ii>=0; ii-- )
		{
			final SGElementGroupSet groupSet
				= (SGElementGroupSet)list.get(ii);
			if( this.moveGroupSetToBack( groupSet ) == false )
			{
				return false;
			}
		}
		
		notifyChange();

		this.setChanged(true);

		return true;
	}



	/**
	 * 
	 * @return
	 */
/*	protected boolean clearSelectedGroupSet()
	{

		for( int ii=0; ii<this.mFocusedObjectsList.size(); ii++ )
		{
			final SGElementGroupSet groupSet = (SGElementGroupSet)this.mFocusedObjectsList.get(ii);
			groupSet.setSelected( false );
		}
		this.mFocusedObjectsList.clear();

		return true;
	}
*/


	/**
	 * 
	 */
	protected ElementGroupSetInGraph getElementGroupSet( SGData data )
	{
		for( int ii=0; ii<this.mDataList.size(); ii++ )
		{
			SGData data_ = (SGData)this.mDataList.get(ii);
			if( data_.equals(data) )
			{
				ElementGroupSetInGraph groupSet
					= (ElementGroupSetInGraph)this.mGroupSetList.get(ii);
				return groupSet;
			}
		}

		return null;
	}



	/**
	 * 
	 */
	protected SGData getData( ElementGroupSetInGraph groupSet )
	{
		for( int ii=0; ii<this.mGroupSetList.size(); ii++ )
		{
			SGElementGroupSet groupSet_ = (SGElementGroupSet)this.mGroupSetList.get(ii);
			if( groupSet_.equals(groupSet) )
			{
				SGData data = (SGData)this.mDataList.get(ii);
				return data;
			}
		}
		return null;
	}



	/**
	 * 
	 * @return
	 */
	public ArrayList getPropertyDialogObserverList()
	{
		return this.getFocusedObjectsList();
	}



	/**
	 * 
	 * @return
	 */
	protected boolean drawAnchorsForFocusedObjects(
		final Point2D pos, final Graphics2D g2d )
	{
		SGUtilityForFigureElement.drawAnchorAsFocusedObject(pos,g2d);
		return true;
	}



	/**
	 * 
	 */
	public boolean onMouseClicked( final MouseEvent e )
	{

		// click the data
		ArrayList list = this.mGroupSetList;
		for( int ii=list.size()-1; ii>=0; ii-- )
		{
			final ElementGroupSetInGraph groupSet
				= (ElementGroupSetInGraph)list.get(ii);
			if( groupSet.isVisible() ==false )
			{
				continue;
			}

			if( groupSet.onMouseClicked(e) )
			{
				return true;
			}
		}

		// if no data are clicked, clear the list of clicked data.
//		this.clearFocusedObjects();

		return false;
	}



	/**
	 * 
	 * @param e
	 */
	public boolean onMousePressed( final MouseEvent e )
	{
		ArrayList list = this.mGroupSetList;
		for( int ii=list.size()-1; ii>=0; ii-- )
		{
			final ElementGroupSetInGraph groupSet
				= (ElementGroupSetInGraph)list.get(ii);
			if( groupSet.onMousePressed(e) )
			{
				return true;
			}
		}

		return false;
	}	

	

	/**
	 * 
	 * @param e
	 */
	public boolean onMouseDragged( final MouseEvent e )
	{
		if( this.getFocusedObjectsList().size()!=0 )
		{
			return true;
		}

		return false;
	}



	/**
	 * 
	 * @param e
	 */
	public boolean onMouseReleased( final MouseEvent e )
	{
		return true;
	}



	/**
	 * 
	 * @param e
	 */
	public boolean onDrawingElement( final int x, final int y )
	{
//		// グラフの領域外であれば終了
//		if( !this.isInsideGraphArea(x,y) )
//		{
//			return false;
//		}

/*
		// 描画要素に対してマウスが上にあるかどうか問い合わせる
		for( int ii=this.mGroupSetList.size()-1; ii>=0; ii-- )
		{
			final ElementGroupSetInGraph groupSet = (ElementGroupSetInGraph)mGroupSetList.get(ii);
			if( groupSet.onDrawingElement(x,y) )
			{
				this.mCursor = new Cursor( Cursor.HAND_CURSOR );
				return true;
			}
		}
*/

		return false;
	}


	/**
	 * 
	 * @return
	 */
	public boolean setTemporaryPropertiesOfFocusedObjects()
	{
		return true;
	}



	/**
	 * 
	 * @return
	 */
	public boolean setChangedFocusedObjects()
	{
		return true;
	}


	/**
	 * 
	 */
	protected boolean drawRectangle(
		final double xMin, final double xMax, final double yMin, double yMax, final Graphics2D g2d )
	{

		if( g2d == null )
		{
			return false;
		}

		final Line2D lineUpper = new Line2D.Double( xMin, yMin, xMax, yMin );
		final Line2D lineLower = new Line2D.Double( xMin, yMax, xMax, yMax );
		final Line2D lineLeft = new Line2D.Double( xMin, yMin, xMin, yMax );
		final Line2D lineRight = new Line2D.Double( xMax, yMin, xMax, yMax );

		g2d.draw(lineUpper);
		g2d.draw(lineLower);
		g2d.draw(lineLeft);
		g2d.draw(lineRight);

		return true;
	}



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

	
	/**
	 * 
	 */
	public Element createElement( final Document document )
	{
/*		Element el = this.createThisElement( document );
		if( el==null )
		{
			return null;
		}

		return el;
*/
		return null;
	}

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

	
	
	/**
	 * 
	 */
	public boolean readProperty( final Element element )
	{
		return true;
	}
	
	
	/**
	 * 
	 * @param document
	 * @return
	 */
	public boolean createElementOfData( final Document document, final ArrayList list )
	{
		ArrayList groupSetList = this.getVisibleElementGroupSetList();
		for( int ii=0; ii<groupSetList.size(); ii++ )
		{
			ElementGroupSetInGraph groupSet = (ElementGroupSetInGraph)groupSetList.get(ii);

			Element el = groupSet.createElement( document );
			if( el==null )
			{
				return false;
			}
			el.setAttribute( KEY_DATA_TYPE, groupSet.getDataClassName() );

			list.add(el);
		}
		return true;
	}

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

		for( int ii=0; ii<this.mDataList.size(); ii++ )
		{
			writer.write( TAG_NAME_DATA + "\n" );

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

			if( data instanceof SGSXYData )
			{
				className = SGDataTypeConstants.SXY_DATA;
			}
			else if( data instanceof SGVXYData )
			{
				className = SGDataTypeConstants.VXY_DATA;
			}
			else if( data instanceof SGSXYMultipleData )
			{
				if( data instanceof SGSXYSamplingData )
				{
					className = SGDataTypeConstants.SXY_SAMPLING_DATA;
				}
				else
				{
					className = SGDataTypeConstants.SXY_MULTIPLE_DATA;
				}
			}
			else
			{
				return false;
			}

			SGUtilityText.writePropertyLine( writer, PF_CLASS_NAME, className );


			// データに対応したSGElementGroupSetオブジェクトを取得
			ElementGroupSetInGraph groupSet = this.getGraphData(data);
			groupSet.writePropertyOfData(writer);

		}


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

		return true;		

	}
*/


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



	/**
	 * 
	 */
	public boolean getProperties( final SGProperties p )
	{
		if( ( p instanceof GraphProperties ) == false )
		{
			return false;
		}

		GraphProperties gp = (GraphProperties)p;
		gp.visibleElementGroupList = this.getVisibleElementGroupSetList();

		return true;
	}


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

		GraphProperties gp = (GraphProperties)p;


		boolean flag;
		flag = this.setVisibleElementGroupList( gp.visibleElementGroupList );
		if( !flag )
		{
			return false;
		}

		return true;

	}



	/**
	 * 
	 */
	protected ArrayList getVisibleElementGroupSetList()
	{
		ArrayList list = new ArrayList();

		for( int ii=0; ii<this.mGroupSetList.size(); ii++ )
		{
			SGElementGroupSet groupSet
				= (SGElementGroupSet)this.mGroupSetList.get(ii);
			if( groupSet.isVisible() )
			{
				list.add(groupSet);
			}
		}

		return list;
	}



	/**
	 * Returns a list of child nodes.
	 * @return a list of chid nodes
	 */
	public ArrayList getChildNodes()
	{
		return this.getVisibleElementGroupSetList();
	}




	/**
	 * 
	 */
	protected boolean setVisibleElementGroupList( final ArrayList list )
	{

		ArrayList visibleList = new ArrayList( list );
		ArrayList invisibleList = new ArrayList();

		ArrayList visibleDataList = new ArrayList();
		ArrayList invisibleDataList = new ArrayList();

		for( int ii=0; ii<this.mGroupSetList.size(); ii++ )
		{
			ElementGroupSetInGraph groupSet = (ElementGroupSetInGraph)this.mGroupSetList.get(ii);
			final boolean b = list.contains(groupSet);
			groupSet.setVisible(b);
			if(!b)
			{
				invisibleList.add( groupSet );
				invisibleDataList.add( this.getData( groupSet ) );
			}
		}


		for( int ii=0; ii<visibleList.size(); ii++ )
		{
			ElementGroupSetInGraph groupSet = (ElementGroupSetInGraph)visibleList.get(ii);
			SGData data = this.getData(groupSet);
			visibleDataList.add(data);
		}


		this.mGroupSetList.clear();
		this.mDataList.clear();
		for( int ii=0; ii<visibleList.size(); ii++ )
		{
			this.mGroupSetList.add( visibleList.get(ii) );
			this.mDataList.add( visibleDataList.get(ii) );
		}
		for( int ii=0; ii<invisibleList.size(); ii++ )
		{
			this.mGroupSetList.add( invisibleList.get(ii) );
			this.mDataList.add( invisibleDataList.get(ii) );
		}


		return true;
	}



	/**
	 * 
	 * @return
	 */
	public boolean addPropertiesHistory( SGProperties p )
	{

		if( ( p instanceof GraphProperties ) == false )
		{
			return false;
		}

		boolean flag = super.addPropertiesHistory(p);		

		return flag;
	}



	/**
	 * 
	 */
	public boolean undo()
	{
		boolean flag = super.undo();
		if( !flag )
		{
			return false;
		}

		this.clearFocusedObjects();
		this.setAllDrawingElementsLocation();
		this.notifyChange();

		return true;
	}


	/**
	 * 
	 */
	public boolean redo()
	{
		boolean flag = super.redo();
		if( !flag )
		{
			return false;
		}

		this.clearFocusedObjects();
		this.setAllDrawingElementsLocation();
		this.notifyChange();

		return true;
	}



	/**
	 * 
	 */
	public boolean updateHistory()
	{
		return this.updateHistory_( this.getVisibleElementGroupSetList() );
	}


	/**
	 * 
	 */
	public boolean isChanged()
	{
		if( super.isChanged() )
		{
			return true;
		}
		ArrayList list = this.getVisibleElementGroupSetList();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGIUndoable el = (SGIUndoable)list.get(ii);
			if( el.isChanged() )
			{
				return true;
			}
		}
		return false;
	}





	/**
	 *
	 */
	protected abstract class ElementGroupSetInGraph
		extends SGElementGroupSetInFigureElement
		implements ActionListener,
			SGIPropertyDialogObserver, SGISelectable, SGINode
	{


		/**
		 * 
		 */
		protected boolean mClipFlag = true;


		/**
		 * 
		 * @param b
		 */
		protected void setClipFlag( final boolean b )
		{
			this.mClipFlag = b;
		}

		
		/**
		 * 
		 * @return
		 */
		protected boolean getClipFlag()
		{
			return this.mClipFlag;
		}


		/**
		 * Flag whether this object is focused.
		 */
		protected boolean mSelectedFlag = false;


		/**
		 * Get the flag as a focused object.
		 * @return whether this object is focused.
		 */
		public boolean isSelected()
		{
			return this.mSelectedFlag;
		}


		/**
		 * Set the flag as a focused object.
		 * @param b focused
		 */
		public void setSelected( final boolean b )
		{
			this.mSelectedFlag = b;
			
			ArrayList list = new ArrayList( this.mDrawingElementGroupList );
			for( int ii=0; ii<list.size(); ii++ )
			{
				IElementGroupInGraph group = (IElementGroupInGraph)list.get(ii);
				group.setFocused(b);
			}
		}



		/**
		 * 
		 */
		protected SGProperties mTemporaryProperties = null;


		/**
		 * ポップアップメニュー
		 */
		protected JPopupMenu mPopupMenu = new JPopupMenu();


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



		/**
		 * 
		 */
		public ArrayList getVisibleFlagList()
		{
			final ArrayList list = new ArrayList();
			final ArrayList groupList = new ArrayList( this.mDrawingElementGroupList );
			for( int ii=0; ii<groupList.size(); ii++ )
			{
				final SGElementGroup group = (SGElementGroup)groupList.get(ii);
				final boolean flag = group.isVisible();
				list.add( Boolean.valueOf(flag) );
			}

			return list;
		}



		/**
		 * 
		 */
		public void actionPerformed( final ActionEvent e )
		{
			final Object source = e.getSource();
			final String command = e.getActionCommand();

			if( command.equals( SGGraphElement.MENUCMD_PROPERTY ) )
			{
				setPropertiesOfSelectedObjects();
			}
			else if( command.equals( MENUCMD_MOVE_TO_FRONT )
				| command.equals( MENUCMD_MOVE_TO_BACK )
				| command.equals( MENUCMD_CUT )
				| command.equals( MENUCMD_COPY )
				| command.equals( MENUCMD_PASTE )
				| command.equals( MENUCMD_DELETE )
			)
			{
				notifyToListener( command );
			}

		}


		/**
		 * 
		 */
		protected abstract boolean createDrawingElements();




		/**
		 * 
		 * @param e
		 * @param groupSet
		 * @return
		 */
		protected boolean onMouseClicked( final MouseEvent e )
		{

			final int x = e.getX();
			final int y = e.getY();
			final int cnt = e.getClickCount();

			// clicked on the line elements
			if( this.contains(x,y) )
			{
				//
				SGGraphElement.this.updateFocusedObjectsList( this, e );

				if( SwingUtilities.isLeftMouseButton(e) & cnt==2 )
				{
					// show the property dialog
					SGGraphElement.this.setPropertiesOfSelectedObjects();
				}
				else if( SwingUtilities.isRightMouseButton(e) & cnt==1 )
				{
					this.mPopupMenu.show( SGGraphElement.this, x, y );
				}

				return true;
			}

			return false;
		}



		/**
		 * 
		 * @param e
		 * @param groupSet
		 * @return
		 */
		protected boolean onMousePressed( final MouseEvent e )
		{
			return this.contains( e.getX(), e.getY() );
		}



		/**
		 * 
		 * @param dg
		 * @return
		 */
		public boolean commit()
		{

			SGProperties pTemp = this.mTemporaryProperties;
			SGProperties pPresent = this.getWholeProperties();

			if( pTemp.equals(pPresent) == false )
			{
				this.mChangedFlag = true;
			}

			this.mTemporaryProperties = null;

			//
			if( setAllDrawingElementsLocation() == false )
			{
				return false;
			}

			repaint();
			notifyChange();

			return true;
		}

		

		/**
		 * 
		 */
		public boolean cancel()
		{
			if( this.setWholeProperties( this.mTemporaryProperties ) == false )
			{
				return false;
			}

			this.mTemporaryProperties = null;

			//
			if( setAllDrawingElementsLocation() == false )
			{
				return false;
			}
			repaint();
			notifyChange();

			return true;
		}


		/**
		 * 
		 * @param dg
		 * @return
		 */
		public boolean preview()
		{

			//
			if( setAllDrawingElementsLocation() == false )
			{
				return false;
			}
			repaint();
			notifyChange();

			return true;
		}


		/**
		 * Returns a list of child nodes.
		 * @return a list of chid nodes
		 */
		public ArrayList getChildNodes()
		{
			return new ArrayList();
		}




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

			return ep;
		}


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

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

			ElementGroupSetInGraphProperties ep = (ElementGroupSetInGraphProperties)p;

			ep.xAxis = mAxisElement.getConfigurationInCube( this.getXAxis() );
			ep.yAxis = mAxisElement.getConfigurationInCube( this.getYAxis() );
			ep.zAxis = mAxisElement.getConfigurationInCube( this.getZAxis() );

			return true;
		}



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

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

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

			ElementGroupSetInGraphProperties ep = (ElementGroupSetInGraphProperties)p;

			SGIAxisElement aElement = SGGraphElement.this.mAxisElement;

			this.setXAxis( aElement.getAxisInCube( ep.xAxis ) );
			this.setYAxis( aElement.getAxisInCube( ep.yAxis ) );
			this.setZAxis( aElement.getAxisInCube( ep.zAxis ) );

			return true;
		}


		
		/**
		 * 
		 * @return
		 */
		public abstract String getDataClassName();


		
		public Element createElement( final Document document )
		{
			Element el = super.createElement( document );
			el.setAttribute( KEY_DATA_TYPE, this.getDataClassName() );
			return el;
		}
		
		


		/**
		 * 
		 * @return
		 */
		public String getTagName()
		{
			return SGGraphElement.TAG_NAME_DATA;
		}

		

		/**
		 * 
		 * @return
		 */
		public boolean setDrawingElementProperties( final ArrayList dElementList )
		{

			final ArrayList groupList = this.mDrawingElementGroupList;
			if( dElementList.size() != groupList.size() )
			{
				throw new IllegalArgumentException("dElementList.size() != groupList.size()");
			}

			// set the properties of drawing elements
			for( int ii=0; ii<groupList.size(); ii++ )
			{
				SGElementGroup group = (SGElementGroup)groupList.get(ii);
				SGDrawingElement dElement = (SGDrawingElement)dElementList.get(ii);
				group.setProperty( dElement );
			}

			return true;
		}



		/**
		 * アンドゥを行う
		 */
		public boolean undo()
		{
			if( super.undo() == false ) return false;

			setAllDrawingElementsLocation();

			return true;
		}


		/**
		 * リドゥを行う
		 */
		public boolean redo()
		{
			if( super.redo() == false ) return false;

			setAllDrawingElementsLocation();

			return true;
		}



		/**
		 * 
		 *
		 */
		public void notifyToRoot()
		{
			SGGraphElement.this.notifyToRoot();
		}




		/**
		 * 
		 */
		class ElementGroupSetInGraphProperties	extends ElementGroupSetPropertiesInFigureElement
		{
			int xAxis;
			int yAxis;
			int zAxis;

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

				ElementGroupSetInGraphProperties p
					= (ElementGroupSetInGraphProperties)obj;

				if( super.equals(obj) == false ) return false;
				if( p.xAxis!=this.xAxis ) return false;
				if( p.yAxis!=this.yAxis ) return false;
				if( p.zAxis!=this.zAxis ) return false;

				return true;
			}


		}


	}




	/**
	 * 
	 */
	abstract class ElementGroupSetForMultipleData extends ElementGroupSetInGraph
	{

		/**
		 * 
		 */
		protected ArrayList mElementGroupSetList = new ArrayList();


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


		/**
		 * 
		 */
		public ArrayList getVisibleFlagList()
		{
			if( this.mElementGroupSetList.size()==0 )
			{
				return new ArrayList();
			}
			ElementGroupSetInGraph groupSet
				= (ElementGroupSetInGraph)this.mElementGroupSetList.get(0);
			ArrayList list = groupSet.getVisibleFlagList();
			return list;
		}


		/**
		 * 
		 */
		public void setSelected( final boolean b )
		{
			this.mSelectedFlag = b;
			ArrayList list = this.mElementGroupSetList;
			for( int ii=list.size()-1; ii>=0; ii-- )
			{
				SGISelectable groupSet = (SGISelectable)list.get(ii);
				groupSet.setSelected(b);
			}
		}


		/**
		 * 
		 */
		public boolean contains( final int x, final int y )
		{
			ArrayList list = this.mElementGroupSetList;
			for( int ii=list.size()-1; ii>=0; ii-- )
			{
				ElementGroupSetInGraph groupSet
					= (ElementGroupSetInGraph)list.get(ii);
				if( groupSet.contains(x,y) )
				{
					return true;
				}
			}
			return false;
		}


		/**
		 * 
		 * @param x
		 * @param y
		 * @return
		 */
		public SGElementGroup getElementGroupAt( final int x, final int y )
		{
			ArrayList list = this.mElementGroupSetList;
			for( int ii=list.size()-1; ii>=0; ii-- )
			{
				ElementGroupSetInGraph groupSet
					= (ElementGroupSetInGraph)list.get(ii);
				SGElementGroup group = groupSet.getElementGroupAt(x,y);
				if( group!=null )
				{
					return group;
				}

			}

			return null;
		}

		/**
		 * 
		 */
		public boolean setMagnification( final float mag )
		{
			super.setMagnification(mag);
			for( int ii=0; ii<this.mElementGroupSetList.size(); ii++ )
			{
				SGElementGroupSet groupSet
					= (SGElementGroupSet)this.mElementGroupSetList.get(ii);
				groupSet.setMagnification(mag);
			}

			return true;
		}


		/**
		 * 
		 */
		public boolean zoom( final float ratio )
		{
			super.zoom(ratio);

			for( int ii=0; ii<this.mElementGroupSetList.size(); ii++ )
			{
				SGElementGroupSet groupSet
					= (SGElementGroupSet)this.mElementGroupSetList.get(ii);
				groupSet.zoom(ratio);
			}

			return true;
		}

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

			for( int ii=0; ii<this.mElementGroupSetList.size(); ii++ )
			{
				final ElementGroupSetInGraph groupSet = (ElementGroupSetInGraph)this.mElementGroupSetList.get(ii);
				groupSet.addDrawingElementGroup(type);
			}

			return true;
		}


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

			for( int ii=0; ii<this.mElementGroupSetList.size(); ii++ )
			{
				final ElementGroupSetInGraph groupSet = (ElementGroupSetInGraph)this.mElementGroupSetList.get(ii);
				groupSet.addDrawingElementGroup(element);
			}

			return true;
		}



		/**
		 * 
		 */
		public boolean onDrawingElement( final int x, final int y )
		{

			ArrayList list = this.mElementGroupSetList;
			for( int ii=list.size()-1; ii>=0; ii-- )
			{
				ElementGroupSetInGraph groupSet
					= (ElementGroupSetInGraph)list.get(ii);
				boolean flag = groupSet.onDrawingElement(x,y);
				if( flag )
				{
					return true;
				}
			}

			return false;
		}


		/**
		 * 
		 */
		public void paintGraphics2D( final Graphics2D g2d )
		{
			ArrayList list = this.mElementGroupSetList;
			for( int ii=list.size()-1; ii>=0; ii-- )
			{
				ElementGroupSetInGraph groupSet
					= (ElementGroupSetInGraph)list.get(ii);
				groupSet.paintGraphics2D(g2d);
			}
		}


		/**
		 * 
		 */
		public void setClipFlag( final boolean b )
		{
			super.setClipFlag(b);
			ArrayList list = this.mElementGroupSetList;
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupSetInGraph grouptSet = (ElementGroupSetInGraph)list.get(ii);
				grouptSet.setClipFlag(b);
			}
		}


		/**
		 * 
		 */
		public ArrayList getDrawingElementList()
		{
			final ArrayList list = new ArrayList();

			if( this.mElementGroupSetList.size() == 0 )
			{
				return list;
			}

			// 最初のグループからだけ取得する
			final SGElementGroupSet groupSet = (SGElementGroupSet)this.mElementGroupSetList.get(0);
			for( int ii=0; ii<groupSet.mDrawingElementGroupList.size(); ii++ )
			{
				final SGElementGroup group = (SGElementGroup)groupSet.mDrawingElementGroupList.get(ii);
				final SGDrawingElement dElement = group.getDrawingElement();
				list.add( dElement );
			}

			return list;
		}



		/**
		 * 
		 * @return
		 */
		public boolean setDrawingElementProperties( final ArrayList dElementList )
		{

			final ArrayList groupSetList = this.mElementGroupSetList;

			// set the properties of drawing elements
			for( int ii=0; ii<groupSetList.size(); ii++ )
			{
				ElementGroupSetInGraph groupSet = (ElementGroupSetInGraph)groupSetList.get(ii);
				groupSet.setDrawingElementProperties( dElementList );
			}

/*
			final ArrayList groupList = this.mDrawingElementGroupList;
			if( dElementList.size() != groupList.size() )
			{
				throw new IllegalArgumentException("dElementList.size() != groupList.size()");
			}

			// set the properties of drawing elements
			for( int ii=0; ii<groupList.size(); ii++ )
			{
				SGElementGroup group = (SGElementGroup)groupList.get(ii);
				SGDrawingElement dElement = (SGDrawingElement)dElementList.get(ii);
				group.setProperty( dElement );
			}
*/

			return true;
		}


	}


	/**
	 * 
	 */
	public static interface IElementGroupInGraph
	{
		public void setFocused( final boolean b );
		
		public boolean isFocused();
	}


	/**
	 * 
	 */
	public static class GraphProperties extends SGProperties
	{

		ArrayList visibleElementGroupList = new ArrayList();


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


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

			GraphProperties p = (GraphProperties)obj;

			if( p.visibleElementGroupList.equals(this.visibleElementGroupList) == false )
			{
				return false;
			}
			return true;
		}


	}



}

