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

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

import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;

import jp.riken.brain.ni.samuraigraph.base.SGAxis;
import jp.riken.brain.ni.samuraigraph.base.SGData;
import jp.riken.brain.ni.samuraigraph.base.SGDefaultValues;
import jp.riken.brain.ni.samuraigraph.base.SGDrawingElement;
import jp.riken.brain.ni.samuraigraph.base.SGIAxisElement;
import jp.riken.brain.ni.samuraigraph.base.SGIConstants;
import jp.riken.brain.ni.samuraigraph.base.SGILegendElement;
import jp.riken.brain.ni.samuraigraph.base.SGProperties;
import jp.riken.brain.ni.samuraigraph.base.SGPropertyDialog;
import jp.riken.brain.ni.samuraigraph.base.SGTuple2d;
import jp.riken.brain.ni.samuraigraph.base.SGTuple2f;
import jp.riken.brain.ni.samuraigraph.base.SGUtility;
import jp.riken.brain.ni.samuraigraph.base.SGUtilityText;
import jp.riken.brain.ni.samuraigraph.data.SGDataTypeConstants;
import jp.riken.brain.ni.samuraigraph.data.SGSXYData;
import jp.riken.brain.ni.samuraigraph.data.SGSXYMultipleData;
import jp.riken.brain.ni.samuraigraph.data.SGSXYSamplingData;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementLine;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementRectangle;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementString;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementSymbol;

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



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


