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

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;

import javax.swing.JLabel;
import javax.swing.JPopupMenu;

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.SGIAxisElement;
import jp.riken.brain.ni.samuraigraph.base.SGIConstants;
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.base.SGUtility;
import jp.riken.brain.ni.samuraigraph.base.SGUtilityText;
import jp.riken.brain.ni.samuraigraph.data.SGISXYTypeData;
import jp.riken.brain.ni.samuraigraph.data.SGISXYTypeMultipleData;
import jp.riken.brain.ni.samuraigraph.data.SGSXYSamplingData;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementBar;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementErrorBar;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementLine;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementString;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementSymbol;

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



/**
 * xy型データのグラフのクラス
 */
public class SGSXYGraphElement extends SGGraphElement
{


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



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

		final SGPropertyDialogSXYData dg
		 = new SGPropertyDialogSXYData( mDialogOwner, true );

		mDialog = dg;

		return true;
	}



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


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


		if( super.addData(data,name) == false )
		{
			return false;
		}


		// create an ElementGroupSetInGraph object
		ElementGroupSetInGraph groupSet = this.createGroupSet(data,name);
		if( groupSet==null )
		{
			return false;
		}


		// initialize the properties
		groupSet.initPropertiesHistory();


		// create property dialog
		if( this.mDialog==null )
		{
			this.createDataDialog();
		}


		// set the change flag and notify to the root
		this.setChanged(true);
		this.notifyToRoot();

		return true;
	}



	/**
	 * Add a data object with a set of properties.
	 * @param data - added data.
	 * @param name - the "right" name set to be data.
	 * @param p - properties set to be data.
	 * @return true:succeeded, false:failed
	 */
	public boolean addData( final SGData data, final String name, final SGProperties p )
	{

		// データのチェック
		if( !(data instanceof SGISXYTypeData) & !(data instanceof SGISXYTypeMultipleData) )
		{
			return false;
		}


		if( super.addData(data,name) == false )
		{
			return false;
		}


		// create an ElementGroupSetInGraph object
		ElementGroupSetInGraph groupSet = this.createGroupSet(data,name);
		if( groupSet==null )
		{
			return false;
		}


		// set properties
		if( groupSet.setWholeProperties(p) == false )
		{
			return false;
		}


		// set visible because cut data objects are set invisible
		groupSet.setVisible(true);


		// Set the given name to data.
		// The name given in p would be redundant.
		groupSet.setName(name);


		// initialize the properties
		groupSet.initPropertiesHistory();

		// create property dialog
		if( this.mDialog==null )
		{
			this.createDataDialog();
		}


		// set the change flag and notify to the root
		this.setChanged(true);
		this.notifyToRoot();

		return true;
	}



	private ElementGroupSetInGraph createGroupSet( SGData data, String name )
	{
		// get axes list
		final SGAxis bAxis = this.mAxisElement.getAxisInPlane( SGAxisElement.AXIS_HORIZONTAL_1 );
		final SGAxis tAxis = this.mAxisElement.getAxisInPlane( SGAxisElement.AXIS_HORIZONTAL_2 );
		final SGAxis lAxis = this.mAxisElement.getAxisInPlane( SGAxisElement.AXIS_PERPENDICULAR_1 );
		final SGAxis rAxis = this.mAxisElement.getAxisInPlane( SGAxisElement.AXIS_PERPENDICULAR_2 );
		SGAxis axisX = null;
		SGAxis axisY = null;
		if( SGDefaultValues.SCALE_REFERENCE.equals( SGIAxisElement.LEFT_BOTTOM ) )
		{
			axisX = bAxis;
			axisY = lAxis;
		}
		else if( SGDefaultValues.SCALE_REFERENCE.equals( SGIAxisElement.LEFT_TOP ) )
		{
			axisX = tAxis;
			axisY = lAxis;
		}
		else if( SGDefaultValues.SCALE_REFERENCE.equals( SGIAxisElement.RIGHT_BOTTOM ) )
		{
			axisX = bAxis;
			axisY = rAxis;
		}
		else if( SGDefaultValues.SCALE_REFERENCE.equals( SGIAxisElement.RIGHT_TOP ) )
		{
			axisX = tAxis;
			axisY = rAxis;
		}
		else
		{
			return null;
		}


		//
		ElementGroupSetInGraph groupSet = null;
		if( data instanceof SGISXYTypeData )
		{
			groupSet = this.createSingleGroupSet( (SGISXYTypeData)data, axisX, axisY, name );
		}
		else if( data instanceof SGISXYTypeMultipleData )
		{
			groupSet = this.createMultipleGroupSet( (SGISXYTypeMultipleData)data, axisX, axisY, name );
		}
		else
		{
			return null;
		}

		//
		this.mGroupSetList.add( groupSet );

		return groupSet;		
	}



	/**
	 * 
	 */
	private ElementGroupSetForMultipleData createMultipleGroupSet(
		final SGISXYTypeMultipleData data, final SGAxis axisX, final SGAxis axisY,
		final String name )
	{
	
		final ElementGroupSetForMultipleDataInSXYGraph groupSet
			= new ElementGroupSetForMultipleDataInSXYGraph();
	
	
		// set the name
		groupSet.setName(name);
	
	
		// set axes
		groupSet.setXAxis(axisX);
		groupSet.setYAxis(axisY);
	

		//
		SGISXYTypeData[] dataArray = data.getSXYDataArray();
		for( int ii=0; ii<dataArray.length; ii++ )
		{
			ElementGroupSetInSXYGraph gs
				= this.createGroupSetSXYInstance( dataArray[ii], axisX, axisY );

			gs.setName(name);

			//
			gs.initPropertiesHistory();

			//
			groupSet.mElementGroupSetList.add(gs);
		}	

		return groupSet;		
	}




	/**
	 * 
	 */
	private ElementGroupSetInSXYGraph createSingleGroupSet(
		final SGISXYTypeData data, final SGAxis axisX, final SGAxis axisY,
		final String name )
	{
		ElementGroupSetInSXYGraph groupSet
			= this.createGroupSetSXYInstance( data, axisX, axisY );

		groupSet.setName(name);

		return groupSet;		
	}




	/**
	 * 
	 * @param data
	 * @param axisX
	 * @param axisY
	 * @return
	 */
	private ElementGroupSetInSXYGraph createGroupSetSXYInstance(
		final SGISXYTypeData data, final SGAxis axisX, final SGAxis axisY )
	{

		final ElementGroupSetInSXYGraph groupSet
			= new ElementGroupSetInSXYGraph();


		// set axes
		groupSet.setXAxis(axisX);
		groupSet.setYAxis(axisY);


		// create instances of the points
		final int num = data.getPointsNumber();
		SGTuple2f[] pointsArray = new SGTuple2f[num];
		for( int ii=0; ii<num; ii++ )
		{
			pointsArray[ii] = new SGTuple2f();
		}
		groupSet.mPointsArray = pointsArray;


		// add drawing element groups of lines, symbols and bars
		if( groupSet.addDrawingElementGroup( SGElementGroup.RECTANGLE_GROUP ) == false )
		{
			return null;
		}


		//
		// set bar width from the interval of x values and graph width
		//

		final double[] xArray = data.getXValueArray();
		double minDiff = Double.MAX_VALUE;
		for( int ii=0; ii<xArray.length-1; ii++ )
		{
			final double diff = Math.abs( xArray[ii+1] - xArray[ii] );
			if( diff < minDiff )
			{
				minDiff = diff;
			}
		}

		final double xMin = axisX.getMinValue();
		final double xMax = axisX.getMaxValue();
		final double ratio = minDiff/( xMax - xMin );
		final float minWidth = BAR_WIDTH_MIN;
		final float maxWidth = BAR_WIDTH_MAX;
		float barWidth = this.mGraphRectWidth*(float)ratio;
		if( barWidth < minWidth )
		{
			barWidth = minWidth;
		}
		else if( barWidth > maxWidth )
		{
			barWidth = maxWidth;
		}
		groupSet.getBarGroup().setRectangleWidth( barWidth );


		// create error bar instance
		if( data.isErrorValueHolding() )
		{
			ElementGroupErrorBar errorBar = groupSet.createErrorBars( data );
			if( errorBar.setPropertiesOfDrawingElements() == false )
			{
				return null;
			}
		}

		if( groupSet.addDrawingElementGroup( SGElementGroup.POLYLINE_GROUP ) == false )
		{
			return null;
		}

		if( groupSet.addDrawingElementGroup( SGElementGroup.SYMBOL_GROUP ) == false )
		{
			return null;
		}

		// create tick label instance
		if( data.isStringArrayHolding() )
		{
			ElementGroupTickLabels tickLabels = groupSet.createTickLabels( data );
			if( tickLabels.setPropertiesOfDrawingElements() == false )
			{
				return null;
			}
		}


		// set the location of the drawing elements of data
		if( groupSet.setDrawingElementsLocation( (SGData)data ) == false )
		{
			return null;
		}


		// set magnification
		groupSet.setMagnification( this.getMagnification() );

		return groupSet;
	}



	/**
	 * 
	 * @return
	 */
	private JPopupMenu createGroupSetPopupMenu( ElementGroupSetInGraph groupSet )
	{
		JPopupMenu p = new JPopupMenu();
		p.setBounds( 0, 0, 100, 100 );

		p.add( new JLabel( "  -- Data --" ) );
		p.addSeparator();

		SGUtility.addItem( p, groupSet, MENUCMD_MOVE_TO_FRONT );
		SGUtility.addItem( p, groupSet, MENUCMD_MOVE_TO_BACK );

		p.addSeparator();

		SGUtility.addItem( p, groupSet, MENUCMD_CUT );
		SGUtility.addItem( p, groupSet, MENUCMD_COPY );
		SGUtility.addItem( p, groupSet, MENUCMD_PASTE );

		p.addSeparator();

		SGUtility.addItem( p, groupSet, MENUCMD_DELETE );

		p.addSeparator();

		SGUtility.addItem( p, groupSet, MENUCMD_PROPERTY );

		return p;
	}



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

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


		// 描画要素のプロパティの同期を取る
		ArrayList dataList = new ArrayList( this.mDataList );
		ArrayList gsList = new ArrayList( this.mGroupSetList );
		for( int ii=dataList.size()-1; ii>=0; ii-- )
		{
			SGData data = (SGData)dataList.get(ii);

			ElementGroupSetInGraph groupSet
				= (ElementGroupSetInGraph)gsList.get(ii);

			boolean diffFlag = false;

			// name of data
			String nameNew = element.getDataName(data);
			String nameOld = groupSet.getName();
			if( nameNew.equals( nameOld ) == false )
			{
				groupSet.setChanged(true);
			}
			groupSet.setName( nameNew );


			// axes
			SGAxis xAxis = element.getXAxis(data);
			if( xAxis!=null & groupSet.getXAxis()!=null )
			{
				if( xAxis.equals(groupSet.getXAxis()) == false )
				{
					groupSet.setChanged(true);
				}
			}
			groupSet.setXAxis(xAxis);

			SGAxis yAxis = element.getYAxis(data);
			if( yAxis!=null & groupSet.getYAxis()!=null )
			{
				if( yAxis.equals(groupSet.getYAxis()) == false )
				{
					groupSet.setChanged(true);
				}
			}
			groupSet.setYAxis(yAxis);

			SGAxis zAxis = element.getZAxis(data);
			if( zAxis!=null & groupSet.mZAxis!=null )
			{
				if( zAxis.equals(groupSet.mZAxis) == false )
				{
					groupSet.setChanged(true);
				}
				groupSet.setZAxis(zAxis);
			}


			// visible
			boolean visibleFlag = element.isDataVisible(data);
			if( visibleFlag != groupSet.isVisible() )
			{
				this.setChanged(true);
			}
			groupSet.setVisible( visibleFlag );


			// drawing element of data
			ArrayList sList = element.getDrawingElementList(data);
			final boolean b = ((IElementGroupSetInSXYGraph)groupSet).synchronizeDrawingElement(sList);
			if(b)
			{
				diffFlag = true;
			}

			if( diffFlag )
			{
				groupSet.setChanged(true);
			}

		}


		this.setAllDrawingElementsLocation();
		updateImage();

		return flag;
	}



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

		ArrayList list = this.mGroupSetList;

		// データ付属文字列の描画
		for( int ii=0; ii<list.size(); ii++ )
		{
			final SGElementGroupSet groupSet
				= (SGElementGroupSet)list.get(ii);
			if( groupSet.isVisible() )
			{
				IElementGroupSetInSXYGraph iGroupSet
					= (IElementGroupSetInSXYGraph)groupSet;
				iGroupSet.paintDataString(g2d);
			}
		}


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


		// グラフの描画
		for( int ii=0; ii<list.size(); ii++ )
		{
			final ElementGroupSetInGraph groupSet
				= (ElementGroupSetInGraph)list.get(ii);
			if( groupSet.isVisible() )
			{
				groupSet.setClipFlag( clip );
				groupSet.paintGraphics2D(g2d);
			}
		}

		if( clip )
		{
			g2d.setClip( this.getViewBounds() );
		}

	}






	/**
	 * 
	 */
	private ElementGroupLine getGroupLine( final ElementGroupSetInSXYGraph groupSet )
	{

		final ArrayList groupList = groupSet.mDrawingElementGroupList;
		for( int ii=0; ii<groupList.size(); ii++ )
		{
			final SGElementGroup group = (SGElementGroup)groupList.get(ii);
			if( group instanceof ElementGroupLine )
			{
				return (ElementGroupLine)group;
			}
		}

		return null;
	}


	/**
	 * 
	 */
	private ElementGroupBar getGroupBar( final ElementGroupSetInSXYGraph groupSet )
	{

		final ArrayList groupList = groupSet.mDrawingElementGroupList;
		for( int ii=0; ii<groupList.size(); ii++ )
		{
			final SGElementGroup group = (SGElementGroup)groupList.get(ii);
			if( group instanceof ElementGroupBar )
			{
				return (ElementGroupBar)group;
			}
		}

		return null;
	}


	/**
	 * 
	 */
	private ElementGroupSymbol getGroupSymbol( final ElementGroupSetInSXYGraph groupSet )
	{

		final ArrayList groupList = groupSet.mDrawingElementGroupList;
		for( int ii=0; ii<groupList.size(); ii++ )
		{
			final SGElementGroup group = (SGElementGroup)groupList.get(ii);
			if( group instanceof ElementGroupSymbol )
			{
				return (ElementGroupSymbol)group;
			}
		}

		return null;
	}



	/**
	 * 
	 */
	public boolean getMarginAroundGraphRect(
		SGTuple2f topAndBottom, SGTuple2f leftAndRight )
	{
//System.out.println("<< SGSXYGraphElement : getMarginAroundGraphAreaRect >>");

		if( super.getMarginAroundGraphRect( topAndBottom, leftAndRight ) == false )
		{
			return false;
		}


		// 各文字列群ごとに、全ての文字列を外包する矩形を取得する
		final ArrayList rectList = new ArrayList();
		for( int ii=0; ii<this.mGroupSetList.size(); ii++ )
		{
//System.out.println("ii="+ii);
			final ElementGroupSetInGraph groupSet
				= (ElementGroupSetInGraph)this.mGroupSetList.get(ii);
			SGData data = getData(groupSet);
			Rectangle2D rectAll = ((IElementGroupSetInSXYGraph)groupSet).getTickLabelsBoundingBox(data);
			if( rectAll==null )
			{
				return false;
			}

			if( rectAll.getWidth() < Double.MIN_VALUE || rectAll.getHeight() < Double.MIN_VALUE )
			{
				continue;
			}

			rectList.add(rectAll);
		}


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


		// 得られた矩形を結合する
		Rectangle2D uniRect = SGUtility.createUnion(rectList);


		// 結合した矩形から幅を求める
		final float top = this.mGraphRectY - (float)uniRect.getY();
		final float bottom = -( this.mGraphRectY + this.mGraphRectHeight )
			 + (float)( uniRect.getY() + uniRect.getHeight() );
		final float left = this.mGraphRectX - (float)uniRect.getX();
		final float right = -( this.mGraphRectX + this.mGraphRectWidth )
			 + (float)( uniRect.getX() + uniRect.getWidth() );


		// 引数に設定
		topAndBottom.x += top;
		topAndBottom.y += bottom;
		leftAndRight.x += left;
		leftAndRight.y += right;

		return true;

	}



	/**
	 * 全描画要素の位置を決定
	 */
	protected boolean setAllDrawingElementsLocation()
	{
//System.out.println("<< SGSXYGraphElement::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( ((IElementGroupSetInSXYGraph)groupSet).setDrawingElementsLocation(data) == false )
			{
				return false;
			}
		}


		return true;

	}




	/**
	 * 
	 */
	protected ElementGroupSetInGraph getGroupSetNewInstance( final SGData data )
	{
		ElementGroupSetInGraph groupSet = null;

		if( data instanceof SGISXYTypeData )
		{
			groupSet = new ElementGroupSetInSXYGraph();
		}
		else if( data instanceof SGISXYTypeMultipleData )
		{
			groupSet = new ElementGroupSetForMultipleDataInSXYGraph();
		}

		return groupSet;
	}

	

	/**
	 * 
	 */
	public boolean createDataObject( final Element el, final SGData data )
	{
		if( !( data instanceof SGISXYTypeData ) && !( data instanceof SGISXYTypeMultipleData ) )
		{
			return false;
		}

		if( super.createDataObject(el,data) == false )
		{
			return false;
		}

		// construct a SGElementGroupSet object
		ElementGroupSetInGraph groupSet = this.getGroupSetNewInstance(data);
		if( groupSet==null )
		{
			return false;
		}


		//
		this.mGroupSetList.add( groupSet );

		//
		int ret = this.setProperty( el, groupSet );
		if( ret==SGIConstants.PROPERTY_FILE_INCORRECT )
		{
			return false;
		}

		this.createDataDialog();
		
		return true;
	}


	
	/**
	 * 
	 */
	private int setProperty(
		final Element el, final ElementGroupSetInGraph groupSet )
	{
		SGData data = this.getData(groupSet);
		int ret = SGIConstants.PROPERTY_FILE_INCORRECT;
		if( data instanceof SGISXYTypeData )
		{
			SGISXYTypeData data_ = (SGISXYTypeData)data;
			ElementGroupSetInSXYGraph gs = (ElementGroupSetInSXYGraph)groupSet;
			ret = this.setPropertyOfElementGroupSetInSXYGraph(el,gs,data_);
		}
		else if( data instanceof SGISXYTypeMultipleData )
		{
			SGISXYTypeMultipleData data_ = (SGISXYTypeMultipleData)data;
			ElementGroupSetForMultipleDataInSXYGraph gs
				= (ElementGroupSetForMultipleDataInSXYGraph)groupSet;
			ret = this.setPropertyOfElementGroupSetForMultipleDataInSXYGraph(el,gs,data_);
		}

		return ret;
	}

	
	
	/**
	 * 
	 */
	private int setPropertyOfElementGroupSetForMultipleDataInSXYGraph(
		final Element el,
		final ElementGroupSetForMultipleDataInSXYGraph groupSet,
		final SGISXYTypeMultipleData data )
	{
		// clear the list of the group of the drawing elements
		groupSet.mDrawingElementGroupList.clear();

		SGISXYTypeData[] dataArray = data.getSXYDataArray();
		ElementGroupSetInSXYGraph gs = new ElementGroupSetInSXYGraph();
		int ret = this.setPropertyOfElementGroupSetInSXYGraph( el, gs, dataArray[0] );
		if( ret==SGIConstants.PROPERTY_FILE_INCORRECT )
		{
			return ret;
		}
		SGProperties p = gs.getProperties();
		SGProperties wp = gs.getWholeProperties();

		ArrayList gsList = new ArrayList();
		for( int ii=0; ii<dataArray.length; ii++ )
		{
			ElementGroupSetInSXYGraph gs_ = new ElementGroupSetInSXYGraph();
			if( gs_.setProperties(p) == false )
			{
				return SGIConstants.PROPERTY_FILE_INCORRECT;
			}

			// create instances of the points
			final int num = dataArray[ii].getPointsNumber();
			SGTuple2f[] pointsArray = new SGTuple2f[num];
			for( int jj=0; jj<num; jj++ )
			{
				pointsArray[jj] = new SGTuple2f();
			}
			gs_.mPointsArray = pointsArray;

			gs_.setDrawingElementsLocation( (SGData)dataArray[ii] );
			gs_.addDrawingElementGroup( SGElementGroup.RECTANGLE_GROUP );
			gs_.addDrawingElementGroup( SGElementGroup.POLYLINE_GROUP );
			gs_.addDrawingElementGroup( SGElementGroup.SYMBOL_GROUP );

			if( gs_.setWholeProperties(wp) == false )
			{
				return SGIConstants.PROPERTY_FILE_INCORRECT;
			}

			gs_.initPropertiesHistory();

			gsList.add(gs_);
		}
		

		groupSet.mElementGroupSetList = new ArrayList( gsList );
		groupSet.setName( gs.getName() );
		groupSet.setXAxis( gs.getXAxis() );
		groupSet.setYAxis( gs.getYAxis() );
		groupSet.setZAxis( gs.getZAxis() );

		groupSet.initPropertiesHistory();


		return SGIConstants.SUCCESSFUL_COMPLETION;
	}

	

	/**
	 * 
	 */
	private int setPropertyOfElementGroupSetInSXYGraph(
		final Element el,
		final ElementGroupSetInSXYGraph groupSet,
		final SGISXYTypeData data )
	{

		final int ic = SGIConstants.PROPERTY_FILE_INCORRECT;
		SGIAxisElement aElement = this.mAxisElement;
		String str = null;


		// name of data
		str = el.getAttribute( KEY_DATA_NAME );
		if( str.length()==0 )
		{
			return ic;
		}
		final String name = str;
		
		groupSet.setName(name);


		// configuration of X-axis
		str = el.getAttribute( KEY_X_AXIS_POSITION );
		if( str.length()==0 )
		{
			return ic;
		}
		final int configX = aElement.getConfigurationInCube(str);


		// configuration of Y-axis
		str = el.getAttribute( KEY_Y_AXIS_POSITION );
		if( str.length()==0 )
		{
			return ic;
		}
		final int configY = aElement.getConfigurationInCube(str);
		
		
		// set x- and y-axis
		groupSet.setXAxis( aElement.getAxisInCube( configX ) );
		groupSet.setYAxis( aElement.getAxisInCube( configY ) );


		// visibility in legend
		str = el.getAttribute( KEY_VISIBLE_IN_LEGEND );
		if( str.length()==0 )
		{
			return ic;
		}
		Boolean b = SGUtilityText.getBoolean(str);
		if( b==null )
		{
			return ic;
		}
		final boolean vLegend = b.booleanValue();
		groupSet.setVisibleInLegend(vLegend);


		// create instances of the points
		final int num = data.getPointsNumber();
		SGTuple2f[] pointsArray = new SGTuple2f[num];
		for( int ii=0; ii<num; ii++ )
		{
			pointsArray[ii] = new SGTuple2f();
		}
		groupSet.mPointsArray = pointsArray;

		

		//
		// create drawing element groups
		//
		
		SGElementGroup group = null;
		NodeList nList = null;


		// bar
		nList = el.getElementsByTagName( SGElementGroupBar.TAG_NAME_BAR );
		if( nList.getLength()!=1 )
		{
			return ic;
		}
		if( groupSet.addDrawingElementGroup( SGElementGroup.RECTANGLE_GROUP ) == false )
		{
			return ic;
		}
		Element bar = (Element)nList.item(0);
		group = groupSet.getBarGroup();
		if( group.readProperty(bar) == false )
		{
			return ic;
		}


		// error bar
		nList = el.getElementsByTagName( SGElementGroupErrorBar.TAG_NAME_ERROR_BAR );

		// the property file has error bar info
		if( nList.getLength()==1 )
		{
			// if data has error bars
			if( data.isErrorValueHolding() )
			{
				ElementGroupErrorBar eGroup = groupSet.createErrorBars( data );

				Element errorBar = (Element)nList.item(0);
				if( eGroup.readProperty(errorBar)==false )
				{
					return ic;
				}

				if( eGroup.setPropertiesOfDrawingElements() == false )
				{
					return ic;
				}

				eGroup.setLocation(
					eGroup.mStartArray,
					eGroup.mEndArray );

			}
		}
		else if( nList.getLength()==0 )
		{
			// if data has error bars
			if( data.isErrorValueHolding() )
			{
				ElementGroupErrorBar eGroup = groupSet.createErrorBars( data );
				if( eGroup.setPropertiesOfDrawingElements() == false )
				{
					return ic;
				}
			}
		}
		else
		{
			return ic;
		}


		// line
		nList = el.getElementsByTagName( SGElementGroupLine.TAG_NAME_LINE );
		if( nList.getLength()!=1 )
		{
			return ic;
		}
		if( groupSet.addDrawingElementGroup( SGElementGroup.POLYLINE_GROUP ) == false )
		{
			return ic;
		}
		Element line = (Element)nList.item(0);
		group = groupSet.getLineGroup();
		if( group.readProperty(line) == false )
		{
			return ic;
		}
		
		
		// symbol
		nList = el.getElementsByTagName( SGElementGroupSymbol.TAG_NAME_SYMBOL );
		if( nList.getLength()!=1 )
		{
			return ic;
		}
		if( groupSet.addDrawingElementGroup( SGElementGroup.SYMBOL_GROUP ) == false )
		{
			return ic;
		}
		Element symbol = (Element)nList.item(0);
		group = groupSet.getSymbolGroup();
		if( group.readProperty(symbol) == false )
		{
			return ic;
		}

		
		// tick label
		nList = el.getElementsByTagName( SGElementGroupTickLabel.TAG_NAME_TICK_LABELS );

		// the property file has tick label info
		if( nList.getLength()==1 )
		{
			// if data has tick labels
			if( data.isStringArrayHolding() )
			{
				ElementGroupTickLabels tGroup = groupSet.createTickLabels( data );

				Element tickLabel = (Element)nList.item(0);
				if( tGroup.readProperty(tickLabel) == false )
				{
					return ic;
				}

				if( tGroup.setPropertiesOfDrawingElements() == false )
				{
					return ic;
				}

				tGroup.setLocation( tGroup.mPointsArray );
			}
		}
		else if( nList.getLength()==0 )
		{
			// if data has tick labels
			if( data.isStringArrayHolding() )
			{
				ElementGroupTickLabels tGroup = groupSet.createTickLabels( data );
				if( tGroup.setPropertiesOfDrawingElements() == false )
				{
					return ic;
				}
			}
		}
		else
		{
			return ic;
		}
		
		
		
		//
		groupSet.initPropertiesHistory();

		
		return SGIConstants.SUCCESSFUL_COMPLETION;
	}

	


	/**
	 * An interface used in this class.
	 */
	private static interface IElementGroupSetInSXYGraph
	{
		/**
		 * 
		 */
		public Rectangle2D getTickLabelsBoundingBox( final SGData data );


		/**
		 * 
		 */
		public boolean setDrawingElementsLocation( final SGData data );

		/**
		 * 
		 */
		public boolean paintDataString( final Graphics2D g2d );


		/**
		 * Synchronize to the given drawing elements.
		 * @param list - list of drawing element
		 * @return whether property changed
		 */
		public boolean synchronizeDrawingElement( ArrayList list );

	}




	/**
	 * 
	 */
	class ElementGroupSetForMultipleDataInSXYGraph
		extends ElementGroupSetForMultipleData
		implements IElementGroupSetInSXYGraph, SGISXYDataDialogObserver
	{

		/**
		 * 
		 */
		protected ElementGroupSetForMultipleDataInSXYGraph()
		{
			super();
			this.mPopupMenu = createGroupSetPopupMenu(this);
		}


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


		/**
		 * 
		 */
		protected boolean createDrawingElements()
		{
			for( int ii=0; ii<this.mElementGroupSetList.size(); ii++ )
			{
				ElementGroupSetInGraph groupSet
					= (ElementGroupSetInGraph)this.mElementGroupSetList.get(ii);
				if( groupSet.createDrawingElements() == false )
				{
					return false;
				} 
			}

			return true;
		}



//		public ArrayList getLineGroupList()
//		{
//			return this.getLineGroups();
//		}
//
//		public ArrayList getSymbolGroupList()
//		{
//			return this.getSymbolGroups();
//		}
//
//		public ArrayList getBarGroupList()
//		{
//			return this.getBarGroups();
//		}
//
//		public ArrayList getErrorBarGroupList()
//		{
//			return this.getErrorBarGroups();
//		}
//
//		public ArrayList getTickLabelGroupList()
//		{
//			return this.getTickLabelGroups();
//		}


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

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

			SGISXYTypeMultipleData data_ = (SGISXYTypeMultipleData)data;
			SGISXYTypeData[] dataSXYArray = data_.getSXYDataArray();
			for( int ii=0; ii<this.mElementGroupSetList.size(); ii++ )
			{
				IElementGroupSetInSXYGraph gs
					= (IElementGroupSetInSXYGraph)this.mElementGroupSetList.get(ii);
				if( gs.setDrawingElementsLocation( (SGData)dataSXYArray[ii]) == false )
				{
					return false;
				}
			}

			return true;
		}


		/**
		 * 
		 */
		public Rectangle2D getTickLabelsBoundingBox( final SGData data )
		{
			if( ( data instanceof SGISXYTypeMultipleData ) == false )
			{
				return null;
			}

			SGISXYTypeMultipleData data_ = (SGISXYTypeMultipleData)data;
			SGISXYTypeData[] dataSXYArray = data_.getSXYDataArray();

			ArrayList list = new ArrayList();
			for( int ii=0; ii<this.mElementGroupSetList.size(); ii++ )
			{
				IElementGroupSetInSXYGraph groupSet
					= (IElementGroupSetInSXYGraph)this.mElementGroupSetList.get(ii);
				Rectangle2D rect = groupSet.getTickLabelsBoundingBox( (SGData)dataSXYArray[ii] );
				if( rect==null )
				{
					return null;
				}
				list.add(rect);
			}

			Rectangle2D rectAll = SGUtility.createUnion(list);

			return rectAll;
		}



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

			for( int ii=0; ii<this.mElementGroupSetList.size(); ii++ )
			{
				IElementGroupSetInSXYGraph groupSet
					= (IElementGroupSetInSXYGraph)this.mElementGroupSetList.get(ii);
				groupSet.paintDataString(g2d);
			}

			return true;
		}



		/**
		 * 
		 */
		public boolean prepare()
		{
			this.mTemporaryProperties = this.getWholeProperties();
			return true;
		}



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


		/**
		 * 
		 */
		public void setXAxisConfiguration( final int config )
		{
			this.setXAxis( this.getAxis(config) );
		}

		/**
		 * 
		 */
		public void setYAxisConfiguration( final int config )
		{
			this.setYAxis( this.getAxis(config) );
		}

		private SGAxis getAxis( final int config )
		{
			return mAxisElement.getAxisInPlane( config );
		}


		public boolean setXAxis( SGAxis axis )
		{
			super.setXAxis(axis);
			ArrayList list = this.mElementGroupSetList;
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupSetInGraph groupSet
					= (ElementGroupSetInGraph)list.get(ii);
				groupSet.setXAxis( axis );
			}
			return true;
		}


		public boolean setYAxis( SGAxis axis )
		{
			super.setYAxis(axis);
			ArrayList list = this.mElementGroupSetList;
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupSetInGraph groupSet
					= (ElementGroupSetInGraph)list.get(ii);
				groupSet.setYAxis( axis );
			}
			return true;
		}



		/**
		 * 
		 */
		public double getSamplingRate()
		{
			SGData data = SGSXYGraphElement.this.getData(this);
			SGSXYSamplingData sData = (SGSXYSamplingData)data;
			return sData.getSamplingRate();
		}



		/**
		 * 
		 */
		public SGProperties getWholeProperties()
		{
			ElementGroupSetInSXYGraph groupSet = this.getFirst();
			WholeProperties wp = new WholeProperties();
			if( groupSet.getWholeProperties(wp) == false ) return null;
			return wp;
		}


		/**
		 * 
		 */
		public boolean setWholeProperties( SGProperties p )
		{
			if( ( p instanceof WholeProperties ) == false ) return false;

			WholeProperties wp = (WholeProperties)p;
			
			ArrayList list = this.mElementGroupSetList;
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupSetInSXYGraph groupSet
					= (ElementGroupSetInSXYGraph)list.get(ii);
				if( groupSet.setWholeProperties(p) == false ) return false;
			}

			return true;
		}

		
		
		/**
		 * 
		 * @param document
		 * @return
		 */
		public Element createElement( final Document document )
		{
			Element el = document.createElement( this.getTagName() );
			if( this.writeProperty(el) == false )
			{
				return null;
			}

			// get the first group set
			ElementGroupSetInSXYGraph groupSet = this.getFirst();

			// axes
			SGAxis xAxis = groupSet.getXAxis();
			SGAxis yAxis = groupSet.getYAxis();
			final int configX = mAxisElement.getConfigurationInCube( xAxis );
			final int configY = mAxisElement.getConfigurationInCube( yAxis );
			final String strX = mAxisElement.getConfigurationString( configX );
			final String strY = mAxisElement.getConfigurationString( configY );
			el.setAttribute( KEY_X_AXIS_POSITION, strX );
			el.setAttribute( KEY_Y_AXIS_POSITION, strY );

			// drawing elements
			ArrayList list = groupSet.mDrawingElementGroupList;
			for( int ii=0; ii<list.size(); ii++ )
			{
				SGElementGroup group = (SGElementGroup)list.get(ii);
				Element element = group.createElement( document );
				if( element == null )
				{
					return null;
				}
				el.appendChild( element );
			}

			return el;
		}


		
		/**
		 * 
		 */
		public boolean writeProperty( final Element el )
		{
			SGISXYTypeMultipleData data = (SGISXYTypeMultipleData)getData( this );


			// call the method in the super class
			if( super.writeProperty(el) == false )
			{
				return false;
			}

			
			// write sampling rate
			if( data instanceof SGSXYSamplingData )
			{
				final double rate = this.getSamplingRate();
				el.setAttribute( PF_SAMPLING_RATE, Double.toString(rate) );
			}


			return true;
		}




		// Line
		
		public boolean isLineVisible()
		{
			return this.getLineGroup().isVisible();
		}
		
		public float getLineWidth()
		{
			return this.getLineGroup().getLineWidth();
		}
		
		public int getLineType()
		{
			return this.getLineGroup().getLineType();
		}

		public Color getLineColor()
		{
			return this.getLineGroup().getColor(0);
		}


		public boolean setLineVisible( final boolean b )
		{
			ArrayList list = this.getLineGroups();
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupLine group = (ElementGroupLine)list.get(ii);
				group.setVisible(b);
			}
			return true;
		}

		public boolean setLineWidth( final float width )
		{
			ArrayList list = this.getLineGroups();
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupLine group = (ElementGroupLine)list.get(ii);
				group.setLineWidth(width);
			}
			return true;
		}

		public boolean setLineType( final int type )
		{
			ArrayList list = this.getLineGroups();
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupLine group = (ElementGroupLine)list.get(ii);
				group.setLineType(type);
			}
			return true;
		}
		
		public boolean setLineColor( final Color cl )
		{
			ArrayList list = this.getLineGroups();
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupLine group = (ElementGroupLine)list.get(ii);
				group.setColor(cl);
			}
			return true;
		}



		// Symbol

		public boolean isSymbolVisible()
		{
			return this.getSymbolGroup().isVisible();
		}

		public int getSymbolType()
		{
			return this.getSymbolGroup().getType();
		}

		public float getSymbolSize()
		{
			return this.getSymbolGroup().getSize();
		}

		public float getSymbolLineWidth()
		{
			return this.getSymbolGroup().getLineWidth();
		}

		public Color getSymbolInnerColor()
		{
			return this.getSymbolGroup().getColor(0);
		}

		public Color getSymbolLineColor()
		{
			return this.getSymbolGroup().getLineColor();
		}

		public boolean setSymbolVisible( final boolean b )
		{
			ArrayList list = this.getSymbolGroups();
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupSymbol group = (ElementGroupSymbol)list.get(ii);
				group.setVisible(b);
			}
			return true;
		}

		public boolean setSymbolType( final int type )
		{
			ArrayList list = this.getSymbolGroups();
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupSymbol group = (ElementGroupSymbol)list.get(ii);
				group.setType(type);
			}
			return true;
		}

		public boolean setSymbolSize( final float size )
		{
			ArrayList list = this.getSymbolGroups();
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupSymbol group = (ElementGroupSymbol)list.get(ii);
				group.setSize(size);
			}
			return true;
		}

		public boolean setSymbolLineWidth( final float width )
		{
			ArrayList list = this.getSymbolGroups();
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupSymbol group = (ElementGroupSymbol)list.get(ii);
				group.setLineWidth(width);
			}
			return true;
		}

		public boolean setSymbolInnerColor( final Color cl )
		{
			ArrayList list = this.getSymbolGroups();
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupSymbol group = (ElementGroupSymbol)list.get(ii);
				group.setColor(cl);
			}
			return true;
		}

		public boolean setSymbolLineColor( final Color cl )
		{
			ArrayList list = this.getSymbolGroups();
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupSymbol group = (ElementGroupSymbol)list.get(ii);
				group.setLineColor(cl);
			}
			return true;
		}



		// Bar

		public boolean isBarVisible()
		{
			return this.getBarGroup().isVisible();
		}

		public double getBarBaselineValue()
		{
			return this.getBarGroup().getBaselineValue();
		}

		public float getBarWidth()
		{
			return this.getBarGroup().getRectangleWidth();
		}

		public float getBarEdgeLineWidth()
		{
			return this.getBarGroup().getEdgeLineWidth();
		}

		public Color getBarInnerColor()
		{
			return this.getBarGroup().getColor(0);
		}

		public Color getBarEdgeLineColor()
		{
			return this.getBarGroup().getEdgeLineColor();
		}

		public boolean setBarVisible( final boolean b )
		{
			ArrayList list = this.getBarGroups();
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupBar group = (ElementGroupBar)list.get(ii);
				group.setVisible(b);
			}
			return true;
		}

		public boolean setBarBaselineValue( final double value )
		{
			ArrayList list = this.getBarGroups();
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupBar group = (ElementGroupBar)list.get(ii);
				group.setBaselineValue(value);
			}
			return true;
		}

		public boolean setBarWidth( final float width )
		{
			ArrayList list = this.getBarGroups();
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupBar group = (ElementGroupBar)list.get(ii);
				group.setRectangleWidth(width);
			}
			return true;
		}

		public boolean setBarEdgeLineWidth( final float width )
		{
			ArrayList list = this.getBarGroups();
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupBar group = (ElementGroupBar)list.get(ii);
				group.setEdgeLineWidth(width);
			}
			return true;
		}

		public boolean setBarInnerColor( final Color cl )
		{
			ArrayList list = this.getBarGroups();
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupBar group = (ElementGroupBar)list.get(ii);
				group.setColor(cl);
			}
			return true;
		}

		public boolean setBarEdgeLineColor( final Color cl )
		{
			ArrayList list = this.getBarGroups();
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupBar group = (ElementGroupBar)list.get(ii);
				group.setEdgeLineColor(cl);
			}
			return true;
		}



		// Error Bar
		public boolean isErrorBarHolding()
		{
			return (this.getErrorBarGroup()!=null);
		}

		public boolean isErrorBarVisible()
		{
			return this.getErrorBarGroup().isVisible();
		}

		public int getErrorBarHeadType()
		{
			return this.getErrorBarGroup().getHeadType();
		}

		public float getErrorBarHeadSize()
		{
			return this.getErrorBarGroup().getHeadSize();
		}

		public Color getErrorBarColor()
		{
			return this.getErrorBarGroup().getColor(0);
		}

		public float getErrorBarLineWidth()
		{
			return this.getErrorBarGroup().getLineWidth();
		}

		public int getErrorBarStyle()
		{
			return this.getErrorBarGroup().getErrorBarStyle();
		}

		public boolean setErrorBarVisible( final boolean b )
		{
			return true;
		}

		public boolean setErrorBarHeadType( final int type )
		{
			return true;
		}

		public boolean setErrorBarHeadSize( final float size )
		{
			return true;
		}

		public boolean setErrorBarColor( final Color cl )
		{
			return true;
		}

		public boolean setErrorBarLineWidth( final float width )
		{
			return true;
		}

		public boolean setErrorBarStyle( final int style )
		{
			return true;
		}



		// Tick Label

		public boolean isTickLabelHolding()
		{
			return (this.getTickLabelGroup()!=null);
		}

		public boolean isTickLabelVisible()
		{
			return this.getTickLabelGroup().isVisible();
		}

		public String getTickLabelFontName()
		{
			return this.getTickLabelGroup().getFontName();
		}

		public int getTickLabelFontStyle()
		{
			return this.getTickLabelGroup().getFontStyle();
		}

		public float getTickLabelFontSize()
		{
			return this.getTickLabelGroup().getFontSize();
		}

		public Color getTickLabelColor()
		{
			return this.getTickLabelGroup().getColor(0);
		}

		public boolean isTickLabelHorizontal()
		{
			return (this.getTickLabelGroup().getAngle()==SGElementGroupTickLabel.ANGLE_HORIZONTAL);
		}

		public boolean setTickLabelVisible( final boolean b )
		{
			return true;
		}

		public boolean setTickLabelFontName( final String name )
		{
			return true;
		}

		public boolean setTickLabelFontStyle( final int style )
		{
			return true;
		}

		public boolean setTickLabelFontSize( final float size )
		{
			return true;
		}

		public boolean setTickLabelColor( final Color cl )
		{
			return true;
		}

		public boolean setTickLabelHorizontal( final boolean b )
		{
			return true;
		}


		
		/**
		 * 
		 */
		public ArrayList getLineGroups()
		{
			ArrayList list = new ArrayList();
			ArrayList gsList = this.mElementGroupSetList;
			for( int ii=0; ii<gsList.size(); ii++ )
			{
				ElementGroupSetInSXYGraph groupSet
					= (ElementGroupSetInSXYGraph)gsList.get(ii);
				list.addAll( groupSet.getLineGroups() );
			}
			return list;
		}


		/**
		 * 
		 */
		public ArrayList getSymbolGroups()
		{
			ArrayList list = new ArrayList();
			ArrayList gsList = this.mElementGroupSetList;
			for( int ii=0; ii<gsList.size(); ii++ )
			{
				ElementGroupSetInSXYGraph groupSet
					= (ElementGroupSetInSXYGraph)gsList.get(ii);
				list.addAll( groupSet.getSymbolGroups() );
			}
			return list;
		}


		/**
		 * 
		 */
		public ArrayList getBarGroups()
		{
			ArrayList list = new ArrayList();
			ArrayList gsList = this.mElementGroupSetList;
			for( int ii=0; ii<gsList.size(); ii++ )
			{
				ElementGroupSetInSXYGraph groupSet
					= (ElementGroupSetInSXYGraph)gsList.get(ii);
				list.addAll( groupSet.getBarGroups() );
			}
			return list;
		}


		/**
		 * 
		 */
		public ArrayList getErrorBarGroups()
		{
			ArrayList list = new ArrayList();
			ArrayList gsList = this.mElementGroupSetList;
			for( int ii=0; ii<gsList.size(); ii++ )
			{
				ElementGroupSetInSXYGraph groupSet
					= (ElementGroupSetInSXYGraph)gsList.get(ii);
				list.addAll( groupSet.getErrorBarGroups() );
			}
			return list;
		}


		/**
		 * 
		 */
		public ArrayList getTickLabelGroups()
		{
			ArrayList list = new ArrayList();
			ArrayList gsList = this.mElementGroupSetList;
			for( int ii=0; ii<gsList.size(); ii++ )
			{
				ElementGroupSetInSXYGraph groupSet
					= (ElementGroupSetInSXYGraph)gsList.get(ii);
				list.addAll( groupSet.getTickLabelGroups() );
			}
			return list;
		}


		public int getSelectedTabIndex()
		{
			return this.mSelectedTabIndex;
		}

		private int mSelectedTabIndex = -1;


		/**
		 * 
		 * @param e
		 * @param groupSet
		 * @return
		 */
		protected boolean onMouseClicked( final MouseEvent e )
		{
			if( super.onMouseClicked(e) == false )
			{
				return false;
			}

			SGElementGroup group = this.getElementGroupAt( e.getX(), e.getY() );

			int index = -1;
			if( group instanceof ElementGroupLine )
			{
				index = 0;
			}
			else if( group instanceof ElementGroupSymbol )
			{
				index = 1;
			}
			else if( group instanceof ElementGroupBar )
			{
				index = 2;
			}
//			else if( group instanceof ElementGroupErrorBar )
//			{
//				index = 3;
//			}
//			else if( group instanceof ElementGroupTickLabels )
//			{
//				index = 4;
//			}
			this.mSelectedTabIndex = index;

			return true;
		}

		
		/**
		 * 
		 * @return
		 */
		private ElementGroupSetInSXYGraph getFirst()
		{
			ElementGroupSetInSXYGraph groupSet
				= (ElementGroupSetInSXYGraph)this.mElementGroupSetList.get(0);
			return groupSet;
		}


		/**
		 * 
		 */
		public int getXAxisConfiguration()
		{
			return this.getFirst().getXAxisConfiguration();
		}


		/**
		 * 
		 */
		public int getYAxisConfiguration()
		{
			return this.getFirst().getYAxisConfiguration();
		}

		
		/**
		 * 
		 */
		public boolean getLegendVisibleFlag()
		{
			return this.isVisibleInLegend();
		}



		/**
		 * 
		 */
		public boolean synchronizeDrawingElement( ArrayList sList )
		{
			boolean diffFlag = false;

			ArrayList gList = this.mElementGroupSetList;
			for( int ii=0; ii<gList.size(); ii++ )
			{
				ElementGroupSetInSXYGraph groupSet
					= (ElementGroupSetInSXYGraph)gList.get(ii);
				final boolean b = groupSet.synchronizeDrawingElement( sList );
				if(b)
				{
					diffFlag = true;
				}
			}

			return diffFlag;
		}


