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

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
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 java.util.List;

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.SGIConstants;
import jp.riken.brain.ni.samuraigraph.base.SGIData;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementAxis;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementGraphSXY;
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 jp.riken.brain.ni.samuraigraph.figure.SGElementGroup;
import jp.riken.brain.ni.samuraigraph.figure.SGElementGroupSet;
import jp.riken.brain.ni.samuraigraph.figure.SGIBarConstants;
import jp.riken.brain.ni.samuraigraph.figure.SGIErrorBarConstants;
import jp.riken.brain.ni.samuraigraph.figure.SGILineConstants;
import jp.riken.brain.ni.samuraigraph.figure.SGISXYDataConstants;
import jp.riken.brain.ni.samuraigraph.figure.SGISymbolConstants;
import jp.riken.brain.ni.samuraigraph.figure.SGITickLabelConstants;

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



/**
 * The graph for the two-dimensional scalar-type data.
 * 
 */
public class SGFigureElementGraphSXY extends SGFigureElementGraph
	implements SGIFigureElementGraphSXY, SGISXYDataConstants
{


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



	/**
	 * 
	 */
	protected boolean createDataDialog()
	{

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

		this.mDialog = dg;

		return true;
	}



	/**
	 * 
	 */
	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;
		}

		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,p) == false )
		{
			return false;
		}

		return true;
	}


	//
	protected ElementGroupSetInGraph createGroupSet( SGData data, String name )
	{
		// get axes list
		final SGAxis bAxis = this.mAxisElement.getAxisInPlane( SGIFigureElementAxis.AXIS_HORIZONTAL_1 );
		final SGAxis tAxis = this.mAxisElement.getAxisInPlane( SGIFigureElementAxis.AXIS_HORIZONTAL_2 );
		final SGAxis lAxis = this.mAxisElement.getAxisInPlane( SGIFigureElementAxis.AXIS_PERPENDICULAR_1 );
		final SGAxis rAxis = this.mAxisElement.getAxisInPlane( SGIFigureElementAxis.AXIS_PERPENDICULAR_2 );
		SGAxis axisX = null;
		SGAxis axisY = null;
		if( DEFAULT_SCALE_REFERENCE.equals( SGIFigureElementAxis.LEFT_BOTTOM ) )
		{
			axisX = bAxis;
			axisY = lAxis;
		}
		else if( DEFAULT_SCALE_REFERENCE.equals( SGIFigureElementAxis.LEFT_TOP ) )
		{
			axisX = tAxis;
			axisY = lAxis;
		}
		else if( DEFAULT_SCALE_REFERENCE.equals( SGIFigureElementAxis.RIGHT_BOTTOM ) )
		{
			axisX = bAxis;
			axisY = rAxis;
		}
		else if( DEFAULT_SCALE_REFERENCE.equals( SGIFigureElementAxis.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;
		}

		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();
		groupSet.initPointsArray(num);


		// add drawing element groups of lines, symbols and bars
		if( groupSet.addDrawingElementGroup( SGIElementGroupConstants.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;
			}
		}
		minDiff = this.getNumberInRangeOrder( minDiff, axisX );
		ElementGroupBar groupBar = (ElementGroupBar)groupSet.getBarGroup();
		groupBar.setWidthValue( minDiff );

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

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

		if( groupSet.addDrawingElementGroup( SGIElementGroupConstants.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.updateDrawingElementsLocation( (SGData)data ) == false )
		{
			return null;
		}


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

		return groupSet;
	}



//	/**
//	 * Overrode to notify the change of bar width.
//	 */
//	protected boolean synchronizeToAxisElement(
//		final SGIAxisElement aElement, final String msg )
//	{
//		if( super.synchronizeToAxisElement( aElement, msg ) == false )
//		{
//			return false;
//		}
//
//		this.notifyChange();
//		return true;
//	}


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

		List list = this.mChildList;

		// データ付属文字列の描画
		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 )
		{
			SGUtilityForFigureElementJava2D.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 )
	{
		ArrayList groupList = groupSet.getElementGroupList();
		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 )
	{
		ArrayList groupList = groupSet.getElementGroupList();
		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 )
	{
		ArrayList groupList = groupSet.getElementGroupList();
		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 )
	{

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


		// 各文字列群ごとに、全ての文字列を外包する矩形を取得する
		final ArrayList rectList = new ArrayList();
		for( int ii=0; ii<this.mChildList.size(); ii++ )
		{
			final ElementGroupSetInGraph groupSet
				= (ElementGroupSetInGraph)this.mChildList.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 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;
		}

		// add to the child list
		this.addToList( groupSet );

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

		this.createDataDialog();
		
		return true;
	}


	
	/**
	 * 
	 */
	protected int setDataProperties(
		final Element el, final ElementGroupSetInGraph groupSet, final SGData data )
	{
		final int ic = SGIConstants.PROPERTY_FILE_INCORRECT;

		if( super.setDataProperties( el, groupSet, data ) == ic )
		{
			return ic;
		}

		if( data instanceof SGISXYTypeData )
		{
			SGISXYTypeData data_ = (SGISXYTypeData)data;
			ElementGroupSetInSXYGraph gs = (ElementGroupSetInSXYGraph)groupSet;
			if( this.setPropertyOfElementGroupSetInSXYGraph(el,gs,data_) == ic )
			{
				return ic;
			}
		}
		else if( data instanceof SGISXYTypeMultipleData )
		{
			SGISXYTypeMultipleData data_ = (SGISXYTypeMultipleData)data;
			ElementGroupSetForMultipleDataInSXYGraph gs
				= (ElementGroupSetForMultipleDataInSXYGraph)groupSet;
			if( this.setPropertyOfElementGroupSetForMultipleDataInSXYGraph(el,gs,data_) == ic )
			{
				return ic;
			}
		}

		return SGIConstants.SUCCESSFUL_COMPLETION;
	}

	
	
	/**
	 * 
	 */
	private int setPropertyOfElementGroupSetForMultipleDataInSXYGraph(
		final Element el,
		final ElementGroupSetForMultipleDataInSXYGraph groupSet,
		final SGISXYTypeMultipleData data )
	{

		SGISXYTypeData[] dataArray = data.getSXYDataArray();
		ElementGroupSetInSXYGraph gs = new ElementGroupSetInSXYGraph();

		int ret = this.setDataProperties( el, gs, (SGData)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();
			gs_.initPointsArray(num);

			gs_.updateDrawingElementsLocation( (SGData)dataArray[ii] );
			gs_.addDrawingElementGroup( SGIElementGroupConstants.RECTANGLE_GROUP );
			gs_.addDrawingElementGroup( SGIElementGroupConstants.POLYLINE_GROUP );
			gs_.addDrawingElementGroup( SGIElementGroupConstants.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;
//		SGIFigureElementAxis aElement = this.mAxisElement;
//		String str = null;


		// create instances of the points
		final int num = data.getPointsNumber();
		groupSet.initPointsArray(num);
		

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


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


		// code for the versions older than 0.9.1
		ElementGroupBar groupBar = (ElementGroupBar)group;
		final float rectWidth = groupBar.getRectangleWidth();
		if( rectWidth!=0.0f )
		{
			SGAxis axisX = groupSet.getXAxis();
			final double max = axisX.getMaxValue();
			final double min = axisX.getMinValue();
			final float ratio = rectWidth/this.mGraphRectWidth;
			double value = ( max - min )*ratio;
			value = this.getNumberInRangeOrder( value, axisX );
			groupBar.setWidthValue( value );
		}


		// error bar
		nList = el.getElementsByTagName( SGIErrorBarConstants.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( SGILineConstants.TAG_NAME_LINE );
		if( nList.getLength()!=1 )
		{
			return ic;
		}
		if( groupSet.addDrawingElementGroup( SGIElementGroupConstants.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( SGISymbolConstants.TAG_NAME_SYMBOL );
		if( nList.getLength()!=1 )
		{
			return ic;
		}
		if( groupSet.addDrawingElementGroup( SGIElementGroupConstants.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( SGITickLabelConstants.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;
	}

	
	public void setMode( final int mode )
	{
		super.setMode(mode);
		this.updateAllDrawingElementsLocation();
	}



	//
	private ElementGroupSetInSXYGraph getSXYGroupSet( final int id )
	{
		return (ElementGroupSetInSXYGraph)this.getGroupSet(id);
	}

	public boolean setLineVisibleDirectly( final int id, final boolean value )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setLineVisible( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setLineWidthDirectly( final int id, final float value, final String unit )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setLineWidth( value, unit ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setLineTypeDirectly( final int id, final int value )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setLineType( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setLineColorDirectly( final int id, final Color value )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setLineColor( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}


	public boolean setSymbolVisibleDirectly( final int id, final boolean value )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setSymbolVisible( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setSymbolTypeDirectly( final int id, final int value )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setSymbolType( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setSymbolSizeDirectly( final int id, final float value, final String unit )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setSymbolSize( value, unit ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setSymbolLineWidthDirectly( final int id, final float value, final String unit )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setSymbolLineWidth( value, unit ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setSymbolInnerColorDirectly( final int id, final Color value )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setSymbolInnerColor( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setSymbolLineColorDirectly( final int id, final Color value )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setSymbolLineColor( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}


	public boolean setBarVisibleDirectly( final int id, final boolean value )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setBarVisible( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setBarBaselineDirectly( final int id, final double value )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setBarBaselineValue( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setBarWidthDirectly( final int id, final double value )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setBarWidthValue( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setBarEdgeLineWidthDirectly( final int id, final float value, final String unit )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setBarEdgeLineWidth( value, unit ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setBarInnerColorDirectly( final int id, final Color value )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setBarInnerColor( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setBarLineColorDirectly( final int id, final Color value )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setBarEdgeLineColor( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setErrorBarVisibleDirectly( final int id, final boolean value )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( el.getErrorBarGroup() == null) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setErrorBarVisible( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setErrorBarSymbolTypeDirectly( final int id, final int value )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( el.getErrorBarGroup() == null) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setErrorBarHeadType( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setErrorBarSymbolSizeDirectly( final int id, final float value, final String unit )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( el.getErrorBarGroup() == null) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setErrorBarHeadSize( value, unit ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setErrorBarStyleDirectly( final int id, final int value )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( el.getErrorBarGroup() == null) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setErrorBarStyle( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setErrorBarLineWidthDirectly( final int id, final float value, final String unit )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( el.getErrorBarGroup() == null) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setErrorBarLineWidth( value, unit ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setErrorBarColorDirectly( final int id, final Color value )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( el.getErrorBarGroup() == null) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setErrorBarColor( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setTickLabelVisibleDirectly( final int id, final boolean value )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( el.getTickLabelGroup() == null) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setTickLabelVisible( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setTickLabelFontNameDirectly( final int id, final String value )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( el.getTickLabelGroup() == null) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setTickLabelFontName( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setTickLabelFontStyleDirectly( final int id, final int value )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( el.getTickLabelGroup() == null) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setTickLabelFontStyle( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setTickLabelFontSizeDirectly( final int id, final float value, final String unit )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( el.getTickLabelGroup() == null) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setTickLabelFontSize( value, unit ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setTickLabelFontColorDirectly( final int id, final Color value )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( el.getTickLabelGroup() == null) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setTickLabelColor( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}

	public boolean setTickLabelAngleDirectly( final int id, final boolean value )
	{
		ElementGroupSetInSXYGraph el = this.getSXYGroupSet(id);
		if( el==null ) return false;
		if( el.getTickLabelGroup() == null) return false;
		if( this.setDirectlyBefore(el) == false ) return false;
		if( el.setTickLabelHorizontal( value ) == false ) return false;
		if( this.setDirectlyAfter(el) == false ) return false;
		return true;
	}



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


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

	}




	/**
	 * 
	 */
	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 boolean updateDrawingElementsLocation( final SGIData 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++ )
			{
				ElementGroupSetInGraph gs
					= (ElementGroupSetInGraph)this.mElementGroupSetList.get(ii);
				if( gs.updateDrawingElementsLocation( (SGData)dataSXYArray[ii]) == false )
				{
					return false;
				}
			}

			return true;
		}


		/**
		 * 
		 */
		public Rectangle2D getTickLabelsBoundingBox( final SGIData 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 SGFigureElementGraphSXY.this.mDialog;
		}


		/**
		 * 
		 */
		public boolean setXAxisLocation( final int config )
		{
			if( config!=SGIFigureElementAxis.AXIS_HORIZONTAL_1
				& config!=SGIFigureElementAxis.AXIS_HORIZONTAL_2 )
			{
				return false;
			}
			this.setXAxis( this.getAxis(config) );
			return true;
		}

		/**
		 * 
		 */
		public boolean setYAxisLocation( final int config )
		{
			if( config!=SGIFigureElementAxis.AXIS_PERPENDICULAR_1
				& config!=SGIFigureElementAxis.AXIS_PERPENDICULAR_2 )
			{
				return false;
			}
			this.setYAxis( this.getAxis(config) );
			return true;
		}

		private SGAxis getAxis( final int config )
		{
			return SGFigureElementGraphSXY.this.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 = SGFigureElementGraphSXY.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;
			
			if( this.setProperties( wp.getElementGroupSetProperties() ) == false ) return false;
			
			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();

			// drawing elements
			ArrayList list = groupSet.getElementGroupList();
			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;
			}

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

			// axes
			final String strX = SGFigureElementGraphSXY.this.mAxisElement.getLocationName( groupSet.getXAxis() );
			final String strY = SGFigureElementGraphSXY.this.mAxisElement.getLocationName( groupSet.getYAxis() );
			el.setAttribute( KEY_X_AXIS_POSITION, strX );
			el.setAttribute( KEY_Y_AXIS_POSITION, strY );
			
			// write sampling rate
			if( data instanceof SGSXYSamplingData )
			{
				final double rate = this.getSamplingRate();
				el.setAttribute( KEY_SAMPLING_RATE, Double.toString(rate) );
			}

			return true;
		}



		// Line
		
		public boolean isLineVisible()
		{
			return this.getLineGroup().isVisible();
		}
		
		public float getLineWidth()
		{
			return this.getLineGroup().getLineWidth();
		}
		
		public float getLineWidth( final String unit )
		{
			return (float)SGUtilityText.convertFromPoint( this.getLineWidth(), unit );
		}

		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 setLineWidth( final float width, final String unit )
		{
			ArrayList list = this.getLineGroups();
			final float value = (float)SGUtilityText.convertToPoint( width, unit );
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupLine group = (ElementGroupLine)list.get(ii);
				group.setLineWidth(value);
			}
			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 getSymbolSize( final String unit )
		{
			return (float)SGUtilityText.convertFromPoint( this.getSymbolSize(), unit );
		}

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

		public float getSymbolLineWidth( final String unit )
		{
			return (float)SGUtilityText.convertFromPoint( this.getSymbolLineWidth(), unit );
		}

		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 setSymbolSize( final float size, final String unit )
		{
			ArrayList list = this.getSymbolGroups();
			final float value = (float)SGUtilityText.convertToPoint( size, unit );
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupSymbol group = (ElementGroupSymbol)list.get(ii);
				group.setSize(value);
			}
			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 setSymbolLineWidth( final float width, final String unit )
		{
			ArrayList list = this.getSymbolGroups();
			final float value = (float)SGUtilityText.convertToPoint( width, unit );
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupSymbol group = (ElementGroupSymbol)list.get(ii);
				group.setLineWidth(value);
			}
			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 double getBarWidthValue()
		{
			return this.getBarGroup().getWidthValue();
		}

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

		public float getBarEdgeLineWidth( final String unit )
		{
			return (float)SGUtilityText.convertFromPoint( this.getBarEdgeLineWidth(), unit );
		}

		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 setBarWidthValue( final double value )
		{
			ArrayList list = this.getBarGroups();
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupBar group = (ElementGroupBar)list.get(ii);
				group.setWidthValue(value);
			}
			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 setBarEdgeLineWidth( final float width, final String unit )
		{
			ArrayList list = this.getBarGroups();
			final float value = (float)SGUtilityText.convertToPoint( width, unit );
			for( int ii=0; ii<list.size(); ii++ )
			{
				ElementGroupBar group = (ElementGroupBar)list.get(ii);
				group.setEdgeLineWidth(value);
			}
			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;
		}

		public boolean hasValidBaselineValue( final int config, final Number value )
		{
			return this.getFirst().hasValidBaselineValue( config, value );
		}


		// 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 float getErrorBarHeadSize( final String unit )
		{
			return (float)SGUtilityText.convertFromPoint( this.getErrorBarHeadSize(), unit );
		}

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

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

		public float getErrorBarLineWidth( final String unit )
		{
			return (float)SGUtilityText.convertFromPoint( this.getErrorBarLineWidth(), unit );
		}

		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 setErrorBarHeadSize( final float size, final String unit )
		{
			return true;
		}

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

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

		public boolean setErrorBarLineWidth( final float width, final String unit )
		{
			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 float getTickLabelFontSize( final String unit )
		{
			return (float)SGUtilityText.convertFromPoint( this.getTickLabelFontSize(), unit );
		}

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

		public boolean isTickLabelHorizontal()
		{
			return (this.getTickLabelGroup().getAngle()==SGITickLabelConstants.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 setTickLabelFontSize( final float size, final String unit )
		{
			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 getXAxisLocation()
		{
			return this.getFirst().getXAxisLocation();
		}


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

		
		/**
		 * 
		 */
		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;
		}

	}




	/**
	 * @author  okumura
	 */
	class ElementGroupSetInSXYGraph extends ElementGroupSetInGraph
		implements IElementGroupSetInSXYGraph, SGISXYDataDialogObserver
	{

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


		/**
		 * 
		 */
		public void dispose()
		{
			super.dispose();

			this.mPointsArray = null;
		}


		/**
		 * 
		 * @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 getXAxisLocation()
		{
			return SGFigureElementGraphSXY.this.mAxisElement.getLocationInPlane( this.getXAxis() );
		}


		/**
		 * 
		 */
		public int getYAxisLocation()
		{
			return SGFigureElementGraphSXY.this.mAxisElement.getLocationInPlane( 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 float getLineWidth( final String unit )
		{
			return this.getLineGroup().getLineWidth( unit );
		}
		
		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, final String unit )
		{
			final double conv = SGUtilityText.convert( width, unit, LINE_WIDTH_UNIT );
			if( conv < LINE_WIDTH_MIN_VALUE ) return false;
			if( conv > LINE_WIDTH_MAX_VALUE ) return false;

			return this.getLineGroup().setLineWidth(  (float)SGUtilityText.convertToPoint( width, unit )  );
		}

		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 getSymbolSize( final String unit )
		{
			return this.getSymbolGroup().getSize( unit );
		}

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

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

		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, final String unit )
		{
			final double conv = SGUtilityText.convert( size, unit, SYMBOL_SIZE_UNIT );
			if( conv < SYMBOL_SIZE_MIN ) return false;
			if( conv > SYMBOL_SIZE_MAX ) return false;

			return this.getSymbolGroup().setSize( (float)SGUtilityText.convertToPoint( size, unit ) );
		}

		public boolean setSymbolLineWidth( final float width, final String unit )
		{
			final double conv = SGUtilityText.convert( width, unit, LINE_WIDTH_UNIT );
			if( conv < LINE_WIDTH_MIN_VALUE ) return false;
			if( conv > LINE_WIDTH_MAX_VALUE ) return false;

			return this.getSymbolGroup().setLineWidth( (float)SGUtilityText.convertToPoint( width, unit ) );
		}

		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 double getBarWidthValue()
		{
			return this.getBarGroup().getWidthValue();
		}

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

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

		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 setBarWidthValue( final double value )
		{
			return this.getBarGroup().setWidthValue( value );
		}

		public boolean setBarEdgeLineWidth( final float width, final String unit )
		{
			final double conv = SGUtilityText.convert( width, unit, LINE_WIDTH_UNIT );
			if( conv < LINE_WIDTH_MIN_VALUE ) return false;
			if( conv > LINE_WIDTH_MAX_VALUE ) return false;

			return this.getBarGroup().setEdgeLineWidth( (float)SGUtilityText.convertToPoint( width, unit ) );
		}

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

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

		public boolean hasValidBaselineValue( final int config, final Number value )
		{
			final SGAxis axis = (config==-1) ? this.mYAxis : SGFigureElementGraphSXY.this.mAxisElement.getAxisInPlane( config );
			final double v = (value!=null) ? value.doubleValue() : this.getBarBaselineValue();
			return axis.isValidValue(v);
		}


		// 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 float getErrorBarHeadSize( final String unit )
		{
			return this.getErrorBarGroup().getHeadSize( unit );
		}

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

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

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

		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 )
		{
			return this.getErrorBarGroup().setHeadType( type );
		}

		public boolean setErrorBarHeadSize( final float size, final String unit )
		{
			final double conv = SGUtilityText.convert( size, unit, ERROR_BAR_HEAD_SIZE_UNIT );
			if( conv < ERROR_BAR_HEAD_SIZE_MIN ) return false;
			if( conv > ERROR_BAR_HEAD_SIZE_MAX ) return false;

			return this.getErrorBarGroup().setHeadSize( (float)SGUtilityText.convertToPoint( size, unit ) );
		}

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

		public boolean setErrorBarLineWidth( final float width, final String unit )
		{
			final double conv = SGUtilityText.convert( width, unit, LINE_WIDTH_UNIT );
			if( conv < LINE_WIDTH_MIN_VALUE ) return false;
			if( conv > LINE_WIDTH_MAX_VALUE ) return false;

			return this.getErrorBarGroup().setLineWidth( (float)SGUtilityText.convertToPoint( width, unit ) );
		}

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



		// 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 float getTickLabelFontSize( final String unit )
		{
			return this.getTickLabelGroup().getFontSize( unit );
		}

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

		public boolean isTickLabelHorizontal()
		{
			return (this.getTickLabelGroup().getAngle()==SGITickLabelConstants.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, final String unit )
		{
			final double conv = SGUtilityText.convert( size, unit, FONT_SIZE_UNIT );
			if( conv < FONT_SIZE_MIN_VALUE ) return false;
			if( conv > FONT_SIZE_MAX_VALUE ) return false;

			return this.getTickLabelGroup().setFontSize( (float)SGUtilityText.convertToPoint( size, unit ) );
		}

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

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


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

			SGElementGroupSXY group = null;
			if( type == SGIElementGroupConstants.POLYLINE_GROUP )
			{
				group = new ElementGroupLine();
			}
			else if( type == SGIElementGroupConstants.RECTANGLE_GROUP )
			{
				group = new ElementGroupBar();
			}
			else if( type == SGIElementGroupConstants.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;
		}



		/**
		 * @uml.property  name="mPointsArray"
		 * @uml.associationEnd  multiplicity="(0 -1)"
		 */
		private SGTuple2f[] mPointsArray = null;


		private void initPointsArray( final int num )
		{
			SGTuple2f[] pointsArray = new SGTuple2f[num];
			for( int ii=0; ii<num; ii++ )
			{
				pointsArray[ii] = new SGTuple2f();
			}
			this.mPointsArray = pointsArray;
		}


		/**
		 * Called when the location of data points have changed.
		 */
		public boolean updateDrawingElementsLocation( final SGIData 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( calcLocationOfPoints(
				dataSXY.getXValueArray(),
				dataSXY.getYValueArray(),
				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 )
		{

			// set the group set
			IElementGroupInGraph iGroup = (IElementGroupInGraph)group;
			iGroup.setElementGroupSet(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 SGIData 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.getDrawingElementArray();
			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 boolean setXAxisLocation( final int config )
		{
			if( config!=SGIFigureElementAxis.AXIS_HORIZONTAL_1
				& config!=SGIFigureElementAxis.AXIS_HORIZONTAL_2 )
			{
				return false;
			}
			return this.setXAxis( this.getAxis(config) );
		}

		/**
		 * 
		 */
		public boolean setYAxisLocation( final int config )
		{
			if( config!=SGIFigureElementAxis.AXIS_PERPENDICULAR_1
				& config!=SGIFigureElementAxis.AXIS_PERPENDICULAR_2 )
			{
				return false;
			}
			return this.setYAxis( this.getAxis(config) );
		}

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


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



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


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

			final String strX = SGFigureElementGraphSXY.this.mAxisElement.getLocationName( this.getXAxis() );
			final String strY = SGFigureElementGraphSXY.this.mAxisElement.getLocationName( this.getYAxis() );

			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;
		}


	}



	/**
	 * @author  okumura
	 */
	private class ElementGroupLine extends SGElementGroupLine
		implements IElementGroupInGraph
	{

		protected ElementGroupSetInGraph mGroupSet = null;
		public boolean setElementGroupSet( ElementGroupSetInGraph gs )
		{
			this.mGroupSet = gs;
			return true;
		}


		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( DEFAULT_LINE_VISIBLE );
			this.setLineWidth( DEFAULT_LINE_WIDTH, LINE_WIDTH_UNIT );
			this.setLineType( DEFAULT_LINE_TYPE );
			this.setColor( DEFAULT_LINE_COLOR );

			return true;
		}


		/**
		 * 
		 */
		public boolean setLineWidth( final float width, final String unit )
		{
			if( width < LINE_WIDTH_MIN_VALUE ) return false;
			if( width > LINE_WIDTH_MAX_VALUE ) return false;

			return super.setLineWidth( width, unit );
		}


		/**
		 * 
		 */
		public boolean writeProperty( final Element el )
		{
			if( super.writeProperty(el) == false )
			{
				return false;
			}
			el.setAttribute( KEY_VISIBLE, Boolean.toString( this.mVisibleFlag ) );
			return true;
		}


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

			return SGFigureElementGraphSXY.this.readProperty( this, el );
		}


		/**
		 * 
		 */
		public boolean setLocation(
			final SGTuple2f[] pointArray )
		{
			final int mode = SGFigureElementGraphSXY.this.getMode();
			if( mode == MODE_EXPORT_AS_IMAGE )
			{
				this.mMode = MODE_ALL;
			}
			else if( mode == MODE_DISPLAY )
			{
				this.mMode = MODE_OMIT;
			}
			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() && SGFigureElementGraphSXY.this.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;
		}

	}





	/**
	 * @author  okumura
	 */
	private class ElementGroupBar extends SGElementGroupBar implements IElementGroupInGraph
	{
		protected ElementGroupSetInGraph mGroupSet = null;

		public boolean setElementGroupSet( ElementGroupSetInGraph gs )
		{
			this.mGroupSet = gs;
			return true;
		}


		private boolean mFocusedFlag = false;

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

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


		/**
		 *
		 */
		protected ElementGroupBar()
		{
			super();
			this.init();
		}


		/**
		 * 
		 */
		private void init()
		{
			this.setVisible( DEFAULT_BAR_VISIBLE );
			this.setBaselineValue( DEFAULT_BAR_BASELINE_VALUE );
			this.setColor( DEFAULT_BAR_COLOR );
			this.setEdgeLineWidth( DEFAULT_BAR_EDGE_LINE_WIDTH, LINE_WIDTH_UNIT );
			this.setEdgeLineColor( DEFAULT_BAR_EDGE_LINE_COLOR );
		}


		/**
		 * 
		 * @return
		 */
		public 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;
		}


		/**
		 * 
		 */
		public boolean setEdgeLineWidth( final float width, final String unit )
		{
			if( width < LINE_WIDTH_MIN_VALUE ) return false;
			if( width > LINE_WIDTH_MAX_VALUE ) return false;

			return super.setEdgeLineWidth( width, unit );
		}


		/**
		 * 
		 */
		public boolean writeProperty( final Element el )
		{
			if( super.writeProperty(el) == false )
			{
				return false;
			}
			el.setAttribute( KEY_VISIBLE, Boolean.toString( this.mVisibleFlag ) );
			return true;
		}


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

			return SGFigureElementGraphSXY.this.readProperty( this, el );
		}


		/**
		 * 
		 */
		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 ElementGroupSetInSXYGraph gs
				= (ElementGroupSetInSXYGraph)this.mGroupSet;
			final SGAxis xAxis = gs.getXAxis();
			final double xMin = xAxis.getMinValue();
			final double xMax = xAxis.getMaxValue();
			final float w = SGFigureElementGraphSXY.this.mGraphRectWidth*(float)( this.getWidthValue()/( xMax - xMin ) );
			this.setRectangleWidth(w);

			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() && SGFigureElementGraphSXY.this.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;
		}

	}



	/**
	 * @author  okumura
	 */
	private class ElementGroupSymbol extends SGElementGroupSymbol implements IElementGroupInGraph
	{
		protected ElementGroupSetInGraph mGroupSet = null;
		public boolean setElementGroupSet( ElementGroupSetInGraph gs )
		{
			this.mGroupSet = gs;
			return true;
		}

		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( DEFAULT_SYMBOL_VISIBLE );
			this.setType( DEFAULT_SYMBOL_TYPE );
			this.setSize( DEFAULT_SYMBOL_SIZE, SYMBOL_SIZE_UNIT );
			this.setColor( DEFAULT_SYMBOL_BODY_COLOR );
			this.setLineWidth( DEFAULT_SYMBOL_LINE_WIDTH, LINE_WIDTH_UNIT );
			this.setLineColor( DEFAULT_SYMBOL_LINE_COLOR );

			return true;
		}


		/**
		 * 
		 */
		public boolean setLineWidth( final float width, final String unit )
		{
			if( width < LINE_WIDTH_MIN_VALUE ) return false;
			if( width > LINE_WIDTH_MAX_VALUE ) return false;

			return super.setLineWidth( width, unit );
		}


		/**
		 * 
		 */
		public boolean setSize( final float size, final String unit )
		{
			if( size < SYMBOL_SIZE_MIN ) return false;
			if( size > SYMBOL_SIZE_MAX ) return false;

			return super.setSize( size, unit );
		}


		/**
		 * 
		 */
		public boolean writeProperty( final Element el )
		{
			if( super.writeProperty(el) == false )
			{
				return false;
			}
			el.setAttribute( KEY_VISIBLE, Boolean.toString( this.mVisibleFlag ) );
			return true;
		}


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

			return SGFigureElementGraphSXY.this.readProperty( this, el );
		}


//		/**
//		 * 
//		 */
//		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() && SGFigureElementGraphSXY.this.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;
		}

	}




	/**
	 * @author  okumura
	 */
	private class ElementGroupErrorBar extends SGElementGroupErrorBar
		implements IElementGroupInGraph
	{
		protected ElementGroupSetInGraph mGroupSet = null;
		public boolean setElementGroupSet( ElementGroupSetInGraph gs )
		{
			this.mGroupSet = gs;
			return true;
		}

		// location of start points and end points
		/**
		 * @uml.property  name="mStartArray"
		 * @uml.associationEnd  multiplicity="(0 -1)"
		 */
		private SGTuple2f[] mStartArray = null;
		/**
		 * @uml.property  name="mEndArray"
		 * @uml.associationEnd  multiplicity="(0 -1)"
		 */
		private 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();
			}

		}


		/**
		 * 
		 */
		public void dispose()
		{
			super.dispose();
			this.mStartArray = null;
			this.mEndArray = null;
		}


		/**
		 * 
		 */
		private boolean init()
		{
			this.setVisible( DEFAULT_ERROR_BAR_VISIBLE );
			this.setLineWidth( DEFAULT_ERROR_BAR_LINE_WIDTH, LINE_WIDTH_UNIT );
			this.setHeadSize( DEFAULT_ERROR_BAR_SYMBOL_SIZE, ERROR_BAR_HEAD_SIZE_UNIT );
			this.setHeadType( DEFAULT_ERROR_BAR_SYMBOL_TYPE );
			this.setErrorBarStyle( DEFAULT_ERROR_BAR_STYLE );
			this.setColor( DEFAULT_ERROR_BAR_COLOR );

			return true;
		}


		/**
		 * 
		 */
		public boolean setLineWidth( final float width, final String unit )
		{
			if( width < LINE_WIDTH_MIN_VALUE ) return false;
			if( width > LINE_WIDTH_MAX_VALUE ) return false;

			return super.setLineWidth( width, unit );
		}


		/**
		 * 
		 */
		public boolean writeProperty( final Element el )
		{
			if( super.writeProperty(el) == false )
			{
				return false;
			}
			el.setAttribute( KEY_VISIBLE, Boolean.toString( this.mVisibleFlag ) );
			return true;
		}


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

			return SGFigureElementGraphSXY.this.readProperty( this, el );
		}


		/**
		 * 
		 */
		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_BOTHSIDES )
			{
				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_UPSIDE )
			{
				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_DOWNSIDE )
			{
				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();
			}


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

			return true;
		}

	}



	/**
	 * @author  okumura
	 */
	private class ElementGroupTickLabels extends SGElementGroupTickLabel
		implements IElementGroupInGraph
	{
		protected ElementGroupSetInGraph mGroupSet = null;
		public boolean setElementGroupSet( ElementGroupSetInGraph gs )
		{
			this.mGroupSet = gs;
			return true;
		}


		/**
		 * @uml.property  name="mPointsArray"
		 * @uml.associationEnd  multiplicity="(0 -1)"
		 */
		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();
			SGDrawingElement[] array = 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( DEFAULT_TICK_LABEL_VISIBLE );

			this.setFontSize( DEFAULT_TICK_LABEL_FONT_SIZE, FONT_SIZE_UNIT );
			this.setFontName( DEFAULT_TICK_LABEL_FONT_NAME );
			this.setFontStyle( DEFAULT_TICK_LABEL_FONT_STYLE );
			this.setAngle( DEFAULT_TICK_LABEL_ANGLE );
			this.setColor( DEFAULT_TICK_LABEL_FONT_COLOR );

			return true;
		}


		/**
		 * 
		 */
		protected SGDrawingElement createDrawingElementInstance()
		{
			return new TickLabelStringElement();
		}

		/**
		 * 
		 */
		public void dispose()
		{
			super.dispose();
			this.mPointsArray = null;
		}


//		/**
//		 * 
//		 */
//		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;
//
//		}


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

			final int config = SGFigureElementGraphSXY.this.mAxisElement.getLocationInPlane(axisX);

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

			final int num = dataSXY.getPointsNumber();
	
			// calcurate baseline height 
			float maxascent = 0.0f;
			float maxdescent = 0.0f;
			for( int ii=0; ii<num; ii++ )
			{
				final TickLabelStringElement el
					= (TickLabelStringElement)this.mDrawingElementArray[ii];
				final float a = el.getAscent();
				final float b = el.getDescent();
				if(a > maxascent) maxascent = a;
				if(b > maxdescent) maxdescent = b;
			}
			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 == SGITickLabelConstants.ANGLE_HORIZONTAL )
				{
					x = xCenter - 0.50f*w;
				}
				else if( angle == SGITickLabelConstants.ANGLE_INCLINED )
				{
					if( config == SGIFigureElementAxis.AXIS_HORIZONTAL_1 )
					{
						x = xCenter - w_*( (float)Math.cos(angle) );
					}
					else if( config == SGIFigureElementAxis.AXIS_HORIZONTAL_2 )
					{
						x = xCenter - h_*( (float)Math.sin(angle) );
					}
					else
					{
						throw new Error();
					}
				}
				else
				{
					throw new Error();
				}


				// y-cooordinates
				if( config == SGIFigureElementAxis.AXIS_HORIZONTAL_1 )
				{
					if( angle == SGITickLabelConstants.ANGLE_HORIZONTAL )
					{
						yDefault = maxascent - el.getAscent();
					}
					yDefault += gy + gh + space;
				}
				else if( config == SGIFigureElementAxis.AXIS_HORIZONTAL_2 )
				{
					if( angle == SGITickLabelConstants.ANGLE_HORIZONTAL )
					{
						yDefault = - maxdescent + el.getDescent();
					}
					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 );

			}

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

			if( dataSXY!=null )
			{
				//
				final double[] xArray = dataSXY.getXValueArray();
				for( int ii=0; ii<pointArray.length; ii++ )
				{
					TickLabelStringElement el
						= (TickLabelStringElement)this.mDrawingElementArray[ii];
					el.setVisible( axisX.insideRange( xArray[ii] ) );
				}
			}

			return true;
		}


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


		/**
		 * 
		 */
		public boolean writeProperty( final Element el )
		{
			if( super.writeProperty(el) == false )
			{
				return false;
			}
			el.setAttribute( KEY_VISIBLE, Boolean.toString( this.mVisibleFlag ) );
			return true;
		}


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

			return SGFigureElementGraphSXY.this.readProperty( this, el );
		}

	}



	/**
	 * 
	 */
	private static class TickLabelStringElement extends SGDrawingElementString2DExtended
	{
		protected TickLabelStringElement()
		{
			super();
		}
	}


}