//	public static final String KEY_X_AXIS_POSITION = "XAxisPosition";
//	public static final String KEY_Y_AXIS_POSITION = "YAxisPosition";

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



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

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

		mPropertyDialogForData = dg;

		return true;
	}



	/**
	 *
	 */
	public boolean addData( final SGData data )
	{
		// set the name of data
		final String name = "data"+(this.mGroupSetList.size()+1);

		this.addData( data, name );
		
		return true;
	}



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


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


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


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

		//
		groupSet.initPropertiesHistory();

		//
		this.mGroupSetList.add( groupSet );


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

		return true;
	}



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

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


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


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


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

		//
		this.mGroupSetList.add( groupSet );


		if( groupSet.setWholeProperties(p) == false )
		{
			throw new Error();
		}

		// set visible because the cut data is set to be invisible
		groupSet.setVisible(true);

		// set name because the given property object has the old name
		groupSet.setName(name);

		//
		groupSet.initPropertiesHistory();


		if( this.setAllDrawingElementsLocation() == false )
		{
			return false;
		}

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

		return true;
	}



	/**
	 * 
	 */
	private ElementGroupSetForMultipleData createMultipleGroupSet(
		final SGSXYMultipleData 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);
	

		//
		SGSXYData[] 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 SGSXYData 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 SGSXYData data, final SGAxis axisX, final SGAxis axisY )
	{

		final ElementGroupSetInSXYGraph groupSet
			= new ElementGroupSetInSXYGraph();


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


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


		// add drawing element groups of lines, symbols and bars
		if( groupSet.addDrawingElementGroup( SGElementGroup.POLYLINE_GROUP ) == false )
		{
			throw new Error();
		}
		if( groupSet.addDrawingElementGroup( SGElementGroup.SYMBOL_GROUP ) == false )
		{
			throw new Error();
		}
		if( groupSet.addDrawingElementGroup( SGElementGroup.RECTANGLE_GROUP ) == false )
		{
			throw new Error();
		}


		// create error bar instance
		if( data.isErrorValueHolding() )
		{
			ElementGroupErrorBar errorBar
				= this.createErrorBar( groupSet, data );

			if( errorBar == null )
			{
				throw new Error();
			}

			if( errorBar.setPropertiesOfDrawingElements() == false )
			{
				throw new Error();
			}

		}


		// create tick label instance
		if( data.isStringArrayHolding() )
		{
			if( this.createTickLabels( groupSet, data ) == null )
			{
				throw new Error();
			}
		}


		// set the location of the drawing elements of data
		if( groupSet.setDrawingElementsLocation( data ) == false )
		{
			throw new Error();
		}


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

		return groupSet;
	}




	/**
	 * 
	 */
	private ElementGroupTickLabelStringElement createTickLabels(
		ElementGroupSetInSXYGraph groupSet, SGSXYData dataSXY )
	{

		final ElementGroupTickLabelStringElement sGroup
			= new ElementGroupTickLabelStringElement();
		groupSet.mTickLabels = sGroup;
		sGroup.mGroupSet = groupSet;

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

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

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

		if( sGroup.setPropertiesOfDrawingElements() == false )
		{
			throw new Error();
		}

		return sGroup;
	}




	/**
	 * 
	 */
	private ElementGroupErrorBar createErrorBar(
		final ElementGroupSetInSXYGraph groupSet,
		final SGSXYData dataSXY )
	{

		final ElementGroupErrorBar eGroup
			= new ElementGroupErrorBar();
		groupSet.mErrorBarGroup = eGroup;
		eGroup.mGroupSet = groupSet;

		eGroup.setMagnification( this.mMagnification );

		final int num = dataSXY.getPointsNumber();
		eGroup.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();
		}
		eGroup.mStartArray = startArray;
		eGroup.mEndArray = endArray;


		return eGroup;
	}





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

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

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

		p.addSeparator();

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

		p.addSeparator();

		SGUtility.addItem( p, groupSet, MENUCMD_DELETE );

		p.addSeparator();

		SGUtility.addItem( p, groupSet, MENUCMD_PROPERTY );

		return p;
	}




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

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


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

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

			boolean diffFlag = false;

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

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



			// drawing element of data
			ArrayList sList = element.getDrawingElementList(data);

			ArrayList elList = new ArrayList();
			for( int jj=sList.size()-1; jj>=0; jj-- )
			{
				SGDrawingElement el = (SGDrawingElement)sList.get(jj);
				ArrayList lList = groupSet.mDrawingElementGroupList;
				SGElementGroup group = (SGElementGroup)lList.remove(jj);
				SGDrawingElement elOld = group.getDrawingElement();
				SGProperties p = el.getProperties();
				SGProperties pOld = elOld.getProperties();
				if( p.equals(pOld) == false )
				{
					diffFlag = true;
				}
				elList.add(el);
			}
			for( int jj=elList.size()-1; jj>=0; jj-- )
			{
				SGDrawingElement el = (SGDrawingElement)elList.get(jj);
				groupSet.addDrawingElementGroup(el);
			}


			// add to the group-set list
			mGroupSetList.set( ii, groupSet );


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


		}


		this.setAllDrawingElementsLocation();
		this.repaint();

		return flag;
	}



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

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


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


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

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

	}






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

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

		return null;
	}


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

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

		return null;
	}


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

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

		return null;
	}



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

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


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

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

			rectList.add(rectAll);
		}


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


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


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


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

		return true;

	}



	/**
	 * 全描画要素の位置を決定
	 */
	protected boolean setAllDrawingElementsLocation()
	{
//System.out.println("<< SGSXYGraphElement::setAllDrawingElementsLocation >>");

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

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

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

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


		return true;

	}




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

		if( data instanceof SGSXYData )
		{
			groupSet = new ElementGroupSetInSXYGraph();
		}
		else if( data instanceof SGSXYMultipleData )
		{
			groupSet = new ElementGroupSetForMultipleDataInSXYGraph();
		}

		return groupSet;
	}

	

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

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

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


		//
		this.mGroupSetList.add( groupSet );

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


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

		return ret;
	}

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

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

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

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

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

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

			gs_.initPropertiesHistory();

			gsList.add(gs_);
		}
		

		groupSet.mElementGroupSetList = new ArrayList( gsList );
		groupSet.mName = new String( gs.getName() );

		groupSet.initPropertiesHistory();


		return SGIConstants.SUCCESSFUL_COMPLETION;
	}

	

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

		final int ic = SGIConstants.PROPERTY_FILE_INCORRECT;
		String str = null;


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


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


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


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


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

		

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

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

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

		
		// error bar
		nList = el.getElementsByTagName( SGElementGroupErrorBar.TAG_NAME_ERROR_BAR );
		if( nList.getLength()==1 )
		{
			Element errorBar = (Element)nList.item(0);

			// 読み込まれたデータがエラーバー情報を持っているとは限らない！
			// 持っている場合には以下の処理を行う
			if( data.isErrorValueHolding() )
			{
				ElementGroupErrorBar eGroup
					= this.createErrorBar( groupSet, data );

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

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

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

			}
			else
			{
				ElementGroupErrorBar eGroup = new ElementGroupErrorBar();
				if( eGroup.readProperty(errorBar) == false )
				{
					return ic;
				}
			}
		
		}
		else if( nList.getLength()==0 )
		{
			// 読み込まれたデータがエラーバー情報を持っていないとは限らない！
			// 持っている場合には以下の処理を行う
			if( data.isErrorValueHolding() )
			{
				ElementGroupErrorBar eGroup = this.createErrorBar( groupSet, data );
				if( eGroup==null )
				{
					return ic;
				}
				if( eGroup.setPropertiesOfDrawingElements() == false )
				{
					return ic;
				}
			}
		}
		else
		{
			return ic;
		}
		
		
		// tick label
		nList = el.getElementsByTagName( SGElementGroupTickLabel.TAG_NAME_TICK_LABELS );
		if( nList.getLength()==1 )
		{
			Element tickLabel = (Element)nList.item(0);

			// 読み込まれたデータがデータ文字列情報を持っているとは限らない！
			if( data.isStringArrayHolding() )
			{
				ElementGroupTickLabelStringElement tGroup
					= this.createTickLabels( groupSet, data );
				if( tGroup.readProperty(tickLabel) == false )
				{
					return ic;
				}

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

				tGroup.setLocation( tGroup.mPointsArray );
			}
			else
			{
				ElementGroupTickLabelStringElement tGroup
					= new ElementGroupTickLabelStringElement();
				if( tGroup.readProperty(tickLabel) == false )
				{
					return ic;
				}
			}
			
		}
		else if( nList.getLength()==0 )
		{
			if( data.isStringArrayHolding() )
			{
				ElementGroupTickLabelStringElement tGroup
					= this.createTickLabels( groupSet, data );
				if( tGroup==null )
				{
					return ic;
				}
				if( tGroup.setPropertiesOfDrawingElements() == false )
				{
					return ic;
				}
			}
		}
		else
		{
			return ic;
		}
		
		
		
		//
		groupSet.initPropertiesHistory();

		
		return SGIConstants.SUCCESSFUL_COMPLETION;
	}

	


	/**
	 * 
	 */
	public static interface IElementGroupSetInSXYGraph
	{
		/**
		 * 
		 */
		public Rectangle2D getTickLabelsBoundingBox( final SGData data );


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

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

	}




	/**
	 * 
	 */
	class ElementGroupSetForMultipleDataInSXYGraph
		extends ElementGroupSetForMultipleData
		implements ActionListener, IElementGroupSetInSXYGraph, SGIPropertySettingListenerSXYData
	{

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


		/**
		 * 
		 * @return
		 */
		public String getDataClassName()
		{
			SGData data = getData(this);
			String name = null;
			if( data instanceof SGSXYSamplingData )
			{
				name = SGDataTypeConstants.SXY_SAMPLING_DATA;
			}
			else
			{
				name = SGDataTypeConstants.SXY_MULTIPLE_DATA;
			}
			return name;
		}


		/**
		 * 
		 */
		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 setDrawingElementsLocation( final SGData data )
		{

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

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

			return true;
		}


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

			SGSXYMultipleData data_ = (SGSXYMultipleData)data;
			SGSXYData[] 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(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 createTemporaryPropertyObject()
		{
			this.mTemporaryProperties = this.getWholeProperties();
			return true;
		}



		/**
		 * 
		 */
		public boolean setPropertiesFromDialog()
		{

			final SGPropertyDialogSXYData dg = (SGPropertyDialogSXYData)mPropertyDialogForData;


			// 全部がチェックアウトされたら警告
			if( !dg.getLineVisible()
			&& !dg.getBarVisible()
			&& !dg.getSymbolVisible() )
			{
				JOptionPane.showMessageDialog(
					dg, MSG_NOT_HIDE_ALL_ELEMENTS );
				return false;
			}


			for( int ii=0; ii<this.mElementGroupSetList.size(); ii++ )
			{
				ElementGroupSetInSXYGraph groupSet
					= (ElementGroupSetInSXYGraph)this.mElementGroupSetList.get(ii);
				if( groupSet.setPropertyWithDialog_( dg ) == false )
				{
					return false;
				}
			}

			return true;			
		}



		/**
		 * 
		 * @return
		 */
		protected boolean recover()
		{
			if( this.setWholeProperties( this.mTemporaryProperties ) == false )
			{
				return false;
			}

			return true;
		}



		/**
		 * 
		 */
		protected boolean clickDrawingElements( final MouseEvent e )
		{

			final int x = e.getX();
			final int y = e.getY();
			if( this.contains(x,y) == false )
			{
				return false;
			}


			if( (SwingUtilities.isRightMouseButton(e) )
				&& ( e.getClickCount() == 1 ) )
			{
//					final JPopupMenu menu = errBarGroup.getPopupMenu();
//					menu.show( this, e.getX(), e.getY() );
			}
			else if( (SwingUtilities.isLeftMouseButton(e) )
				&& ( e.getClickCount() == 2 ) )
			{
				this.showPropertyDialog();
			}

			return true;

		}



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


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

			ElementGroupSetPropertiesForSamplingDataInSXYGraph gp
				= (ElementGroupSetPropertiesForSamplingDataInSXYGraph)p;


			gp.samplingRate = this.getSamplingRate();

			return true;

		}



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



		/**
		 * 
		 */
		public SGProperties getWholeProperties()
		{
			ElementGroupSetInSXYGraph groupSet
				= (ElementGroupSetInSXYGraph)this.mElementGroupSetList.get(0);
			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;
			for( int ii=0; ii<this.mElementGroupSetList.size(); ii++ )
			{
				ElementGroupSetInSXYGraph groupSet
					= (ElementGroupSetInSXYGraph)this.mElementGroupSetList.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;
			}

			// 各データが持つ描画要素群にプロパティを出力させる
			ElementGroupSetInSXYGraph groupSet
				= (ElementGroupSetInSXYGraph)this.mElementGroupSetList.get(0);
			ArrayList list = groupSet.mDrawingElementGroupList;
			for( int ii=0; ii<list.size(); ii++ )
			{
				SGElementGroup group = (SGElementGroup)list.get(ii);
				Element element = group.createElement( document );
				if( element == null )
				{
					return null;
				}
				el.appendChild( element );
			}

			return el;
		}

		

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


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

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


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

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

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

			return true;
		}



		
		/**
		 * 
		 */
		public ArrayList getLineGroups()
		{
			return this.getFirst().getLineGroups();
		}


		/**
		 * 
		 */
		public ArrayList getSymbolGroups()
		{
			return this.getFirst().getSymbolGroups();
		}


		/**
		 * 
		 */
		public ArrayList getBarGroups()
		{
			return this.getFirst().getBarGroups();
		}


		/**
		 * 
		 */
		public ArrayList getErrorBarGroups()
		{
			return this.getFirst().getErrorBarGroups();
		}


		/**
		 * 
		 */
		public ArrayList getTickLabelGroups()
		{
			return this.getFirst().getTickLabelGroups();
		}

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


		public boolean setLineProperties( SGProperties p )
		{
			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 this.setProperties( list, p );
		}


		public boolean setSymbolProperties( SGProperties p )
		{
			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 this.setProperties( list, p );
		}


		public boolean setBarProperties( SGProperties p )
		{
			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 this.setProperties( list, p );
		}


		public boolean setErrorBarProperties( SGProperties p )
		{
			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 this.setProperties( list, p );
		}


		public boolean setTickLabelProperties( SGProperties p )
		{
			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 this.setProperties( list, p );
		}


		
		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 int getXAxisConfiguration()
		{
			return mAxisElement.getConfigurationInPlane( this.mXAxis );
		}


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

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


		/**
		 * 
		 */
		class ElementGroupSetPropertiesForSamplingDataInSXYGraph
			extends ElementGroupSetInGraphProperties
		{

			double samplingRate;

			/**
			 * 
			 */
			public boolean equals( final Object obj )
			{

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

				if( ( obj instanceof ElementGroupSetPropertiesForSamplingDataInSXYGraph ) == false )
				{
					return false;
				}

				ElementGroupSetPropertiesForSamplingDataInSXYGraph p
					= (ElementGroupSetPropertiesForSamplingDataInSXYGraph)obj;

				if( p.samplingRate!=this.samplingRate ) return false;

				return true;

			}

			
		}



	}




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

		/**
		 * 
		 */
		private ElementGroupErrorBar mErrorBarGroup = null;


		/**
		 * 
		 */
		private ElementGroupTickLabelStringElement mTickLabels = null;



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


		/**
		 * 
		 * @return
		 */
		public String getDataClassName()
		{
			return SGDataTypeConstants.SXY_DATA;
		}

		
		/**
		 * 
		 */
		public boolean contains( final int x, final int y )
		{
//System.out.println("<< ElementGroupSetInGraph::contains >>");

			if( super.contains(x,y) )
			{
//System.out.println("return true : gs"+"  "+this);
				return true;
			}

			if( this.mErrorBarGroup!=null )
			{
				if( this.mErrorBarGroup.contains(x,y) )
				{
					return true;
				}
			}
			
			if( this.mTickLabels!=null )
			{
				if( this.mTickLabels.contains(x,y) )
				{
					return true;
				}
			}

			return false;
		}


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

			// error bars
			final ElementGroupErrorBar eGroup = this.mErrorBarGroup;
			if( eGroup != null )
			{
				eGroup.zoom(ratio);
			}

			// tick labels
			if( this.mTickLabels != null )
			{
				this.mTickLabels.zoom(ratio);
			}

			return true;
		}



		/**
		 * 
		 */
		public ArrayList getLineGroups()
		{
			ArrayList list = new ArrayList();
			for( int ii=0; ii<this.mDrawingElementGroupList.size(); ii++ )
			{
				Object obj = this.mDrawingElementGroupList.get(ii);
				if( obj instanceof SGElementGroupLine )
				{
					list.add(obj);
				}
			}
			return list;
		}


		/**
		 * 
		 */
		public ArrayList getSymbolGroups()
		{
			ArrayList list = new ArrayList();
			for( int ii=0; ii<this.mDrawingElementGroupList.size(); ii++ )
			{
				Object obj = this.mDrawingElementGroupList.get(ii);
				if( obj instanceof SGElementGroupSymbol )
				{
					list.add(obj);
				}
			}
			return list;
		}


		/**
		 * 
		 */
		public ArrayList getBarGroups()
		{
			ArrayList list = new ArrayList();
			for( int ii=0; ii<this.mDrawingElementGroupList.size(); ii++ )
			{
				Object obj = this.mDrawingElementGroupList.get(ii);
				if( obj instanceof SGElementGroupBar )
				{
					list.add(obj);
				}
			}
			return list;
		}


		/**
		 * 
		 */
		public ArrayList getErrorBarGroups()
		{
			ArrayList list = new ArrayList();
			if( this.mErrorBarGroup!=null )
			{
				list.add( this.mErrorBarGroup );
			}
			return list;
		}


		/**
		 * 
		 */
		public ArrayList getTickLabelGroups()
		{
			ArrayList list = new ArrayList();
			if( this.mTickLabels!=null )
			{
				list.add( this.mTickLabels );
			}
			return list;
		}



		public boolean setLineProperties( SGProperties p )
		{
			return this.setProperties( this.getLineGroups(), p );
		}


		public boolean setSymbolProperties( SGProperties p )
		{
			return this.setProperties( this.getSymbolGroups(), p );
		}


		public boolean setBarProperties( SGProperties p )
		{
			return this.setProperties( this.getBarGroups(), p );
		}


		public boolean setErrorBarProperties( SGProperties p )
		{
			return this.setProperties( this.getErrorBarGroups(), p );
		}


		public boolean setTickLabelProperties( SGProperties p )
		{
			return this.setProperties( this.getTickLabelGroups(), p );
		}



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

			return true;
		}


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


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


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


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

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


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

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

			return true;
		}



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

			SGElementGroupSXY group = null;
			if( element instanceof SGDrawingElementLine )
			{
				group = new ElementGroupLine();
			}
			else if( element instanceof SGDrawingElementRectangle )
			{
				group = new ElementGroupBar();
			}
			else if( element instanceof SGDrawingElementSymbol )
			{
				group = new ElementGroupSymbol();
			}
			else
			{
				throw new Error("");
			}


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


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

			this.addElementGroup(group);


			return true;

		}



		/**
		 * 
		 */
		private boolean checkGroupType( final SGElementGroup group )
		{

			final Class cl = group.getClass();
			for( int ii=0; ii<this.mDrawingElementGroupList.size(); ii++ )
			{
				final SGElementGroup group_
					= (SGElementGroup)this.mDrawingElementGroupList.get(ii);
				final Class cl_ = group_.getClass();
				if( cl.equals(cl_) )
				{
					System.out.println("既に存在します！");
					return false;
				}
			}

			return true;
		}



		/**
		 * 
		 * @return
		 */
		protected boolean isLineVisible()
		{
			ArrayList list = this.getLineGroups();
			SGElementGroup group = (SGElementGroup)list.get(0);
			return group.isVisible();
		}


		/**
		 * 
		 * @return
		 */
		protected boolean isSymbolVisible()
		{
			ArrayList list = this.getSymbolGroups();
			SGElementGroup group = (SGElementGroup)list.get(0);
			return group.isVisible();
		}


		/**
		 * 
		 * @return
		 */
		protected boolean isBarVisible()
		{
			ArrayList list = this.getBarGroups();
			SGElementGroup group = (SGElementGroup)list.get(0);
			return group.isVisible();
		}



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



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

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


			// set the location of the data points