//		/**
//		 * 
//		 */
//		class ElementGroupSetPropertiesForSamplingDataInSXYGraph
//			extends ElementGroupSetInGraphProperties
//		{
//
//			double samplingRate;
//
//			/**
//			 * 
//			 */
//			public boolean equals( final Object obj )
//			{
//
//				if( obj == null )
//				{
//					return false;
//				}
//
//				if( ( obj instanceof ElementGroupSetPropertiesForSamplingDataInSXYGraph ) == false )
//				{
//					return false;
//				}
//
//				ElementGroupSetPropertiesForSamplingDataInSXYGraph p
//					= (ElementGroupSetPropertiesForSamplingDataInSXYGraph)obj;
//
//				if( p.samplingRate!=this.samplingRate ) return false;
//
//				return true;
//
//			}
//
//			
//		}



	}




	/**
	 * 
	 */
	class ElementGroupSetInSXYGraph extends ElementGroupSetInGraph
		implements IElementGroupSetInSXYGraph, SGISXYDataDialogObserver
	{

		/**
		 * 
		 */
		protected ElementGroupSetInSXYGraph()
		{
			super();
			this.mPopupMenu = createGroupSetPopupMenu(this);
		}


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


		/**
		 * 
		 * @param groupList
		 * @param p
		 * @return
		 */		
		private boolean setProperties( ArrayList groupList, SGProperties p )
		{
			for( int ii=0; ii<groupList.size(); ii++ )
			{
				SGElementGroup group = (SGElementGroup)groupList.get(ii);
				if( group.setProperties(p) == false )
				{
					return false;
				}
			}

			return true;
		}


		/**
		 * 
		 */
		public boolean getLegendVisibleFlag()
		{
			return this.isVisibleInLegend();
		}


		/**
		 * 
		 */
		public int getXAxisConfiguration()
		{
			return mAxisElement.getConfigurationInPlane( this.getXAxis() );
		}


		/**
		 * 
		 */
		public int getYAxisConfiguration()
		{
			return mAxisElement.getConfigurationInPlane( this.getYAxis() );
		}


		public ArrayList getLineGroupList()
		{
			return this.getLineGroups();
		}

		public ArrayList getSymbolGroupList()
		{
			return this.getSymbolGroups();
		}

		public ArrayList getBarGroupList()
		{
			return this.getBarGroups();
		}

		public ArrayList getErrorBarGroupList()
		{
			return this.getErrorBarGroups();
		}

		public ArrayList getTickLabelGroupList()
		{
			return this.getTickLabelGroups();
		}


		public int getSelectedTabIndex()
		{
			return this.mSelectedTabIndex;
		}

		private int mSelectedTabIndex = -1;




		// Line
		
		public boolean isLineVisible()
		{
			return this.getLineGroup().isVisible();
		}
		
		public float getLineWidth()
		{
			return this.getLineGroup().getLineWidth();
		}
		
		public int getLineType()
		{
			return this.getLineGroup().getLineType();
		}

		public Color getLineColor()
		{
			return this.getLineGroup().getColor(0);
		}


		public boolean setLineVisible( final boolean b )
		{
			this.getLineGroup().setVisible(b);
			return true;
		}

		public boolean setLineWidth( final float width )
		{
			return this.getLineGroup().setLineWidth( width );
		}

		public boolean setLineType( final int type )
		{
			return this.getLineGroup().setLineType( type );
		}
		
		public boolean setLineColor( final Color cl )
		{
			return this.getLineGroup().setColor( cl );
		}



		// Symbol

		public boolean isSymbolVisible()
		{
			return this.getSymbolGroup().isVisible();
		}

		public int getSymbolType()
		{
			return this.getSymbolGroup().getType();
		}

		public float getSymbolSize()
		{
			return this.getSymbolGroup().getSize();
		}

		public float getSymbolLineWidth()
		{
			return this.getSymbolGroup().getLineWidth();
		}

		public Color getSymbolInnerColor()
		{
			return this.getSymbolGroup().getColor(0);
		}

		public Color getSymbolLineColor()
		{
			return this.getSymbolGroup().getLineColor();
		}

		public boolean setSymbolVisible( final boolean b )
		{
			this.getSymbolGroup().setVisible(b);
			return true;
		}

		public boolean setSymbolType( final int type )
		{
			return this.getSymbolGroup().setType(type);
		}

		public boolean setSymbolSize( final float size )
		{
			return this.getSymbolGroup().setSize(size);
		}

		public boolean setSymbolLineWidth( final float width )
		{
			return this.getSymbolGroup().setLineWidth(width);
		}

		public boolean setSymbolInnerColor( final Color cl )
		{
			return this.getSymbolGroup().setColor(cl);
		}

		public boolean setSymbolLineColor( final Color cl )
		{
			return this.getSymbolGroup().setLineColor(cl);
		}



		// Bar

		public boolean isBarVisible()
		{
			return this.getBarGroup().isVisible();
		}

		public double getBarBaselineValue()
		{
			return this.getBarGroup().getBaselineValue();
		}

		public float getBarWidth()
		{
			return this.getBarGroup().getRectangleWidth();
		}

		public float getBarEdgeLineWidth()
		{
			return this.getBarGroup().getEdgeLineWidth();
		}

		public Color getBarInnerColor()
		{
			return this.getBarGroup().getColor(0);
		}

		public Color getBarEdgeLineColor()
		{
			return this.getBarGroup().getEdgeLineColor();
		}

		public boolean setBarVisible( final boolean b )
		{
			this.getBarGroup().setVisible(b);
			return true;
		}

		public boolean setBarBaselineValue( final double value )
		{
			return this.getBarGroup().setBaselineValue( value );
		}

		public boolean setBarWidth( final float width )
		{
			return this.getBarGroup().setRectangleWidth( width );
		}

		public boolean setBarEdgeLineWidth( final float width )
		{
			return this.getBarGroup().setEdgeLineWidth( width );
		}

		public boolean setBarInnerColor( final Color cl )
		{
			return this.getBarGroup().setColor(cl);
		}

		public boolean setBarEdgeLineColor( final Color cl )
		{
			return this.getBarGroup().setEdgeLineColor(cl);
		}



		// Error Bar
		public boolean isErrorBarHolding()
		{
			return (this.getErrorBarGroup()!=null);
		}

		public boolean isErrorBarVisible()
		{
			return this.getErrorBarGroup().isVisible();
		}

		public int getErrorBarHeadType()
		{
			return this.getErrorBarGroup().getHeadType();
		}

		public float getErrorBarHeadSize()
		{
			return this.getErrorBarGroup().getHeadSize();
		}

		public Color getErrorBarColor()
		{
			return this.getErrorBarGroup().getColor(0);
		}

		public float getErrorBarLineWidth()
		{
			return this.getErrorBarGroup().getLineWidth();
		}

		public int getErrorBarStyle()
		{
			return this.getErrorBarGroup().getErrorBarStyle();
		}

		public boolean setErrorBarVisible( final boolean b )
		{
			this.getErrorBarGroup().setVisible(b);
			return true;
		}

		public boolean setErrorBarHeadType( final int type )
		{
			this.getErrorBarGroup().setHeadType( type );
			return true;
		}

		public boolean setErrorBarHeadSize( final float size )
		{
			this.getErrorBarGroup().setHeadSize( size );
			return true;
		}

		public boolean setErrorBarColor( final Color cl )
		{
			return this.getErrorBarGroup().setColor(cl);
		}

		public boolean setErrorBarLineWidth( final float width )
		{
			this.getErrorBarGroup().setLineWidth( width );
			return true;
		}

		public boolean setErrorBarStyle( final int style )
		{
			this.getErrorBarGroup().setErrorBarStyle(style);
			return true;
		}



		// Tick Label

		public boolean isTickLabelHolding()
		{
			return (this.getTickLabelGroup()!=null);
		}

		public boolean isTickLabelVisible()
		{
			return this.getTickLabelGroup().isVisible();
		}

		public String getTickLabelFontName()
		{
			return this.getTickLabelGroup().getFontName();
		}

		public int getTickLabelFontStyle()
		{
			return this.getTickLabelGroup().getFontStyle();
		}

		public float getTickLabelFontSize()
		{
			return this.getTickLabelGroup().getFontSize();
		}

		public Color getTickLabelColor()
		{
			return this.getTickLabelGroup().getColor(0);
		}

		public boolean isTickLabelHorizontal()
		{
			return (this.getTickLabelGroup().getAngle()==SGElementGroupTickLabel.ANGLE_HORIZONTAL);
		}

		public boolean setTickLabelVisible( final boolean b )
		{
			this.getTickLabelGroup().setVisible(b);
			return true;
		}

		public boolean setTickLabelFontName( final String name )
		{
			return this.getTickLabelGroup().setFontName( name );
		}

		public boolean setTickLabelFontStyle( final int style )
		{
			return this.getTickLabelGroup().setFontStyle( style );
		}

		public boolean setTickLabelFontSize( final float size )
		{
			return this.getTickLabelGroup().setFontSize( size );
		}

		public boolean setTickLabelColor( final Color cl )
		{
			return this.getTickLabelGroup().setColor(cl);
		}


		public boolean setTickLabelHorizontal( final boolean b )
		{
			float angle;
			if(b)
			{
				angle = SGElementGroupTickLabel.ANGLE_HORIZONTAL;
			}
			else
			{
				angle = SGElementGroupTickLabel.ANGLE_INCLINED;
			}
			return this.getTickLabelGroup().setAngle( angle );			
		}


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

			SGElementGroupSXY group = null;
			if( type == SGElementGroup.POLYLINE_GROUP )
			{
				group = new ElementGroupLine();
			}
			else if( type == SGElementGroup.RECTANGLE_GROUP )
			{
				group = new ElementGroupBar();
			}
			else if( type == SGElementGroup.SYMBOL_GROUP )
			{
				group = new ElementGroupSymbol();
			}
			else
			{
				return false;
			}


			// 既に存在する場合には追加しない
			if( this.checkGroupType( group ) == false )
			{
				return false;
			}

			// add a group
			this.addElementGroup(group);

			return true;
		}


		/**
		 * 
		 */
		private boolean checkGroupType( final SGElementGroup group )
		{
			final Class cl = group.getClass();
			ArrayList list = this.mDrawingElementGroupList;
			for( int ii=0; ii<list.size(); ii++ )
			{
				final SGElementGroup group_ = (SGElementGroup)list.get(ii);
				final Class cl_ = group_.getClass();
				if( cl.equals(cl_) )
				{
					return false;
				}
			}

			return true;
		}



		/**
		 * 
		 */
		private ElementGroupErrorBar createErrorBars( SGISXYTypeData dataSXY )
		{
			final ElementGroupErrorBar eGroup
				= new ElementGroupErrorBar( dataSXY );
			this.mDrawingElementGroupList.add( eGroup );
			eGroup.mGroupSet = this;
			return eGroup;
		}



		/**
		 * 
		 * @param dataSXY
		 * @return
		 */
		private ElementGroupTickLabels createTickLabels( SGISXYTypeData dataSXY )
		{
			final ElementGroupTickLabels sGroup
				= new ElementGroupTickLabels( dataSXY );
			this.mDrawingElementGroupList.add( sGroup );
			sGroup.mGroupSet = this;
			return sGroup;
		}



		/**
		 * 
		 */
		public boolean synchronizeDrawingElement( ArrayList sList )
		{
			ArrayList groupList = new ArrayList();
			for( int ii=0; ii<sList.size(); ii++ )
			{
				SGDrawingElement el = (SGDrawingElement)sList.get(ii);

				SGElementGroup group = null;
				if( el instanceof SGDrawingElementErrorBar )
				{
					group = this.getErrorBarGroup();
				}
				else if( el instanceof SGDrawingElementLine )
				{
					group = this.getLineGroup();
				}
				else if( el instanceof SGDrawingElementSymbol )
				{
					group = this.getSymbolGroup();
				}
				else if( el instanceof SGDrawingElementBar )
				{
					group = this.getBarGroup();
				}
				else if( el instanceof SGDrawingElementString )
				{
					group = this.getTickLabelGroup();
				}

				if( group==null )
				{
					continue;
				}

				groupList.add(group);
			}


			boolean diffFlag = false;
			for( int ii=0; ii<sList.size(); ii++ )
			{
				SGDrawingElement el = (SGDrawingElement)sList.get(ii);
				SGElementGroup group = (SGElementGroup)groupList.get(ii);
				SGDrawingElement elOld = group.getDrawingElement();
				SGProperties p = el.getProperties();
				SGProperties pOld = elOld.getProperties();
				if( p.equals(pOld) == false )
				{
					diffFlag = true;
				}
				group.setProperty(el);
			}

			return diffFlag;
		}



		/**
		 * 
		 */
		private SGTuple2f[] mPointsArray = null;



		/**
		 * Called when the location of data points have changed.
		 */
		public boolean setDrawingElementsLocation( final SGData data )
		{

			if( ( data instanceof SGISXYTypeData ) == false )
			{
				return false;
			}
			SGISXYTypeData dataSXY = (SGISXYTypeData)data;
			final int num = dataSXY.getPointsNumber();


			// set the location of the data points
			if( calcLocationOfSXYData(
				dataSXY,
				this.getXAxis(),
				this.getYAxis(),
				this.mPointsArray ) == false )
			{
				return false;
			}


			ArrayList gList = this.mDrawingElementGroupList;
			for( int ii=0; ii<gList.size(); ii++ )
			{
				SGElementGroup group = (SGElementGroup)gList.get(ii);
				if( group.isVisible() )
				{
					if( group instanceof SGElementGroupErrorBar )
					{
						// set the location of error bars
						ElementGroupErrorBar eGroup = (ElementGroupErrorBar)group;
						SGTuple2f[] startArray = eGroup.mStartArray;
						SGTuple2f[] endArray = eGroup.mEndArray;
						if( eGroup.calcErrorBarLocation(
							dataSXY,
							this.getXAxis(),
							this.getYAxis(),
							startArray,
							endArray ) == false )
						{
							return false;
						}

						if( eGroup.setLocation(
							startArray,
							endArray ) == false )
						{
							return false;
						}
					}
					else if( group instanceof SGElementGroupTickLabel )
					{
						// set the location of tick labels
						ElementGroupTickLabels tl
							= (ElementGroupTickLabels)group;
						SGTuple2f[] pointArray = tl.mPointsArray;

						if( tl.calcTickLabelLocation(
							dataSXY, this.getXAxis(), pointArray ) == false )
						{
							return false;
						}

						if( tl.setLocation( pointArray ) == false )
						{
							return false;
						}
					}
					else if( ( group instanceof SGElementGroupLine )
						| ( group instanceof SGElementGroupSymbol )
						| ( group instanceof SGElementGroupBar ) )
					{
						SGElementGroupSXY groupSXY = (SGElementGroupSXY)group;
						if( groupSXY.setLocation( this.mPointsArray ) == false )
						{
							return false;
						}
					}
				}
			}

			return true;
		}



		/**
		 * 
		 */
		protected boolean createDrawingElements()
		{

			final ArrayList groupList = this.mDrawingElementGroupList;
			for( int ii=0; ii<groupList.size(); ii++ )
			{
				final SGElementGroup group = (SGElementGroup)groupList.get(ii);

				if( group.isVisible() )
				{
					if( group instanceof SGElementGroupSXY )
					{
						SGElementGroupSXY groupSXY = (SGElementGroupSXY)group;
						groupSXY.setLocation( this.mPointsArray );
					}
					else if( group instanceof ElementGroupErrorBar )
					{
						ElementGroupErrorBar eGroup = (ElementGroupErrorBar)group;
						eGroup.setLocation(
							eGroup.mStartArray,
							eGroup.mEndArray );
					}
					else if( group instanceof ElementGroupTickLabels )
					{
						ElementGroupTickLabels tl
							= (ElementGroupTickLabels)group;
						tl.setLocation( tl.mPointsArray );
					}
				}
			}


			return true;
		}



		/**
		 * 
		 */
		private boolean addElementGroup( final SGElementGroupSXY group )
		{

			group.mGroupSet = this;


			// 描画要素の作成
			if( group.initDrawingElement( this.mPointsArray ) == false )
			{
				throw new Error();
			}


			// set the properties to drawing elements
			if( group.setPropertiesOfDrawingElements() == false )
			{
				return false;
			}


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


			return true;

		}



		/**
		 * 
		 */
		public Rectangle2D getTickLabelsBoundingBox( final SGData data )
		{

			if( ( data instanceof SGISXYTypeData ) == false )
			{
				return null;
			}
			
			SGISXYTypeData dataSXY = (SGISXYTypeData)data;

			ArrayList rectList = new ArrayList();
			ArrayList tickLabelGroups = this.getTickLabelGroups();
			if( tickLabelGroups.size()==0 )
			{
				return new Rectangle2D.Float();
			}
			final ElementGroupTickLabels group
				= (ElementGroupTickLabels)tickLabelGroups.get(0);
			if( !group.isVisible() )
			{
				return new Rectangle2D.Float();
			}


			ArrayList strList = new ArrayList();
			SGDrawingElement[] elArray = group.mDrawingElementArray;
			for( int ii=0; ii<elArray.length; ii++ )
			{
				if( elArray[ii].isVisible() )
				{
					strList.add( elArray[ii] );
				}
			}

			Rectangle2D rectAll = SGUtilityJava2D.getBoundingBox(strList);
			if( rectAll==null )
			{
				return new Rectangle2D.Float();
			}
			rectList.add(rectAll);


			// 得られた矩形を結合する
			Rectangle2D uniRect = SGUtility.createUnion(rectList);
			if( uniRect==null )
			{
				new Rectangle2D.Float();
			}

			return uniRect;
		}




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

			Rectangle2D gRect = null;
			if( !this.getClipFlag() )
			{
				gRect = getGraphRect();
			}


			// bar
			final ElementGroupBar groupBar = getGroupBar( this );
			if( groupBar!=null )
			{
				if( groupBar.isVisible() )
				{
					groupBar.paintElement(g2d,gRect);
				}
			}


			// error bar
			ArrayList eList = this.getErrorBarGroups();
			if( eList.size()!=0 )
			{
				final ElementGroupErrorBar eGroup = (ElementGroupErrorBar)eList.get(0);
				if( eGroup!=null )
				{
					if( eGroup.isVisible() )
					{
						eGroup.paintElement(g2d,gRect);
					}
				}
			}


			// line
			final ElementGroupLine groupLine = getGroupLine( this );
			if( groupLine!=null )
			{
				if( groupLine.isVisible() )
				{
					groupLine.paintElement(g2d,gRect);
				}
			}


			// symbol
			final ElementGroupSymbol groupSymbol = getGroupSymbol( this );
			if( groupSymbol!=null )
			{
				if( groupSymbol.isVisible() )
				{
					groupSymbol.paintElement(g2d,gRect);
				}
			}


		}




		/**
		 * 
		 */
		public boolean paintDataString( final Graphics2D g2d )
		{
			ArrayList tList = this.getTickLabelGroups();
			if( tList.size()!=0 )
			{
				final ElementGroupTickLabels groupString
					= (ElementGroupTickLabels)tList.get(0);
				if( groupString != null )
				{
					if( groupString.isVisible() )
					{
						groupString.paintElement(g2d);
					}
				}
			}

			return true;
		}



		/**
		 * 
		 */
		public void setXAxisConfiguration( final int config )
		{
			this.setXAxis( this.getAxis(config) );
		}

		/**
		 * 
		 */
		public void setYAxisConfiguration( final int config )
		{
			this.setYAxis( this.getAxis(config) );
		}

		private SGAxis getAxis( final int config )
		{
			return mAxisElement.getAxisInPlane( config );
		}


		/**
		 * 
		 */
		public boolean prepare()
		{
			this.mTemporaryProperties = this.getWholeProperties();
			return true;
		}



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


		/**
		 * 
		 */
		public boolean writeProperty( final Element el )
		{
			if( super.writeProperty(el) == false )
			{
				return false;
			}

			// 軸の配置の出力
			final int configX = mAxisElement.getConfigurationInCube( this.getXAxis() );
			final int configY = mAxisElement.getConfigurationInCube( this.getYAxis() );

			final String strX = mAxisElement.getConfigurationString( configX );
			final String strY = mAxisElement.getConfigurationString( configY );

			el.setAttribute( KEY_X_AXIS_POSITION, strX );
			el.setAttribute( KEY_Y_AXIS_POSITION, strY );

			return true;
		}
		

		/**
		 * 
		 * @param e
		 * @param groupSet
		 * @return
		 */
		protected boolean onMouseClicked( final MouseEvent e )
		{
			if( super.onMouseClicked(e) == false )
			{
				return false;
			}

			SGElementGroup group = this.getElementGroupAt( e.getX(), e.getY() );

			int index = -1;
			if( group instanceof ElementGroupLine )
			{
				index = 0;
			}
			else if( group instanceof ElementGroupSymbol )
			{
				index = 1;
			}
			else if( group instanceof ElementGroupBar )
			{
				index = 2;
			}
			else if( group instanceof ElementGroupErrorBar )
			{
				index = 3;
			}
			else if( group instanceof ElementGroupTickLabels )
			{
				index = 4;
			}
			this.mSelectedTabIndex = index;

			return true;
		}


	}



	/**
	 *
	 */
	class ElementGroupLine extends SGElementGroupLine implements IElementGroupInGraph
	{

		private boolean mFocusedFlag = false;


		public void setFocused( final boolean b )
		{
			this.mFocusedFlag = b;
		}

		public boolean isFocused()
		{
			return this.mFocusedFlag;
		}


		/**
		 *
		 */
		protected ElementGroupLine()
		{
			super();
			if( this.init() == false )
			{
				throw new Error();
			}
		}


		/**
		 * 
		 */
		private boolean init()
		{
			this.setVisible( SGDefaultValues.LINE_VISIBLE );
			this.setLineWidth( SGDefaultValues.LINE_WIDTH );
			final Integer n = SGDrawingElementLine.getLineTypeFromName( SGDefaultValues.LINE_TYPE );
			if( n==null )
			{
				return false;
			}
			this.setLineType( n.intValue() );
			this.setColor( SGDefaultValues.LINE_COLOR );

			return true;
		}


		/**
		 * 
		 */
		public boolean setLocation(
			final SGTuple2f[] pointArray )
		{
			return this.setLocation_( pointArray, false );
		}


		/**
		 * 
		 */
		public boolean paintElement( final Graphics2D g2d, final Rectangle2D rect )
		{
			super.paintElement(g2d,rect);

			ElementGroupSetInSXYGraph groupSet
				= (ElementGroupSetInSXYGraph)this.mGroupSet;

			if( this.isFocused() && mSymbolsVisibleFlagAroundFocusedObjects )
			{
				if( !groupSet.isSymbolVisible() && !groupSet.isBarVisible() )
				{
					ArrayList pathList = this.mConnectedPathList;
					for( int ii=0; ii<pathList.size(); ii++ )
					{
						GeneralPath gp = (GeneralPath)pathList.get(ii);

						int num=0;
						ArrayList list = new ArrayList();

						PathIterator itr
							= gp.getPathIterator( new AffineTransform() );
						final float[] array = new float[6];
						itr.currentSegment( array );
						Point2D prev = new Point2D.Float( array[0], array[1] );
						itr.next();

						while( !itr.isDone() )
						{
							itr.currentSegment( array );
							Point2D pos = new Point2D.Float( array[0], array[1] );
							pos.setLocation(
								( prev.getX() + pos.getX() )/2.0,
								( prev.getY() + pos.getY() )/2.0
							);
							prev.setLocation( array[0], array[1] );
							list.add( pos );
							itr.next();
							num++;
						}

						if( num <= MAX_NUMBER_OF_ANCHORS )
						{
							for( int jj=0; jj<num; jj++ )
							{
								Point2D pos = (Point2D)list.get(jj);
								drawAnchorsForFocusedObjects( pos, g2d );
							}
						}
						else
						{
							int div = num/MAX_NUMBER_OF_ANCHORS;
							int cnt = 0;
							while( true )
							{
								Point2D pos = (Point2D)list.get(cnt);
								drawAnchorsForFocusedObjects( pos, g2d );
								cnt += div;
								if( cnt >= num )
								{
									break;
								}
							}
	
						}

					}

				}

			}


			return true;
		}

	}





	/**
	 *
	 */
	class ElementGroupBar extends SGElementGroupBar implements IElementGroupInGraph
	{

		private boolean mFocusedFlag = false;

		public void setFocused( final boolean b )
		{
			this.mFocusedFlag = b;
		}

		public boolean isFocused()
		{
			return this.mFocusedFlag;
		}


		/**
		 *
		 */
		protected ElementGroupBar()
		{
			super();
			if( this.init() == false )
			{
				throw new Error();
			}
		}


		/**
		 * 
		 */
		private boolean init()
		{
			this.setVisible( SGDefaultValues.BAR_VISIBLE );
			this.setBaselineValue( SGDefaultValues.BAR_BASELINE_VALUE );

//			this.setRectangleWidth( SGDefaultValues.BAR_WIDTH );

			this.setColor( SGDefaultValues.BAR_COLOR );
			this.setEdgeLineWidth( SGDefaultValues.BAR_LINE_WIDTH );
			this.setEdgeLineColor( SGDefaultValues.BAR_LINE_COLOR );

			return true;
		}


		/**
		 * 
		 * @return
		 */
		protected boolean initDrawingElement( final int num )
		{
			super.initDrawingElement(num);
			this.setHorizontal(false);
			return true;
		}


		/**
		 * 
		 * @return
		 */
		protected boolean initDrawingElement( final SGTuple2f[] array )
		{
			super.initDrawingElement(array);
			this.setHorizontal(false);
			return true;
		}


		/**
		 * 
		 */
		private float getBaselineLocation( final double baselineValue )
		{
			final SGAxis axis = ((ElementGroupSetInSXYGraph)(this.mGroupSet)).getYAxis();
			return calcLocation( baselineValue, axis, false );
		}



		/**
		 * 
		 */
		public boolean setLocation(
			final SGTuple2f[] pointArray )
		{
			if( this.mDrawingElementArray==null )
			{
				return true;
			}

			// get the location of the baseline
			final float baseline
				= this.getBaselineLocation( this.getBaselineValue() );

			boolean baselineFlag = true;
			if( Float.isInfinite(baseline) | Float.isNaN(baseline) )
			{
				baselineFlag = false;
			}

			// set the bounds of drawing elements
			final float w = this.mMagnification*this.mRectangleWidth;

			SGDrawingElement[] array = this.mDrawingElementArray;
			for( int ii=0; ii<array.length; ii++ )
			{
				final SGDrawingElementBar2D bar = (SGDrawingElementBar2D)array[ii];

				final float x = pointArray[ii].x;
				final float y = pointArray[ii].y;

				if( Float.isInfinite( y ) | Float.isNaN( y ) | !baselineFlag )
				{
					bar.setVisible( false );
					continue;
				}

				final float h = baseline - y;

				bar.setVisible(true);
				bar.setBounds( x, y, w, h );
			}

			return true;
		}



		/**
		 * 
		 */
		public boolean paintElement( final Graphics2D g2d, final Rectangle2D rect )
		{
			super.paintElement(g2d,rect);

			ElementGroupSetInGraph gs = (ElementGroupSetInGraph)this.mGroupSet;
			SGDrawingElement[] array = this.mDrawingElementArray;

			if( this.isFocused() && mSymbolsVisibleFlagAroundFocusedObjects )
			{
				final int num = array.length;
				if( num <= MAX_NUMBER_OF_ANCHORS )
				{
					for( int ii=0; ii<num; ii++ )
					{
						SGDrawingElementBar2D bar
							= (SGDrawingElementBar2D)array[ii];
						emphasisBar( bar, g2d );
					}
				}
				else
				{
					int div = num/MAX_NUMBER_OF_ANCHORS;
					int cnt = 0;
					while( true )
					{
						SGDrawingElementBar2D bar
							= (SGDrawingElementBar2D)array[cnt];
						emphasisBar( bar, g2d );
						cnt += div;
						if( cnt >= num )
						{
							break;
						}
					}
				}
				
			}


			return true;
		}



		/**
		 * 
		 * @param g2d
		 * @param symbol
		 * @return
		 */
		private boolean emphasisBar(
			final SGDrawingElementBar2D bar,
			final Graphics2D g2d )
		{
			drawAnchorsOnRectangle( bar.getElementBounds(), g2d );
			return true;
		}

	}



	/**
	 *
	 */
	class ElementGroupSymbol extends SGElementGroupSymbol implements IElementGroupInGraph
	{

		private boolean mFocusedFlag = false;

		public void setFocused( final boolean b )
		{
			this.mFocusedFlag = b;
		}


		public boolean isFocused()
		{
			return this.mFocusedFlag;
		}


		/**
		 *
		 */
		protected ElementGroupSymbol()
		{
			super();
			if( this.init() == false )
			{
				throw new Error();
			}
		}


		/**
		 * 
		 */
		private boolean init()
		{
			this.setVisible( SGDefaultValues.SYMBOL_VISIBLE );
			Integer n = SGDrawingElementSymbol.getSymbolTypeFromName( SGDefaultValues.SYMBOL_TYPE );
			if( n==null )
			{
				return false;
			}
			this.setType( n.intValue() );
			this.setSize( SGDefaultValues.SYMBOL_SIZE );
			this.setColor( SGDefaultValues.SYMBOL_BODY_COLOR );
			this.setLineWidth( SGDefaultValues.SYMBOL_LINE_WIDTH );
			this.setLineColor( SGDefaultValues.SYMBOL_LINE_COLOR );

			return true;
		}



		/**
		 * 
		 */
		private boolean drawRectangle( final Shape shape, final Graphics2D g2d )
		{

			final Rectangle2D rect = shape.getBounds2D();

			g2d.setPaint(Color.black);
			g2d.setStroke( new BasicStroke(1) );


			final int x = (int)rect.getX();
			final int y = (int)rect.getY();
			final int w = (int)rect.getWidth();
			final int h = (int)rect.getHeight();
			
			g2d.drawRect( x,y,w,h );

			return true;

		}




		/**
		 * 
		 */
		public boolean setLocation(
			final SGTuple2f[] pointArray )
		{
			// nothing to do
			return true;
		}


		/**
		 * 
		 */
		public boolean paintElement( final Graphics2D g2d, final Rectangle2D rect )
		{
			super.paintElement(g2d,rect);

			ElementGroupSetInSXYGraph groupSet
				= (ElementGroupSetInSXYGraph)this.mGroupSet;
			SGDrawingElement[] array = this.mDrawingElementArray;

			if( this.isFocused() && mSymbolsVisibleFlagAroundFocusedObjects )
			{
				if( !groupSet.isBarVisible() )
				{
					final int num = array.length;
					if( num <= MAX_NUMBER_OF_ANCHORS )
					{
						for( int ii=0; ii<num; ii++ )
						{
							SGDrawingElementSymbol2D symbol
								= (SGDrawingElementSymbol2D)array[ii];
							emphasisSymbol( symbol, g2d );
						}
					}
					else
					{
						int div = num/MAX_NUMBER_OF_ANCHORS;
						int cnt = 0;
						while( true )
						{
							SGDrawingElementSymbol2D symbol
								= (SGDrawingElementSymbol2D)array[cnt];
							emphasisSymbol( symbol, g2d );
							cnt += div;
							if( cnt >= num )
							{
								break;
							}
						}
					}
				}

			}


			return true;
		}



		/**
		 * 
		 * @param g2d
		 * @param symbol
		 * @return
		 */
		private boolean emphasisSymbol(
			final SGDrawingElementSymbol2D symbol,
			final Graphics2D g2d )
		{
			drawAnchorsOnRectangle( symbol.getElementBounds(), g2d );
			return true;
		}

	}




	/**
	 *
	 */
	class ElementGroupErrorBar extends SGElementGroupErrorBar implements IElementGroupInGraph
	{

		protected SGTuple2f[] mStartArray = null;
		
		
		protected SGTuple2f[] mEndArray = null;



		private boolean mFocusedFlag = false;


		public void setFocused( final boolean b )
		{
			this.mFocusedFlag = b;
		}

		public boolean isFocused()
		{
			return this.mFocusedFlag;
		}

		/**
		 *
		 */
		protected ElementGroupErrorBar( SGISXYTypeData data )
		{
			super();

			final int num = data.getPointsNumber();
			this.initDrawingElement( num );

			SGTuple2f[] startArray = new SGTuple2f[num];
			SGTuple2f[] endArray = new SGTuple2f[num];
			for( int ii=0; ii<num; ii++ )
			{
				startArray[ii] = new SGTuple2f();
				endArray[ii] = new SGTuple2f();
			}
			this.mStartArray = startArray;
			this.mEndArray = endArray;

			if( this.init() == false )
			{
				throw new Error();
			}

		}



		/**
		 * 
		 */
		private boolean init()
		{
			this.setVisible( SGDefaultValues.ERROR_BAR_VISIBLE );

			this.setLineWidth( SGDefaultValues.ERROR_BAR_LINE_WIDTH );
//			this.setLineType( SGDrawingElementLine.LINE_TYPE_SOLID );

			this.setHeadSize( SGDefaultValues.ERROR_BAR_SYMBOL_SIZE );
			Integer n = SGDrawingElementSymbol.getSymbolTypeFromName( SGDefaultValues.ERROR_BAR_SYMBOL_TYPE );
			if( n==null )
			{
				return false;
			}
			this.setHeadType( n.intValue() );
			this.setLineWidth( SGDefaultValues.ERROR_BAR_LINE_WIDTH );

			Integer style = SGDrawingElementErrorBar.getErrorBarStyleFromName( SGDefaultValues.ERROR_BAR_STYLE );
			if( style==null )
			{
				return false;
			}
			this.setErrorBarStyle( style.intValue() );

			this.setColor( SGDefaultValues.ERROR_BAR_COLOR );

			return true;
		}



		/**
		 * 
		 */
		private boolean calcErrorBarLocation(
			final SGISXYTypeData dataSXY, final SGAxis axisX, final SGAxis axisY,
			final SGTuple2f[] startPointArray, final SGTuple2f[] endPointArray )
		{

			final int num = dataSXY.getPointsNumber();
			final double[] xArray = dataSXY.getXValueArray();
			final double[] yArray = dataSXY.getYValueArray();


			final SGTuple2d[] startArray = new SGTuple2d[num];
			final SGTuple2d[] endArray = new SGTuple2d[num];
			for( int ii=0; ii<num; ii++ )
			{
				startArray[ii] = new SGTuple2d();
				endArray[ii] = new SGTuple2d();
				startArray[ii].x = xArray[ii];
				endArray[ii].x = xArray[ii];
			}

			if( this.mErrorBarStyle == ERROR_BAR_FULL )
			{
				final double[] uArray = dataSXY.getUpperErrorValueArray();
				final double[] lArray = dataSXY.getLowerErrorValueArray();
				for( int ii=0; ii<num; ii++ )
				{
					startArray[ii].y = yArray[ii] + lArray[ii];
					endArray[ii].y = yArray[ii] + uArray[ii];
				}
			}
			else if( this.mErrorBarStyle == ERROR_BAR_UPPER_ONLY )
			{
				final double[] uArray = dataSXY.getUpperErrorValueArray();
				for( int ii=0; ii<num; ii++ )
				{
					startArray[ii].y = yArray[ii];
					endArray[ii].y = yArray[ii] + uArray[ii];
				}
			}
			else if( this.mErrorBarStyle == ERROR_BAR_LOWER_ONLY )
			{
				final double[] lArray = dataSXY.getLowerErrorValueArray();
				for( int ii=0; ii<num; ii++ )
				{
					startArray[ii].y = yArray[ii] + lArray[ii];
					endArray[ii].y = yArray[ii];
				}
			}
			else
			{
				throw new Error();
			}


			calcLocationOfVXYData(
				startArray, endArray,
				axisX, axisY, startPointArray, endPointArray
			);

			return true;
		}


//		/**
//		 * 
//		 */
//		protected ElementGroupProperties getPropertiesFromDialog()
//		{
//			final SGPropertyDialogSXYData dg = (SGPropertyDialogSXYData)mPropertyDialogForData;
//
//			ErrorBarProperties p = dg.getErrorBarProperties();
//
//			return p;
//		}

	
	}






	/**
	 * 
	 */
	class ElementGroupTickLabels extends SGElementGroupTickLabel implements IElementGroupInGraph
	{


		/**
		 * 
		 */
		private SGTuple2f[] mPointsArray = null;


		private boolean mFocusedFlag = false;


		public void setFocused( final boolean b )
		{
			this.mFocusedFlag = b;
		}

		public boolean isFocused()
		{
			return this.mFocusedFlag;
		}


		/**
		 * 
		 */
		protected ElementGroupTickLabels( SGISXYTypeData dataSXY )
		{
			super();

			final int num = dataSXY.getPointsNumber();
			this.initDrawingElement( num );

			SGTuple2f[] pointArray = new SGTuple2f[num];
			for( int ii=0; ii<num; ii++ )
			{
				pointArray[ii] = new SGTuple2f();
			}
			this.mPointsArray = pointArray;

			String[] strArray = dataSXY.getStringArray();
			SGDrawingElementString[] array
				= (SGDrawingElementString[])this.mDrawingElementArray;
			for( int ii=0; ii<num; ii++ )
			{
				SGDrawingElementString el
					= (SGDrawingElementString)array[ii];
				el.setString( strArray[ii] );
			}

			if( this.init() == false )
			{
				throw new Error();
			}

		}


		/**
		 * 
		 */
		private boolean init()
		{
			this.setVisible( SGDefaultValues.TICK_LABEL_VISIBLE );

			this.setFont(
				SGDefaultValues.TICK_LABEL_FONT_NAME,
				SGUtilityText.getFontStyle( SGDefaultValues.TICK_LABEL_FONT_STYLE ),
				SGDefaultValues.TICK_LABEL_FONT_SIZE
			);

			final Float angle = SGElementGroupTickLabel.getTickLabelAngleFromName( SGDefaultValues.TICK_LABEL_ANGLE );
			if( angle==null )
			{
				return false;
			}
			this.setAngle( angle.floatValue() );
			this.setColor( SGDefaultValues.TICK_LABEL_COLOR );

			return true;
		}


		/**
		 * 
		 */
		private boolean drawStringBounds(
			final SGDrawingElementString2DExtended element, final Graphics2D g2d )
		{

			final float strRectLineWidth = 1.0f;
			final Color strRectLineColor = Color.BLACK;
			g2d.setPaint(strRectLineColor);
			g2d.setStroke( new BasicStroke( strRectLineWidth ) );
			final Rectangle2D rect = element.getElementBounds();
			g2d.drawRect(
				(int)rect.getX(),
				(int)rect.getY(),
				(int)rect.getWidth(),
				(int)rect.getHeight()
			);

			return true;

		}



//		/**
//		 * 
//		 */
//		protected ElementGroupProperties getPropertiesFromDialog()
//		{
//
//			final SGPropertyDialogSXYData dg = (SGPropertyDialogSXYData)mPropertyDialogForData;
//
//			StringProperties p = new StringProperties();
//
//			p.setVisible( dg.getTickLabelVisible() );
//			p.setColorList( dg.getTickLabelColorList() );
//			p.setFontName( dg.getTickLabelFontName() );
//
//
//			final Number fontSize = dg.getTickLabelFontSize();
//			if( fontSize==null )
//			{
//				SGUtility.showIllegalInputErrorMessageDialog( mDialogOwner );
//				return null;
//			}
//			p.setFontSize( fontSize.floatValue() );
//
//			final Integer fontStyle = dg.getTickLabelFontStyle();
//			if( fontStyle==null )
//			{
//				SGUtility.showIllegalInputErrorMessageDialog( mDialogOwner );
//				return null;
//			}
//			p.setFontStyle( fontStyle.intValue() );
//
//			final Number angle = dg.getTickLabelAngle();
//			if( angle==null )
//			{
//				SGUtility.showIllegalInputErrorMessageDialog( mDialogOwner );
//				return null;
//			}
//			p.setAngle( angle.floatValue() );
//
//			return p;
//		}


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




		/**
		 * 
		 */
		private boolean calcTickLabelLocation(
			final SGISXYTypeData dataSXY,
			final SGAxis axisX,
			final SGTuple2f[] pointArray )
		{
			final float gx = mGraphRectX;
			final float gy = mGraphRectY;
			final float gw = mGraphRectWidth;
			final float gh = mGraphRectHeight;

			final int config = mAxisElement.getConfigurationInPlane(axisX);

			final float angle = this.getAngle();
			final float space = mAxisElement.getSpaceAxisLineAndNumber()*this.mMagnification;

			final int num = dataSXY.getPointsNumber();
			for( int ii=0; ii<num; ii++ )
			{
				final TickLabelStringElement el
					= (TickLabelStringElement)this.mDrawingElementArray[ii];

				final double xValue = dataSXY.getXValue(ii).doubleValue();

				final float xCenter = calcLocation( xValue, axisX, true );

				Rectangle2D rect = el.getElementBounds();
				final float w = (float)rect.getWidth();
				final float h = (float)rect.getHeight();

				Rectangle2D rect_ = el.getStringRect();
				final float w_ = (float)rect_.getWidth();
				final float h_ = (float)rect_.getHeight();

				float x = 0.0f;
				float y = 0.0f;
				float yDefault = 0.0f;

				// x-coordinates
				if( angle == SGElementGroupTickLabel.ANGLE_HORIZONTAL )
				{
					x = xCenter - 0.50f*w;
				}
				else if( angle == SGElementGroupTickLabel.ANGLE_INCLINED )
				{
					if( config == SGAxisElement.AXIS_HORIZONTAL_1 )
					{
						x = xCenter - w_*( (float)Math.cos(angle) );
					}
					else if( config == SGAxisElement.AXIS_HORIZONTAL_2 )
					{
						x = xCenter - h_*( (float)Math.sin(angle) );
					}
					else
					{
						throw new Error();
					}
				}
				else
				{
					throw new Error();
				}


				// y-cooordinates
				if( config == SGAxisElement.AXIS_HORIZONTAL_1 )
				{
					yDefault = gy + gh + space;
				}
				else if( config == SGAxisElement.AXIS_HORIZONTAL_2 )
				{
					yDefault = gy - space - h;
				}
				else
				{
					throw new Error();
				}

				el.setLocation(	x, yDefault );
				final float yy = (float)el.getElementBounds().getY();
				y = yDefault + ( yDefault - yy );


				// set to variable
				pointArray[ii].setValues( x, y );

//System.out.println(ii+"  "+pointArray[ii]);
			}

//System.out.println();

			return true;

		}



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

			ElementGroupSetInSXYGraph groupSet
				= (ElementGroupSetInSXYGraph)this.mGroupSet;
			SGAxis axisX = groupSet.getXAxis();
			SGISXYTypeData dataSXY = (SGISXYTypeData)getData(groupSet);
//			final SGTuple2d[] valueArray = dataSXY.getValueArray();

			//
			for( int ii=0; ii<pointArray.length; ii++ )
			{
				final double x = dataSXY.getXValue(ii).doubleValue();
				TickLabelStringElement el
					= (TickLabelStringElement)this.mDrawingElementArray[ii];
				el.setVisible( axisX.insideRange( x ) );
			}

			return true;
		}


		
		/**
		 * 
		 */
		public String getTagName()
		{
			return TAG_NAME_TICK_LABELS;
		}


	}




	/**
	 * 
	 */
	public static class TickLabelStringElement extends SGDrawingElementString2DExtended
	{

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

	}



}