//			SGTuple2d[] valueArray = dataSXY.getValueArray();
			if( calcLocationOfSXYData(
				dataSXY,
				this.mXAxis,
				this.mYAxis,
				this.mPointsArray ) == false )
			{
				return false;
			}


			for( int ii=0; ii<this.mDrawingElementGroupList.size(); ii++ )
			{
				SGElementGroupSXY group
					= (SGElementGroupSXY)this.mDrawingElementGroupList.get(ii);
				if( group.isVisible() )
				{
					if( group.setLocation( this.mPointsArray ) == false )
					{
						return false;
					}
				}
			}


			// set the location of error bars
			if( this.mErrorBarGroup!=null )
			{
				if( this.mErrorBarGroup.isVisible() )
				{
					SGTuple2f[] startArray = this.mErrorBarGroup.mStartArray;
					SGTuple2f[] endArray = this.mErrorBarGroup.mEndArray;
					if( this.mErrorBarGroup.calcErrorBarLocation(
						dataSXY,
						this.mXAxis,
						this.mYAxis,
						startArray,
						endArray ) == false )
					{
						return false;
					}

					if( this.mErrorBarGroup.setLocation(
						startArray,
						endArray ) == false )
					{
						return false;
					}
				}

			}


			// set the location of tick labels
			if( this.mTickLabels!=null )
			{
				if( this.mTickLabels.isVisible() )
				{
					SGTuple2f[] pointArray = this.mTickLabels.mPointsArray;

					if( this.mTickLabels.calcTickLabelLocation(
						dataSXY, this.mXAxis, pointArray ) == false )
					{
						return false;
					}

					if( this.mTickLabels.setLocation( pointArray ) == false )
					{
						return false;
					}
				}
			}


			return true;
		}



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

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

				// 表示状態になっているときは、グループに描画要素を作成させる
				if( group.isVisible() )
				{
					group.setLocation( this.mPointsArray );
				}
			}


			SGSXYData dataSXY = (SGSXYData)getData(this);


			// エラーバー
			if( this.mErrorBarGroup != null )
			{
				if( this.mErrorBarGroup.mVisibleFlag )
				{
					this.mErrorBarGroup.setLocation(
						this.mErrorBarGroup.mStartArray,
						this.mErrorBarGroup.mEndArray );
				}
			}

			// データ付属文字列
			if( this.mTickLabels != null )
			{
				if( this.mTickLabels.mVisibleFlag )
				{
//					this.createDataString( dataSXY );
					this.mTickLabels.setLocation(
						this.mTickLabels.mPointsArray );
				}
			}


			return true;
		}



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

			group.mGroupSet = this;


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


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


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


			return true;

		}



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

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

			ArrayList rectList = new ArrayList();
			final ElementGroupTickLabelStringElement group = this.mTickLabels;
			if( group == null )
			{
				return new Rectangle2D.Float();
			}
			if( !group.isVisible() )
			{
				return new Rectangle2D.Float();
			}


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

			Rectangle2D rectAll = SGUtilityJava2D.getBoundingBox(strList);
			rectList.add(rectAll);


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

			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
			final ElementGroupErrorBar eGroup = this.mErrorBarGroup;
			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 )
		{
			Rectangle2D rect = getGraphRect();
			final ElementGroupTickLabelStringElement groupString = this.mTickLabels;
			if( groupString != null )
			{
				if( groupString.isVisible() )
				{
					groupString.paintElement(g2d);
				}
			}

			return true;
		}



		/**
		 * 
		 */
		public boolean setPropertiesFromDialog( SGPropertyDialog dialog )
		{

			final SGPropertyDialogSXYData dg
				= (SGPropertyDialogSXYData)dialog;


			// 全部がチェックアウトされたら警告
			if( !dg.getLineVisible()
			&& !dg.getBarVisible()
			&& !dg.getSymbolVisible() )
			{
				JOptionPane.showMessageDialog(
					dg, MSG_NOT_HIDE_ALL_ELEMENTS );
				return false;
			}


			//
			if( this.setPropertyWithDialog_( dg ) == false )
			{
				return false;
			}

//			setAllDrawingElementsLocation();
//			repaint();

			return true;
		}


		/**
		 * 
		 */
		private boolean setPropertyWithDialog_( SGPropertyDialogSXYData dg )
		{

			// set the related axes
			this.setAxisPropertyWithDialog();			


			// visibility in legend
			this.setVisibleInLegend();


			//
			ArrayList lineList = this.getLineGroups();
			for( int ii=0; ii<lineList.size(); ii++ )
			{
				SGElementGroupLine group = (SGElementGroupLine)lineList.get(ii);
				if( dg.isTabEnabled( dg.getLinePanel() ) )
				{
					if( dg.setLineProperties(group) == false )
					{
						return false;
					}
				}
			}

			ArrayList symbolList = this.getSymbolGroups();
			for( int ii=0; ii<symbolList.size(); ii++ )
			{
				SGElementGroupSymbol group = (SGElementGroupSymbol)symbolList.get(ii);
				if( dg.isTabEnabled( dg.getSymbolPanel() ) )
				{
					if( dg.setSymbolProperties(group) == false )
					{
						return false;
					}
				}
			}

			ArrayList barList = this.getBarGroups();
			for( int ii=0; ii<barList.size(); ii++ )
			{
				SGElementGroupBar group = (SGElementGroupBar)barList.get(ii);
				if( dg.isTabEnabled( dg.getBarPanel() ) )
				{
					if( dg.setBarProperties(group) == false )
					{
						return false;
					}
				}
			}

			if( this.mErrorBarGroup!=null )
			{
				if( dg.isTabEnabled( dg.getErrorBarPanel() ) )
				{
					if( dg.setErrorBarProperties( this.mErrorBarGroup ) == false )
					{
						return false;
					}
				}
			}

			if( this.mTickLabels!=null )
			{
				if( dg.isTabEnabled( dg.getTickLabelPanel() ) )
				{
					if( dg.setTickLabelProperties( this.mTickLabels ) == false )
					{
						return false;
					}
				}
			}

			return true;
		}


		/**
		 * 
		 */
		private boolean setAxisPropertyWithDialog()
		{
			final SGPropertyDialogSXYData dg = (SGPropertyDialogSXYData)mPropertyDialogForData;

			final SGAxis bAxis = mAxisElement.getAxisInPlane( SGAxisElement.AXIS_HORIZONTAL_1 );
			final SGAxis tAxis = mAxisElement.getAxisInPlane( SGAxisElement.AXIS_HORIZONTAL_2 );
			final SGAxis lAxis = mAxisElement.getAxisInPlane( SGAxisElement.AXIS_PERPENDICULAR_1 );
			final SGAxis rAxis = mAxisElement.getAxisInPlane( SGAxisElement.AXIS_PERPENDICULAR_2 );

			if( dg.isLeftBottomSelected() )
			{
				this.mXAxis = bAxis;
				this.mYAxis = lAxis;
			}
			else if( dg.isLeftTopSelected() )
			{
				this.mXAxis = tAxis;
				this.mYAxis = lAxis;
			}
			else if( dg.isRightBottomSelected() )
			{
				this.mXAxis = bAxis;
				this.mYAxis = rAxis;
			}
			else if( dg.isRightTopSelected() )
			{
				this.mXAxis = tAxis;
				this.mYAxis = rAxis;
			}

			return true;
		}


		/**
		 * 
		 * @return
		 */
		private boolean setVisibleInLegend()
		{
			final SGPropertyDialogSXYData dg = (SGPropertyDialogSXYData)mPropertyDialogForData;

			Boolean b = dg.getLegendVisible();
			if( b!=null )
			{
				this.setVisibleInLegend( b.booleanValue() );
			}

			return true;
		}


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


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

			// Properties of Error Bars
			if( this.mErrorBarGroup != null )
			{
				String tagName = this.mErrorBarGroup.getTagName();
				Element elErrorBar = document.createElement( tagName );
				if( this.mErrorBarGroup.writeProperty( elErrorBar ) == false )
				{
					return null;
				}
				el.appendChild( elErrorBar );
			}

			// Properties of Tick Labels
			if( this.mTickLabels != null )
			{
				String tagName = this.mTickLabels.getTagName();
				Element elTickLabel = document.createElement( tagName );
				if( this.mTickLabels.writeProperty( elTickLabel ) == false )
				{
					return null;
				}
				el.appendChild( elTickLabel );
			}

			return el;
		}


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

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

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

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

			return true;
		}
		


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

			return ep;
		}


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

			super.getProperties(p);

			ElementGroupSetInSXYGraphProperties ep = (ElementGroupSetInSXYGraphProperties)p;

			if( this.mErrorBarGroup!=null )
			{
				ep.errorBarProperties = this.mErrorBarGroup.getProperties();
			}

			if( this.mTickLabels!=null )
			{
				ep.tickLabelsProperties = this.mTickLabels.getProperties();
			}

			return true;
		}


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

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

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

			ElementGroupSetInSXYGraphProperties ep = (ElementGroupSetInSXYGraphProperties)p;

			if( this.mErrorBarGroup!=null )
			{
				this.mErrorBarGroup.setProperties( ep.errorBarProperties );
			}

			if( this.mTickLabels != null)
			{
				this.mTickLabels.setProperties( ep.tickLabelsProperties );
			}

			return true;

		}




		/**
		 * 
		 */
		class ElementGroupSetInSXYGraphProperties extends ElementGroupSetInGraphProperties
		{

			SGProperties errorBarProperties;
			SGProperties tickLabelsProperties;


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

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


				ElementGroupSetInSXYGraphProperties p = (ElementGroupSetInSXYGraphProperties)obj;

				if( p.errorBarProperties == null )
				{
					if( this.errorBarProperties != null )
					{
						return false;
					}
				}
				else
				{
				
					if( p.errorBarProperties.equals( this.errorBarProperties ) == false )
					{
						return false;
					}
				}
		
		
				if( p.tickLabelsProperties == null )
				{
					if( this.tickLabelsProperties != null )
					{
						return false;
					}
				}
				else
				{
				
					if( p.tickLabelsProperties.equals( this.tickLabelsProperties ) == false )
					{
						return false;
					}
				}
		

				return true;

			}



			/**
			 * 
			 */
			public String toString()
			{
				String str = new String("[");
				str += super.toString();

				if( this.errorBarProperties!=null )
				{
					str += this.errorBarProperties.toString();
				}
				else
				{
					str += "ErrorBars_empty, ";
				}

				if( this.tickLabelsProperties!=null )
				{
					str += this.tickLabelsProperties.toString();
				}
				else
				{
					str += "TickLabels_empty, ";
				}

				str += new String("]");

				return str;
			}

		}


	}



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

		private boolean mFocusedFlag = false;


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

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


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


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

			return true;
		}


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


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

			ElementGroupSetInSXYGraph groupSet
				= (ElementGroupSetInSXYGraph)this.mGroupSet;

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

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

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

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

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

					}

				}

			}


			return true;
		}



		/**
		 * 
		 */
		protected boolean setDialogProperty()
		{
			final SGPropertyDialogSXYData dg = (SGPropertyDialogSXYData)mPropertyDialogForData;

			dg.setLineVisible( this.isVisible() );
			dg.setLineWidth( new Float( this.mLineWidth ) );
			dg.setLineType( new Integer( mLineType ) );
			dg.setLineColorList( this.mColorList );

			return true;
		}


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


	}





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

		private boolean mFocusedFlag = false;

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

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


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


		/**
		 * 
		 */
		private boolean init()
		{
			this.setVisible( SGDefaultValues.BAR_VISIBLE );
			this.setBaselineValue( SGDefaultValues.BAR_BASELINE_VALUE );
			this.setRectangleWidth( SGDefaultValues.BAR_WIDTH );
			this.setColor( SGDefaultValues.BAR_COLOR );
			this.setEdgeLineWidth( SGDefaultValues.BAR_LINE_WIDTH );
			this.setEdgeLineColor( SGDefaultValues.BAR_LINE_COLOR );

			return true;
		}



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

//System.out.println("<< ElementGroupBar::setLocation >>");

			final float gx = mGraphRectX;
			final float gy = mGraphRectY;
			final float gw = mGraphRectWidth;
			final float gh = mGraphRectHeight;


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

//System.out.println("baseline="+baseline);

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

//System.out.println("flag="+flag);

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

			for( int ii=0; ii<this.mDrawingElementArray.length; ii++ )
			{
//System.out.println("ii="+ii);

				final SGDrawingElementBar2D bar
					= (SGDrawingElementBar2D)this.mDrawingElementArray[ii];

				float bLine = baseline;

				SGTuple2f point = pointArray[ii];
				float posY = point.y;
				if( Float.isInfinite( posY ) || Float.isNaN( posY ) )
				{

					if( baselineFlag )
					{
						posY = baseline;
						bLine = gy + gh;
					}
					else
					{
						bar.setVisible( false );
					}

					continue;
				}

				if( !baselineFlag )
				{
					bLine = gy + gh;
				}

				final float x = point.x-0.5f*w;
				float y = 0.0f;
				float h = 0.0f;

//System.out.println(point.y+"  "+baseline);

				if( posY <= bLine )
				{
					y = posY;
					h = bLine - posY;
				}
				else
				{
					y = bLine;
					h = posY - bLine;
				}

//System.out.println(y+"  "+h);

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

//System.out.println(bar.getElementBounds());

			}

//System.out.println();

			return true;
		}



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

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

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


			return true;
		}



		/**
		 * 
		 * @param g2d
		 * @param symbol
		 * @return
		 */
		private boolean emphasisBar(
			final SGDrawingElementBar2D bar,
			final Graphics2D g2d )
		{
			Rectangle2D rect = bar.getElementBounds();
			Point2D pos00 = new Point2D.Float(
				(float)rect.getX(), (float)rect.getY() );
			Point2D pos10 = new Point2D.Float(
				(float)( rect.getX() + rect.getWidth() ), (float)rect.getY() );
			Point2D pos01 = new Point2D.Float(
				(float)rect.getX(), (float)( rect.getY() + rect.getHeight() ) );
			Point2D pos11 = new Point2D.Float(
				(float)( rect.getX() + rect.getWidth() ),
				(float)( rect.getY() + rect.getHeight() ) );
			drawAnchorsForFocusedObjects( pos00, g2d );
			drawAnchorsForFocusedObjects( pos10, g2d );
			drawAnchorsForFocusedObjects( pos01, g2d );
			drawAnchorsForFocusedObjects( pos11, g2d );
			return true;
		}




		/**
		 * 
		 */
		protected boolean setDialogProperty()
		{

			final SGPropertyDialogSXYData dg = (SGPropertyDialogSXYData)mPropertyDialogForData;

			dg.setBarVisible( this.isVisible() );
//			dg.setBarTabEnabled( this.isVisible() );
			dg.setBarWidth( new Float( this.mRectangleWidth*SGIConstants.CM_POINT_RATIO ) );
			dg.setBarEdgeLineWidth(	new Float( this.mEdgeLineWidth ) );
			dg.setBarBaselineValue( new Double( this.mBaselineValue ) );
			dg.setBarInnerColorList( this.mColorList );
			dg.setBarEdgeLineColor( this.mEdgeLineColor );

			return true;

		}


		/**
		 * 
		 */
		protected ElementGroupProperties getPropertiesFromDialog()
		{
			final SGPropertyDialogSXYData dg = (SGPropertyDialogSXYData)mPropertyDialogForData;

			BarProperties p = dg.getBarProperties();
			return p;
		}


	}





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

		private boolean mFocusedFlag = false;

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


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


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


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

			return true;
		}



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

			final Rectangle2D rect = shape.getBounds2D();

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


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

			return true;

		}




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


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

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

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

			}


			return true;
		}



		/**
		 * 
		 * @param g2d
		 * @param symbol
		 * @return
		 */
		private boolean emphasisSymbol(
			final SGDrawingElementSymbol2D symbol,
			final Graphics2D g2d )
		{
			Rectangle2D rect = symbol.getElementBounds();
			Point2D pos00 = new Point2D.Float(
				(float)rect.getX(), (float)rect.getY() );
			Point2D pos10 = new Point2D.Float(
				(float)( rect.getX() + rect.getWidth() ), (float)rect.getY() );
			Point2D pos01 = new Point2D.Float(
				(float)rect.getX(), (float)( rect.getY() + rect.getHeight() ) );
			Point2D pos11 = new Point2D.Float(
				(float)( rect.getX() + rect.getWidth() ),
				(float)( rect.getY() + rect.getHeight() ) );
			drawAnchorsForFocusedObjects( pos00, g2d );
			drawAnchorsForFocusedObjects( pos10, g2d );
			drawAnchorsForFocusedObjects( pos01, g2d );
			drawAnchorsForFocusedObjects( pos11, g2d );
			return true;
		}



		/**
		 * 
		 */
		protected boolean setDialogProperty()
		{

			final SGPropertyDialogSXYData dg = (SGPropertyDialogSXYData)mPropertyDialogForData;

			dg.setSymbolVisible( this.isVisible() );
			dg.setSymbolType( new Integer( this.mSymbolType ) );
			dg.setSymbolSize( new Float( this.mSymbolSize*SGIConstants.CM_POINT_RATIO ) );
			dg.setSymbolLineWidth( new Float( this.mLineWidth ) );
			dg.setSymbolColorList( this.mColorList );
			dg.setSymbolLineColor( this.mLineColor );

			return true;
		}



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

	}




	/**
	 *
	 */
	class ElementGroupErrorBar extends SGElementGroupErrorBar
	{

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



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



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

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

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

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

			this.setColor( SGDefaultValues.ERROR_BAR_COLOR );

			return true;
		}



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

			final int num = dataSXY.getPointsNumber();


			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();
				final double x = dataSXY.getXValue(ii).doubleValue();
				startArray[ii].x = x;
				endArray[ii].x = x;
			}

			if( this.mErrorBarStyle == ERROR_BAR_FULL )
			{
				for( int ii=0; ii<num; ii++ )
				{
					final double y = dataSXY.getYValue(ii).doubleValue();
					final double l = dataSXY.getLowerErrorValue(ii).doubleValue();
					final double u = dataSXY.getUpperErrorValue(ii).doubleValue();
					startArray[ii].y = y + l;
					endArray[ii].y = y + u;
				}
			}
			else if( this.mErrorBarStyle == ERROR_BAR_UPPER_ONLY )
			{
				for( int ii=0; ii<num; ii++ )
				{
					final double y = dataSXY.getYValue(ii).doubleValue();
					final double u = dataSXY.getUpperErrorValue(ii).doubleValue();
					startArray[ii].y = y;
					endArray[ii].y = y + u;
				}
			}
			else if( this.mErrorBarStyle == ERROR_BAR_LOWER_ONLY )
			{
				for( int ii=0; ii<num; ii++ )
				{
					final double y = dataSXY.getYValue(ii).doubleValue();
					final double l = dataSXY.getLowerErrorValue(ii).doubleValue();
					startArray[ii].y = y + l;
					endArray[ii].y = y;
				}
			}
			else
			{
				throw new Error();
			}


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

			return true;
		}




		/**
		 * 
		 */
		protected boolean setDialogProperty()
		{

			final SGPropertyDialogSXYData dg = (SGPropertyDialogSXYData)mPropertyDialogForData;

			dg.setErrorBarVisible( this.isVisible() );

			String typeName = null;
			if( this.mErrorBarStyle==ERROR_BAR_FULL
				|| this.mErrorBarStyle==ERROR_BAR_LOWER_ONLY )
			{
				typeName = getSymbolTypeName( this.mStartHeadType );
			}
			else if( this.mErrorBarStyle==ERROR_BAR_UPPER_ONLY )
			{
				typeName = getSymbolTypeName( this.mEndHeadType );
			}
			dg.setErrorBarType(typeName);

			dg.setErrorBarSymbolSize( new Float( this.mHeadSize*SGIConstants.CM_POINT_RATIO ) );
			dg.setErrorBarLineWidth( new Float( this.mLineWidth ) );
			dg.setErrorBarColorList( this.mColorList );
			dg.setErrorBarStyle( new Integer( this.mErrorBarStyle ) );

			return true;

		}



		/**
		 * 
		 */
		protected ElementGroupProperties getPropertiesFromDialog()
		{
			final SGPropertyDialogSXYData dg = (SGPropertyDialogSXYData)mPropertyDialogForData;

			ErrorBarProperties p = dg.getErrorBarProperties();

			// not from a dialog
//			p.setLineType( this.mLineType );
//			p.setHeadOpenAngle( this.mHeadOpenAngle );
//			p.setHeadCloseAngle( this.mHeadCloseAngle );

			return p;
		}

		
	}






	/**
	 * 
	 */
	class ElementGroupTickLabelStringElement extends SGElementGroupTickLabel
	{


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


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


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

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

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

			return true;
		}


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

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

			return true;

		}



		/**
		 * 
		 */
		protected ElementGroupProperties getPropertiesFromDialog()
		{

			final SGPropertyDialogSXYData dg = (SGPropertyDialogSXYData)mPropertyDialogForData;

			StringProperties p = new StringProperties();

			p.setVisible( dg.getTickLabelVisible() );
			p.setColorList( dg.getTickLabelColorList() );
			p.setFontName( dg.getTickLabelFontName() );


			final Number fontSize = dg.getTickLabelFontSize();
			if( fontSize==null )
			{
				SGUtility.showIllegalInputErrorMessageDialog( mDialogOwner );
				return null;
			}
			p.setFontSize( fontSize.floatValue() );

			final Integer fontStyle = dg.getTickLabelFontStyle();
			if( fontStyle==null )
			{
				SGUtility.showIllegalInputErrorMessageDialog( mDialogOwner );
				return null;
			}
			p.setFontStyle( fontStyle.intValue() );

			final Number angle = dg.getTickLabelAngle();
			if( angle==null )
			{
				SGUtility.showIllegalInputErrorMessageDialog( mDialogOwner );
				return null;
			}
			p.setAngle( angle.floatValue() );

			return p;
		}


		/**
		 * 
		 */
		protected boolean setDialogProperty()
		{
			final SGPropertyDialogSXYData dg = (SGPropertyDialogSXYData)mPropertyDialogForData;

			dg.setTickLabelVisible( this.isVisible() );
			dg.setTickLabelFontName( this.mFontName );
			dg.setTickLabelFontSize( new Float( this.mFontSize ) );
			dg.setTickLabelFontStyle( new Integer( this.mFontStyle ) );
			dg.setTickLabelAngle( new Float( this.mAngle ) );
			dg.setTickLabelColorList( this.mColorList );

			return true;
		}



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




		/**
		 * 
		 */
		private boolean calcTickLabelLocation(
			final SGSXYData dataSXY,
			final SGAxis axisX,
			final SGTuple2f[] pointArray )
		{
//System.out.println("<< calcTickLabelLocation >>");

			final float gx = mGraphRectX;
			final float gy = mGraphRectY;
			final float gw = mGraphRectWidth;
			final float gh = mGraphRectHeight;

			final int config = mAxisElement.getConfigurationInPlane(axisX);

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

			final int num = dataSXY.getPointsNumber();
//			final SGTuple2d[] valueArray = dataSXY.getValueArray();
			for( int ii=0; ii<num; ii++ )
			{
				final TickLabelStringElement el
					= (TickLabelStringElement)this.mDrawingElementArray[ii];
/*
				if( axisX.insideRange( valueArray[ii].x ) == false )
				{
					el.setVisible(false);
					continue;
				}
				else
				{
					el.setVisible(true);
				}
*/

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

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

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

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

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

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


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

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


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

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

//System.out.println();

			return true;

		}



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

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

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

			return true;
		}


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


	}




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

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

	}



}

