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

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.font.FontRenderContext;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.math.BigDecimal;
import java.util.ArrayList;

import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;

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.SGIFigureElementAxisBreak;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementAxis;
import jp.riken.brain.ni.samuraigraph.base.SGIConstants;
import jp.riken.brain.ni.samuraigraph.base.SGIDisposable;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureConstants;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElement;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementGraph;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementGrid;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementLegend;
import jp.riken.brain.ni.samuraigraph.base.SGISelectable;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementShape;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementSignificantDifference;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementString;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementTimingLine;
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.SGUtilityNumber;
import jp.riken.brain.ni.samuraigraph.base.SGUtilityText;
import jp.riken.brain.ni.samuraigraph.data.SGDataTypeConstants;
import jp.riken.brain.ni.samuraigraph.data.SGISXYTypeData;
import jp.riken.brain.ni.samuraigraph.data.SGISXYTypeMultipleData;
import jp.riken.brain.ni.samuraigraph.data.SGITwoDimensionalData;
import jp.riken.brain.ni.samuraigraph.data.SGIVXYTypeData;
import jp.riken.brain.ni.samuraigraph.data.SGSXYSamplingData;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementLine;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementString;
import jp.riken.brain.ni.samuraigraph.figure.SGFigureElement;
import jp.riken.brain.ni.samuraigraph.figure.SGIAxisConstants;
import jp.riken.brain.ni.samuraigraph.figure.SGISXYDataConstants;
import jp.riken.brain.ni.samuraigraph.figure.SGIStringConstants;

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



/**
 * A class managing axes.
 */
public class SGFigureElementAxis extends SGFigureElement
	implements SGIFigureElementAxis, SGIStringConstants, SGIAxisDialogObserver,
		CaretListener, ActionListener, SGIAxisConstants
{

	//
	private int mViewDirection = VIEW_XY;


	/**
	 * 
	 */
	private ArrayList mElementsGroupList = new ArrayList();


	/**
	 *
	 */
	private Color mLineColor = DEFAULT_LINE_COLOR;


	/**
	 *
	 */
	private float mAxisLineWidth = DEFAULT_AXIS_LINE_WIDTH;


	/**
	 *
	 */
	private float mScaleLineWidth = DEFAULT_TICK_MARK_LINE_WIDTH;


	/**
	 *
	 */
	private Color mStringColor = DEFAULT_FONT_COLOR;


	/**
	 *
	 */
	private float mTitleFontSize = DEFAULT_FONT_SIZE;


	/**
	 * 
	 */
	private int mTitleFontStyle = -1;


	/**
	 * 
	 */
	private String mTitleFontName = DEFAULT_FONT_NAME;



	/**
	 *
	 */
	private float mScaleFontSize = DEFAULT_FONT_SIZE;


	/**
	 * 
	 */
	private int mScaleFontStyle = -1;


	/**
	 * 
	 */
	private String mScaleFontName = DEFAULT_FONT_NAME;


	/**
	 * 
	 */
	private float mTickMarkLength = DEFAULT_TICK_MARK_LENGTH;


	/**
	 * 
	 */
	private float mSpaceAxisLineAndNumber;


	/**
	 * 
	 */
	private float mSpaceNumberAndTitle;


	/**
	 * 
	 */
	private SGDrawingElement mPressedElement = null;


	/**
	 * 
	 */
	private Point mPressedElementOrigin = null;


	/**
	 * ダイアログ
	 */
	private SGAxisDialog mDialog = null;


	/**
	 * 
	 */
	private boolean mFrameLineVisibleFlag = true;


	/**
	 * 
	 */
	private Color mFrameLineColor = DEFAULT_FRAME_LINE_COLOR;


	/**
	 * 
	 */
	private float mFrameLineWidth = DEFAULT_FRAME_LINE_WIDTH;


	/**
	 * 
	 */
	private static boolean mNotifyChangeOnDraggingFlag = true;


	/**
	 * Used to edit the title.
	 */
	private JTextField mTextField = new JTextField();


	// used only on the start-up
	private boolean mStartFlag = true;



	/**
	 * コンストラクタ
	 */
	public SGFigureElementAxis()
	{
		super();
		this.initEditField();
		if( this.init() == false )
		{
			throw new Error();
		}
	}



	/**
	 * 
	 */
	private boolean init()
	{
		this.setAxisLineWidth( DEFAULT_AXIS_LINE_WIDTH, LINE_WIDTH_UNIT );
		this.setTickMarkWidth( DEFAULT_TICK_MARK_LINE_WIDTH, LINE_WIDTH_UNIT );
		this.setTickMarkLength( DEFAULT_TICK_MARK_LENGTH, AXIS_TICK_LENGTH_UNIT );
		this.setLineColor( DEFAULT_LINE_COLOR );
		this.setFrameLineVisible( DEFAULT_FRAME_LINE_VISIBLE );
		this.setFrameLineWidth( DEFAULT_FRAME_LINE_WIDTH, LINE_WIDTH_UNIT );
		this.setFrameLineColor( DEFAULT_FRAME_LINE_COLOR );
		this.setFontName( DEFAULT_FONT_NAME );
		this.setFontSize( DEFAULT_FONT_SIZE, FONT_SIZE_UNIT );
		this.setFontStyle( DEFAULT_FONT_STYLE );
		this.setStringColor( DEFAULT_FONT_COLOR );

		this.setSpaceAxisLineAndNumber(
			SGIFigureConstants.DEFAULT_SPACE_AXIS_LINE_AND_NUMBER, SGIFigureConstants.FIGURE_SPACE_UNIT );
		this.setSpaceNumberAndTitle(
			SGIFigureConstants.DEFAULT_SPACE_NUMBER_AND_TITLE, SGIFigureConstants.FIGURE_SPACE_UNIT );

		return true;
	}


	/**
	 * 
	 */
	private boolean initEditField()
	{
//		this.getComponent().setLayout(null);
//		this.getComponent().add(this.mTextField);
		this.mTextField.setVisible(false);
		this.mTextField.addActionListener(this);
		this.mTextField.addCaretListener(this);

		return true;
	}


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

		this.mDialog.dispose();
		this.mDialog = null;
		if( this.mEditingStringElement!=null )
		{
			this.mEditingStringElement.dispose();
			this.mEditingStringElement = null;
		}
		this.mFrameLineColor = null;
		this.mLineColor = null;
		if( this.mPressedElement!=null )
		{
			this.mPressedElement.dispose();
			this.mPressedElement = null;
		}
		this.mPressedElementOrigin = null;
		this.mPressedPoint = null;
		this.mScaleFontName = null;
		this.mStringColor = null;
		this.mTemporaryProperties = null;
		this.mTextField = null;
		this.mTitleFontName = null;

		ArrayList list = this.mElementsGroupList;
		for( int ii=0; ii<list.size(); ii++ )
		{
			ElementsGroupOfAxis group = (ElementsGroupOfAxis)list.get(ii);
			group.dispose();
		}
		this.mElementsGroupList.clear();
		this.mElementsGroupList = null;
	}


	public void setComponent( JComponent com )
	{
		super.setComponent(com);
		com.add(this.mTextField);
	}


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

		if( source.equals( this.mTextField ) )
		{
			this.terminateEditField();
			return;
		}
	}




	/**
	 * 
	 */
	public void caretUpdate( final CaretEvent e )
	{
		final String str = this.mTextField.getText();

		final Font font = new Font(
			this.getFontName(),
			this.getFontStyle(),
			(int)(this.getFontSize()*this.getMagnification()) );
		final Rectangle2D stringRect = font.getStringBounds(
			str, new FontRenderContext( null, false, false ) );

		final double width = stringRect.getWidth();
		if( width > this.mTextField.getWidth() )
		{
			this.mTextField.setSize(
				(int)( stringRect.getWidth() + this.getMagnification()*this.getFontSize() ),
				this.mTextField.getHeight()
			);
		}
	
	}



	/**
	 * 
	 */
	private boolean terminateEditField()
	{
		this.commitEdit();
		this.hideEditField();
		return true;
	}


	/**
	 * 
	 * @return
	 */
	private boolean commitEdit()
	{
		String str = this.mTextField.getText();

		String before = this.mEditingStringElement.getString();
		String after = str;
		this.mEditingStringElement.setString( after );

		// update the history
		if( before.equals(after) == false )
		{
			this.setChanged( true );
		}

		//
		this.createAllDrawingElements();

		this.repaint();

		notifyChange();
		this.notifyToRoot();

		return true;
	}


	/**
	 * 
	 */
	private boolean hideEditField()
	{
		this.mTextField.setText("");
		this.mTextField.setVisible(false);
		return true;
	}



	/**
	 * 
	 * @return
	 */
	public String getFontName()
	{
		return this.mTitleFontName;
	}


	/**
	 *
	 */
	public float getFontSize()
	{
		return this.mTitleFontSize;
	}


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


	/**
	 *
	 */
	public int getFontStyle()
	{
		return this.mTitleFontStyle;
	}


	/**
	 * 
	 * @return
	 */
	public Color getStringColor()
	{
		return this.mStringColor;
	}


	/**
	 * 
	 * @return
	 */
	public boolean isFrameLineVisible()
	{
		return this.mFrameLineVisibleFlag;
	}


	/**
	 * 
	 * @return
	 */
	public float getFrameLineWidth()
	{
		return this.mFrameLineWidth;
	}


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


	/**
	 * 
	 * @return
	 */
	public Color getFrameLineColor()
	{
		return this.mFrameLineColor;
	}


	/**
	 * 
	 * @return
	 */
	public float getAxisLineWidth()
	{
		return this.mAxisLineWidth;
	}


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


	/**
	 * 
	 * @return
	 */
	public float getTickMarkWidth()
	{
		return this.mScaleLineWidth;
	}


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


	/**
	 * 
	 * @return
	 */
	public float getTickMarkLength()
	{
		return this.mTickMarkLength;
	}


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


	/**
	 * 
	 */
	public Color getLineColor()
	{
		return this.mLineColor;
	}


	/**
	 * 
	 * @param b
	 */
	public boolean setFrameVisible( final boolean b )
	{
		this.mFrameLineVisibleFlag = b;
		return true;
	}


	/**
	 * 
	 * @param width
	 * @return
	 */
	public boolean setTickMarkWidth( final float width )
	{
		this.mScaleLineWidth = width;
		return true;
	}


	/**
	 * 
	 * @param width
	 * @return
	 */
	public boolean setTickMarkWidth( 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.setTickMarkWidth( (float)SGUtilityText.convertToPoint( width, unit ) );
	}


	/**
	 * 
	 * @param len
	 * @return
	 */
	public boolean setTickMarkLength( final float len )
	{
		this.mTickMarkLength = len;
		return true;
	}


	/**
	 * 
	 * @param width
	 * @return
	 */
	public boolean setTickMarkLength( final float len, final String unit )
	{
		final double conv = SGUtilityText.convert( len, unit, AXIS_TICK_LENGTH_UNIT );
		if( conv < AXIS_TICK_LENGTH_MIN ) return false;
		if( conv > AXIS_TICK_LENGTH_MAX ) return false;

		return this.setTickMarkLength( (float)SGUtilityText.convertToPoint( len, unit ) );
	}


	/**
	 * 
	 */
	public boolean setLineColor( final Color cl )
	{
		this.mLineColor = cl;
		return true;
	}


	/**
	 * Returns the axis location of the selected tab.
	 * @return
	 */
	public int getAxisLocationForSelectedTab()
	{
		return this.mTempAxisLocation;
	}
	
	private int mTempAxisLocation = -1;




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

		boolean flag = true;
		if( element instanceof SGIFigureElementGraph )
		{

		}
		else if( element instanceof SGIFigureElementString )
		{
			
		}
		else if( element instanceof SGIFigureElementLegend )
		{
			
		}
		else if( element instanceof SGIFigureElementAxis )
		{
			
		}
		else if( element instanceof SGIFigureElementAxisBreak )
		{
			
		}
		else if( element instanceof SGIFigureElementSignificantDifference )
		{
			
		}
		else if( element instanceof SGIFigureElementTimingLine )
		{
			
		}
		else if( element instanceof SGIFigureElementGrid )
		{

		}
		else if( element instanceof SGIFigureElementShape )
		{

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


		return flag;
	}



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



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

		// Groups of Axis
		for( int ii=0; ii<this.mElementsGroupList.size(); ii++ )
		{
			final ElementsGroupOfAxis group = (ElementsGroupOfAxis)this.mElementsGroupList.get(ii);
			group.zoom(ratio);
		}

		return true;
	}


	
	/**
	 * 
	 */
	public boolean onMouseClicked( final MouseEvent e )
	{
		// Axis Groups
		ArrayList list = this.mElementsGroupList;
		for( int ii=0; ii<list.size(); ii++ )
		{
			final ElementsGroupOfAxis element
				= (ElementsGroupOfAxis)list.get(ii);
			final boolean flag = element.onMouseClicked(e);
			if( flag )
			{
				return true;
			}
		}

		if( this.mTextField.isVisible() )
		{
			this.terminateEditField();
		}
		else
		{
			this.hideEditField();
		}

		return false;
	}



	/**
	 * 
	 */
	public boolean onMousePressed( final MouseEvent e )
	{
		// Axis Groups
		for( int ii=0; ii<this.mElementsGroupList.size(); ii++ )
		{
			final ElementsGroupOfAxis element = (ElementsGroupOfAxis)this.mElementsGroupList.get(ii);
			final boolean flag = element.onMousePressed(e);
			if( flag )
			{
				this.prepare();
				return true;
			}
		}

		return false;
	}






	/**
	 * 
	 * @param e
	 */
	public boolean onMouseDragged( final MouseEvent e )
	{
		// Axis Group
		for( int ii=0; ii<this.mElementsGroupList.size(); ii++ )
		{
			final ElementsGroupOfAxis element
				= (ElementsGroupOfAxis)this.mElementsGroupList.get(ii);
			final boolean flag = element.onMouseDragged(e);
			if( flag )
			{
				return true;
			}
		}

		return false;
	}



	/**
	 * 
	 * @param e
	 */
	public boolean onMouseReleased( final MouseEvent e )
	{

		boolean notifyFlag = false;

		// Axis Group
		for( int ii=0; ii<this.mElementsGroupList.size(); ii++ )
		{
			final ElementsGroupOfAxis element
				= (ElementsGroupOfAxis)this.mElementsGroupList.get(ii);
			if( element.onMouseReleased(e) )
			{
				if( this.createAllDrawingElements() == false )
				{
					return false;
				}

				this.initializePressedElement();

				SGProperties pTemp = this.mTemporaryProperties;
				SGProperties pPresent = this.getProperties();
				if( pTemp.equals(pPresent) == false )
				{
					this.setChanged(true);
					notifyFlag = true;
				}

				this.mTemporaryProperties = null;

			}

		}

		this.initializePressedElement();

		if( notifyFlag )
		{
			this.notifyChange();
			this.notifyToRoot();
		}

		return true;
	}



	/**
	 * 
	 */
	public boolean onDrawingElement( final int x, final int y )
	{
		ArrayList list = this.mElementsGroupList;
		for( int ii=0; ii<list.size(); ii++ )
		{
			ElementsGroupOfAxis group = (ElementsGroupOfAxis)list.get(ii);
			if( group.onDrawingElement(x,y) )
			{
				return true;
			}
		}

		return false;
	}



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



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

	

	/**
	 * 
	 */
	private void initializePressedElement()
	{
		this.mPressedElement = null;
		this.mPressedElementOrigin = null;
	}



	/**
	 * 
	 */
	private SGProperties mTemporaryProperties = null;



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



	/**
	 * 
	 */
	private boolean createDialog( final int num )
	{
		final SGAxisDialog dg = new SGAxisDialog( this.mDialogOwner, true );
		this.mDialog = dg;
		return true;
	}



	// Axis value used when the minimum value and the maximum value is very close.
	private static final double ALTERNATIVE_AXIS_VALUE = 1.0;


	// calculate appropriate axis range
	private SGTuple2d calcRange(
		final double min, final double max, final double factor )
	{
		final double aValue = ALTERNATIVE_AXIS_VALUE;
		final double diff = max - min;

		double minNew = min;
		double maxNew = max;
		if( Math.abs( max - min ) < Double.MIN_VALUE )
		{
			minNew = min - aValue;
			maxNew = max + aValue;
		}
		else
		{
			final double margin = factor*diff;
			minNew = min - margin;
			maxNew = max + margin;

			minNew = SGUtilityNumber.getNumberInRangeOrder(
				minNew, min, max,
				AXIS_SCALE_EFFECTIVE_DIGIT );
			maxNew = SGUtilityNumber.getNumberInRangeOrder(
				maxNew, min, max,
				AXIS_SCALE_EFFECTIVE_DIGIT );
		}

		SGTuple2d range = new SGTuple2d( minNew, maxNew );
		return range;
	}



	/**
	 *
	 */
	public boolean addData( final SGData data, final String name )
	{

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

		// create axes only once
		if( this.mElementsGroupList.size() == 0 )
		{
			// in case of two-dimensional data
			if( data instanceof SGITwoDimensionalData )
			{

				SGITwoDimensionalData tData = (SGITwoDimensionalData)data;
				
				String xTitle = null;
				String yTitle = null;

				// get values from data
				final double xMin = tData.getMinValueX();
				final double xMax = tData.getMaxValueX();
				final double yMin = tData.getMinValueY();
				final double yMax = tData.getMaxValueY();

				double xMin2 = xMin;
				double xMax2 = xMax;
				double yMin2 = yMin;
				double yMax2 = yMax;

				if( data instanceof SGISXYTypeData || data instanceof SGISXYTypeMultipleData )
				{
					SGTuple2d xRange = this.calcRange( xMin, xMax, 0.0 );
					xMin2 = xRange.x;
					xMax2 = xRange.y;

					SGTuple2d yRange = this.calcRange( yMin, yMax, 0.050 );
					yMin2 = yRange.x;
					yMax2 = yRange.y;
					
				}
				else if( data instanceof SGIVXYTypeData )
				{
					SGTuple2d xRange = this.calcRange( xMin, xMax, 0.10 );
//					xMin2 = xRange.x;
//					xMax2 = xRange.y;

					SGTuple2d yRange = this.calcRange( yMin, yMax, 0.10 );
//					yMin2 = yRange.x;
//					yMax2 = yRange.y;

					final double min = Math.min( xRange.x, yRange.x );
					final double max = Math.max( xRange.y, yRange.y );
					xMin2 = min;
					xMax2 = max;
					yMin2 = min;
					yMax2 = max;
				}

				String dataType = data.getDataType();
				if( dataType.equals(SGDataTypeConstants.SXY_DATA) ||
					dataType.equals(SGDataTypeConstants.SXY_DATE_DATA) ||
					dataType.equals(SGDataTypeConstants.SXY_MULTIPLE_DATA) ||
					dataType.equals(SGDataTypeConstants.VXY_DATA)) {
					xTitle = data.getTitle( 0 );
					if( xTitle != null && !dataType.equals(SGDataTypeConstants.SXY_MULTIPLE_DATA) )
						yTitle = data.getTitle( 1 );
				} else if ( dataType.equals(SGDataTypeConstants.SXY_SAMPLING_DATA)) {
					SGSXYSamplingData _sdata = (SGSXYSamplingData)data;
					xTitle = _sdata.getSamplingRateTitle();
				}

				//
				// creates ElementsGroupOfAxis object
				//
		
				final ElementsGroupOfAxis groupX1 = new ElementsGroupOfAxis();
				final ElementsGroupOfAxis groupX2 = new ElementsGroupOfAxis();
				final ElementsGroupOfAxis groupY1 = new ElementsGroupOfAxis();
				final ElementsGroupOfAxis groupY2 = new ElementsGroupOfAxis();

				// X1
				{
					final SGAxis xAxis = new SGAxis( xMin2, xMax2 );

					final ElementsGroupOfAxis group = groupX1;
					group.zoom( this.mMagnification );
					group.setLocationInPlane( SGIFigureElementAxis.AXIS_HORIZONTAL_1 );
					group.mAxis = xAxis;
					group.setAxisVisible( DEFAULT_BOTTOM_AXIS_VISIBLE );
					if( xTitle != null )
						group.setTitle( xTitle );
					else
						group.setTitle( DEFAULT_BOTTOM_AXIS_TITLE );
					this.mElementsGroupList.add(group);
				}

				// X2
				{
					final SGAxis xAxis = new SGAxis( xMin2, xMax2 );

					final ElementsGroupOfAxis group = groupX2;
					group.zoom( this.mMagnification );
					group.setLocationInPlane( SGIFigureElementAxis.AXIS_HORIZONTAL_2 );
					group.mAxis = xAxis;
					group.setAxisVisible( DEFAULT_TOP_AXIS_VISIBLE );
					if( xTitle != null )
						group.mTitle.setString( xTitle );
					else
						group.mTitle.setString( DEFAULT_TOP_AXIS_TITLE );
					this.mElementsGroupList.add(group);
				}

				// Y1
				{
					final SGAxis yAxis = new SGAxis( yMin2, yMax2 );

					final ElementsGroupOfAxis group = groupY1;
					group.zoom( this.mMagnification );
					group.setLocationInPlane( SGIFigureElementAxis.AXIS_PERPENDICULAR_1 );
					group.mAxis = yAxis;
					group.setAxisVisible( DEFAULT_LEFT_AXIS_VISIBLE );
					if( yTitle != null )
						group.mTitle.setString( yTitle );
					else 
						group.mTitle.setString( DEFAULT_LEFT_AXIS_TITLE );
					this.mElementsGroupList.add(group);
				}

				// Y2
				{
					final SGAxis yAxis = new SGAxis( yMin2, yMax2 );

					final ElementsGroupOfAxis group = groupY2;
					group.zoom( this.mMagnification );
					group.setLocationInPlane( SGIFigureElementAxis.AXIS_PERPENDICULAR_2 );
					group.mAxis = yAxis;
					group.setAxisVisible( DEFAULT_RIGHT_AXIS_VISIBLE );
					if( yTitle != null )
						group.mTitle.setString( yTitle );
					else
						group.mTitle.setString( DEFAULT_RIGHT_AXIS_TITLE );
					this.mElementsGroupList.add(group);
				}


				// 描画要素の作成
				this.createAllDrawingElements();


				// ダイアログの作成
				this.createDialog( SGIFigureElementAxis.TWO_DIMENSIONAL_AXIS );


				// for data with tick
				if( data instanceof SGISXYTypeData )
				{
					SGISXYTypeData sxy = (SGISXYTypeData)data;
					if( sxy.isStringArrayHolding() )
					{
						final String ref = SGISXYDataConstants.DEFAULT_SCALE_REFERENCE;
						if( ref.equals( LEFT_BOTTOM ) | ref.equals( RIGHT_BOTTOM ) )
						{
							groupX1.setNumbersVisible(false);
							groupX1.setTickMarksVisible(false);
						}
						else
						{
							groupX2.setNumbersVisible(false);
							groupX2.setTickMarksVisible(false);
						}
					}
				}

			}
			else
			{
				//
				// SXYZ型およびVXYZ型データの場合
				//

				// X・Y・Z軸の作成

				// モードがMAP、投影図の場合には、SXYやVXYと同じ。
				// 鳥瞰図の場合には、別のメソッドを用いる。
			}

		}


		// set properties on start-up
		if( this.mStartFlag )
		{
			this.mStartFlag = false;
		}


		return true;
	}




	/**
	 * 
	 */
	public boolean setGraphRect(
		final float x, final float y, final float width, final float height )
	{
//System.out.println("<< SGAxisElements::setGraphAreaRect >>");

		super.setGraphRect(x,y,width,height);
		this.setLocationOfAllDrawingElements();

		return true;
	}




	/**
	 * 
	 */
	public boolean getMarginAroundGraphRect(
		final SGTuple2f topAndBottom,
		final SGTuple2f leftAndRight )
	{

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


		// groups
		final ElementsGroupOfAxis groupTop = this.getAxisGroupInPlane( AXIS_HORIZONTAL_2 );
		final ElementsGroupOfAxis groupBottom = this.getAxisGroupInPlane( AXIS_HORIZONTAL_1 );
		final ElementsGroupOfAxis groupLeft = this.getAxisGroupInPlane( AXIS_PERPENDICULAR_1 );
		final ElementsGroupOfAxis groupRight = this.getAxisGroupInPlane( AXIS_PERPENDICULAR_2 );
		if( groupTop==null || groupBottom==null || groupLeft==null || groupRight==null )
		{
			return false;
		}


		//
//		final float space = this.getSpaceAxisLineAndNumber()*this.mMagnification;


		// 全ての描画要素を包むBounding Boxを求める
		Rectangle2D rectAllTop = groupTop.getBoundingBox();
		Rectangle2D rectAllBottom = groupBottom.getBoundingBox();
		Rectangle2D rectAllLeft = groupLeft.getBoundingBox();
		Rectangle2D rectAllRight = groupRight.getBoundingBox();


		Rectangle2D gRect = this.getGraphRect();
		
		ArrayList rectList = new ArrayList();
		rectList.add( gRect );
		
		if( rectAllTop!=null )
		{
			rectList.add( rectAllTop );
		}
		if( rectAllBottom!=null )
		{
			rectList.add( rectAllBottom );
		}
		if( rectAllLeft!=null )
		{
			rectList.add( rectAllLeft );
		}
		if( rectAllRight!=null )
		{
			rectList.add( rectAllRight );
		}
		
		Rectangle2D rectAll = SGUtility.createUnion( rectList );
		
		final float top = (float)( gRect.getY() - rectAll.getY() );
		final float bottom = (float)(
			( rectAll.getY() + rectAll.getHeight() )
			- ( gRect.getY() + gRect.getHeight() ) );
		final float left = (float)( gRect.getX() - rectAll.getX() );
		final float right = (float)(
			( rectAll.getX() + rectAll.getWidth() )
			- ( gRect.getX() + gRect.getWidth() ) );
		
		topAndBottom.x += top;
		topAndBottom.y += bottom;
		leftAndRight.x += left;
		leftAndRight.y += right;

		return true;

	}



	/**
	 * 
	 */
	public boolean setViewDirection( final int direction )
	{
		this.mViewDirection = direction;
		return true;
	}



	/**
	 * 
	 * @return
	 */
	public boolean setTitleFontSize( final float size )
	{
		this.mTitleFontSize = size;
		return true;
	}


	/**
	 * 
	 * @return
	 */
	public boolean setTitleFontStyle( final int style )
	{
		this.mTitleFontStyle = style;
		return true;
	}


	/**
	 * 
	 * @return
	 */
	public boolean setTitleFontName( final String name )
	{
		this.mTitleFontName = name;
		return true;
	}


	/**
	 * 
	 * @return
	 */
	public boolean setAxisLineWidth( final float width )
	{
		this.mAxisLineWidth = width;
		return true;
	}


	/**
	 * 
	 * @return
	 */
	public boolean setAxisLineWidth( 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.setAxisLineWidth( (float)SGUtilityText.convertToPoint( width, unit ) );
	}


	/**
	 * 
	 * @return
	 */
	public boolean setStringColor( final Color color )
	{
		this.mStringColor = color;
		return true;
	}


	/**
	 * 
	 * @return
	 */
	public boolean setFontSize( float size )
	{
		this.setTitleFontSize( size );
		this.setScaleFontSize( size );
		return true;
	}


	/**
	 * 
	 * @return
	 */
	public boolean setFontSize( 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.setFontSize( (float)SGUtilityText.convertToPoint( size, unit ) );
	}


	/**
	 * 
	 * @return
	 */
	public boolean setFontStyle( int style )
	{
		this.setTitleFontStyle( style );
		this.setScaleFontStyle( style );
		return true;
	}


	/**
	 * 
	 * @return
	 */
	public boolean setFontName( String name )
	{
		this.setTitleFontName( name );
		this.setScaleFontName( name );
		return true;
	}



	/**
	 * 
	 * @return
	 */
	public boolean setScaleFontSize( final float size )
	{
		this.mScaleFontSize = size;
		return true;
	}


	/**
	 * 
	 * @return
	 */
	public boolean setScaleFontStyle( final int style )
	{
		this.mScaleFontStyle = style;
		return true;
	}


	/**
	 * 
	 * @return
	 */
	public boolean setScaleFontName( final String name )
	{
		this.mScaleFontName = name;
		return true;
	}


	/**
	 * 
	 */
	public boolean setFrameLineVisible( final boolean b )
	{
		this.mFrameLineVisibleFlag = b;
		return true;
	}


	/**
	 * 
	 */
	public boolean setFrameLineWidth( final float width )
	{
		this.mFrameLineWidth = width;
		return true;
	}


	/**
	 * 
	 */
	public boolean setFrameLineWidth( 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.setFrameLineWidth( (float)SGUtilityText.convertToPoint( width, unit ) );
	}


	/**
	 * 
	 */
	public boolean setFrameLineColor( final Color cl )
	{
		this.mFrameLineColor = cl;
		return true;
	}


	/**
	 * 
	 * @return
	 */
	public boolean setSpaceAxisLineAndNumber( final float margin )
	{
		this.mSpaceAxisLineAndNumber = margin;
		return true;
	}


	/**
	 * 
	 * @return
	 */
	public boolean setSpaceAxisLineAndNumber( final float margin, final String unit )
	{
		final double conv = SGUtilityText.convert( margin, unit, SGIFigureConstants.FIGURE_SPACE_UNIT );
		if( conv < SGIFigureConstants.FIGURE_SPACE_TO_SCALE_MIN ) return false;
		if( conv > SGIFigureConstants.FIGURE_SPACE_TO_SCALE_MAX ) return false;

		return this.setSpaceAxisLineAndNumber( (float)SGUtilityText.convertToPoint( margin, unit ) );
	}


	/**
	 * 
	 * @return
	 */
	public boolean setSpaceNumberAndTitle( final float margin )
	{
		this.mSpaceNumberAndTitle = margin;
		return true;
	}


	/**
	 * 
	 * @return
	 */
	public boolean setSpaceNumberAndTitle( final float margin, final String unit )
	{
		final double conv = SGUtilityText.convert( margin, unit, SGIFigureConstants.FIGURE_SPACE_UNIT );
		if( conv < SGIFigureConstants.FIGURE_SPACE_TO_SCALE_MIN ) return false;
		if( conv > SGIFigureConstants.FIGURE_SPACE_TO_SCALE_MAX ) return false;

		return this.setSpaceNumberAndTitle( (float)SGUtilityText.convertToPoint( margin, unit ) );
	}


	/**
	 * 
	 */
	public float getSpaceAxisLineAndNumber()
	{
		return this.mSpaceAxisLineAndNumber;
	}


	/**
	 * 
	 */
	public float getSpaceNumberAndTitle()
	{
		return this.mSpaceNumberAndTitle;
	}


	/**
	 * 
	 */
	public float getNumberFontSize()
	{
		return this.mScaleFontSize;
	}


	/**
	 * 
	 */
	public float getTitleFontSize()
	{
		return this.mTitleFontSize;
	}

	

	/**
	 * 
	 */
	public boolean getFocusedObjectsList( ArrayList list )
	{
		return true;
	}


	/**
	 * 
	 *
	 */
	public boolean hideSelectedObject( SGISelectable s )
	{
		return true;
	}

	
	
	/**
	 * 
	 * @param loc
	 * @param x
	 * @param y
	 * @return
	 */	
	public double getValue( final int loc, final int x, final int y )
	{
		final ElementsGroupOfAxis group = this.getAxisGroupInPlane( loc );
		final SGAxis axis = group.mAxis;
		double value = 0.0;
		if( loc==SGIFigureElementAxis.AXIS_HORIZONTAL_1 | loc==SGIFigureElementAxis.AXIS_HORIZONTAL_2 )
		{
			value = calcValue( x, axis, true );
		}
		else if( loc==SGIFigureElementAxis.AXIS_PERPENDICULAR_1 | loc==SGIFigureElementAxis.AXIS_PERPENDICULAR_2 )
		{
			value = calcValue( y, axis, false );
		}
		else
		{
			throw new Error();
		}
		value = this.getNumberInRangeOrder( value, axis );
		
		return value;
	}


	/**
	 * 新しい軸のグループを追加する
	 */
	private ElementsGroupOfAxis addAxisGroup(
		final int locInCube, final SGTuple2d range, final int scaleType )
	{
		final ElementsGroupOfAxis group = new ElementsGroupOfAxis();
		final SGAxis axis = new SGAxis( range, scaleType );
		group.mAxis = axis;
		group.setLocationInCube( locInCube );
		this.mElementsGroupList.add(group);

		return group;
	}



	/**
	 * 新しい軸のグループを追加する
	 */
	private ElementsGroupOfAxis addAxisGroup( final int locInCube )
	{
		return this.addAxisGroup( locInCube, new SGTuple2d(), SGAxis.LINEAR_SCALE );
	}



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

		// フレームの線を描画
		if( this.mFrameLineVisibleFlag )
		{
			this.drawGraphAreaBoundsLines(g2d);
		}


		//
		// 描画
		//

		for( int ii=0; ii<this.mElementsGroupList.size(); ii++ )
		{
			final ElementsGroupOfAxis group = (ElementsGroupOfAxis)this.mElementsGroupList.get(ii);
			if( group.isAxisVisible() == false )
			{
				continue;
			}
			group.paintGraphics2D(g2d);
		}

	}



	/**
	 * フレームの線を作成する
	 */
	private boolean drawGraphAreaBoundsLines( final Graphics2D g2d )
	{
		if( g2d == null )
		{
			return false;
		}

		g2d.setPaint(this.mFrameLineColor);
		g2d.setStroke( new BasicStroke( this.mMagnification*this.mFrameLineWidth ) );

		g2d.drawRect(
			(int)(this.mGraphRectX),
			(int)(this.mGraphRectY),
			(int)(this.mGraphRectWidth),
			(int)(this.mGraphRectHeight)
		);


		return true;
	}



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

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


		final double strRectLineWidth = 1.0;
		final Color strRectLineColor = Color.BLACK;
		g2d.setPaint(strRectLineColor);
		g2d.setStroke( new BasicStroke( (float)strRectLineWidth ) );

		final Rectangle2D rect = element.getElementBounds();

		g2d.drawRect(
			(int)rect.getX(),
			(int)rect.getY(),
			(int)rect.getWidth(),
			(int)rect.getHeight()
		);


		return true;

	}






	/**
	 * 
	 */
	private boolean drawString( final SGDrawingElementString2D element, final Graphics2D g2d )
	{

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


		//
		element.paintElement(g2d);


		return true;
	}



	/**
	 * 
	 */
	private boolean drawLine(
		final SGDrawingElementLine2D element,
		final Graphics2D g2d,
		final BasicStroke stroke )
	{
		if( element==null || g2d==null )
		{
			return false;
		}

		g2d.setPaint(element.getColor(0));
		g2d.setStroke( stroke );
		
		SGTuple2f start = element.getStart();
		SGTuple2f end = element.getEnd();
		final Line2D line = new Line2D.Float(
			start.x, start.y,
			end.x, end.y );
		g2d.draw(line);

		return true;
	}



	/**
	 * 
	 * @param axis
	 * @return
	 */
	public boolean isHorizontal( final SGAxis axis )
	{
		return this.getHorizontalAxisList().contains(axis);
	}

	
	/**
	 * 
	 * @param axis
	 * @return
	 */
	public boolean isPerpendicular( final SGAxis axis )
	{
		return this.getPerpendicularAxisList().contains(axis);
	}
	

	/**
	 * 
	 * @param axis
	 * @return
	 */
	public boolean isNormal( final SGAxis axis )
	{
		return this.getNormalAxisList().contains(axis);
	}
	

	/**
	 * 全ての軸を入れたリストを返す
	 * @return
	 */
	public ArrayList getAxisList()
	{
		final ArrayList list = new ArrayList();

		for( int ii=0; ii<this.mElementsGroupList.size(); ii++ )
		{
			final ElementsGroupOfAxis group = (ElementsGroupOfAxis)this.mElementsGroupList.get(ii);
			list.add( group.mAxis );
		}

		return list;
	}



	/**
	 * 
	 * @return
	 */
	public ArrayList getXAxisList()
	{
		ArrayList list = new ArrayList();

		switch( this.mViewDirection )
		{
			case VIEW_XY :
			{
				list = this.getHorizontalAxisList();
				break;
			}

			case VIEW_XZ :
			{
				list = this.getHorizontalAxisList();
				break;
			}

			case VIEW_YZ :
			{
				list = this.getNormalAxisList();
				break;
			}

			default :
			{
				
			}

		}

		return list;
	}



	/**
	 * 
	 * @return
	 */
	public ArrayList getYAxisList()
	{
		ArrayList list = new ArrayList();

		switch( this.mViewDirection )
		{
			case VIEW_XY :
			{
				list = this.getPerpendicularAxisList();
				break;
			}

			case VIEW_XZ :
			{
				list = this.getNormalAxisList();
				break;
			}

			case VIEW_YZ :
			{
				list = this.getHorizontalAxisList();
				break;
			}

			default :
			{
				
			}

		}

		return list;
	}



	/**
	 * 
	 */
	public ArrayList getZAxisList()
	{
		ArrayList list = new ArrayList();

		switch( this.mViewDirection )
		{
			case VIEW_XY :
			{
				list = this.getNormalAxisList();
				break;
			}

			case VIEW_XZ :
			{
				list = this.getPerpendicularAxisList();
				break;
			}

			case VIEW_YZ :
			{
				list = this.getPerpendicularAxisList();
				break;
			}

			default :
			{
				throw new Error("not defined");
			}

		}

		return list;
	}




	/**
	 * 
	 */
	public ArrayList getHorizontalAxisList()
	{
		final ArrayList list = new ArrayList();
		
		for( int ii=0; ii<this.mElementsGroupList.size(); ii++ )
		{
			final ElementsGroupOfAxis group = (ElementsGroupOfAxis)this.mElementsGroupList.get(ii);
			final int loc = this.getLocationInPlane( group.getLocationInCube() );
			if( loc==AXIS_HORIZONTAL_1 || loc==AXIS_HORIZONTAL_2 )
			{
				list.add(group.mAxis);
			}
		}
		
		return list;
	}


	/**
	 * 
	 */
	public ArrayList getPerpendicularAxisList()
	{
		final ArrayList list = new ArrayList();
		
		for( int ii=0; ii<this.mElementsGroupList.size(); ii++ )
		{
			final ElementsGroupOfAxis group = (ElementsGroupOfAxis)this.mElementsGroupList.get(ii);
			final int loc = this.getLocationInPlane( group.getLocationInCube() );
			if( loc==AXIS_PERPENDICULAR_1 || loc==AXIS_PERPENDICULAR_2 )
			{
				list.add(group.mAxis);
			}
		}
		
		return list;
	}


	/**
	 * 
	 */
	public ArrayList getNormalAxisList()
	{
		final ArrayList hList = this.getHorizontalAxisList();
		final ArrayList pList = this.getPerpendicularAxisList();

		final ArrayList list = this.getAxisList();
		for( int ii=list.size()-1; ii>=0; ii-- )
		{
			final SGAxis axis = (SGAxis)list.get(ii);
			if( hList.contains(axis) || pList.contains(axis) )
			{
				list.remove(axis);
			}
		}

		return list;
	}


	/**
	 * 
	 */
	public SGAxis getAxisInCube( final int locInCube )
	{
		final ElementsGroupOfAxis group = this.getAxisGroupInCube( locInCube );

//System.out.println(group);

		if( group == null )
		{
			return null;
		}

		final SGAxis axis = group.mAxis;

//System.out.println(axis);

		return axis;
	}



	/**
	 * 
	 */
	public SGAxis getAxisInPlane( final int locInPlane )
	{
		final ElementsGroupOfAxis group = this.getAxisGroupInPlane( locInPlane );

//System.out.println(group);

		if( group == null )
		{
			return null;
		}

		SGAxis axis = group.mAxis;

//System.out.println(axis);

		return axis;
	}


	/**
	 * 
	 * @param loc - location in plane
	 * @return
	 */
	public SGIAxisPanelObserver getAxisPanelObserverInPlane( final int loc )
	{
		return this.getAxisGroupInPlane( loc );
	}


	/**
	 * 
	 */
	private ElementsGroupOfAxis getAxisGroupInCube( final int locInCube )
	{
		for( int ii=0; ii<this.mElementsGroupList.size(); ii++ )
		{
			final ElementsGroupOfAxis group
				= (ElementsGroupOfAxis)this.mElementsGroupList.get(ii);
			if( group.getLocationInCube() == locInCube )
			{
				return group;
			}
		}
		
		return null;		
	}


	/**
	 * 
	 */
	private ElementsGroupOfAxis getAxisGroupInPlane( final int locInPlane )
	{
		for( int ii=0; ii<this.mElementsGroupList.size(); ii++ )
		{
			final ElementsGroupOfAxis group
				= (ElementsGroupOfAxis)this.mElementsGroupList.get(ii);
			if( group.getLocationInPlane() == locInPlane )
			{
				return group;
			}
		}
		
		return null;		
	}



	/**
	 * Returns a location on the edge of a cube of given an axis.
	 * @param axis - an axis
	 * @return The location of the axis on the edge of a cube.
	 */
	public int getLocationInCube( final SGAxis axis )
	{
		if( axis == null )
		{
			return -1;
		}

		ArrayList list = this.mElementsGroupList;
		for( int ii=0; ii<list.size(); ii++ )
		{
			final ElementsGroupOfAxis group = (ElementsGroupOfAxis)list.get(ii);
			final SGAxis axis_ = group.mAxis;
			if( axis_.equals(axis) )
			{
				return group.getLocationInCube();
			}
		}

		return -1;
	}


	
	/**
	 * Returns a name of axis location in a plane.
	 * @param axis
	 * @return
	 */
	public String getLocationName( final SGAxis axis )
	{
		final int loc = this.getLocationInPlane(axis);
		return this.getLocationName(loc);
	}


	/**
	 * Returns a name of axis location in a plane.
	 * @param location
	 * @return
	 */
	public String getLocationName( final int locationInPlane )
	{
		String name = null;
		switch( locationInPlane )
		{
			case AXIS_HORIZONTAL_1 :
			{
				name = AXIS_BOTTOM;
				break;
			}
			
			case AXIS_HORIZONTAL_2 :
			{
				name = AXIS_TOP;
				break;
			}
			
			case AXIS_PERPENDICULAR_1 :
			{
				name = AXIS_LEFT;
				break;
			}

			case AXIS_PERPENDICULAR_2 :
			{
				name = AXIS_RIGHT;
				break;
			}
		}
	
		return name;
	}
	
	
	/**
	 * Returns a location in a plane from the location on the cube
	 * and the view direction.
	 * @param str - AXIS_BOTTOM, AXIS_TOP, AXIS_LEFT or AXIS_RIGHT
	 * @return The location in the plane such as AXIS_HORIZONTAL_1.
	 */
	public int getLocationInPlane( final String str )
	{
		final String s = str.toLowerCase();
		int loc = -1;
		if( AXIS_BOTTOM.toLowerCase().equals(s) )
		{
			loc = AXIS_HORIZONTAL_1;
		}
		else if( AXIS_TOP.toLowerCase().equals(s) )
		{
			loc = AXIS_HORIZONTAL_2;
		}
		else if( AXIS_LEFT.toLowerCase().equals(s) )
		{
			loc = AXIS_PERPENDICULAR_1;
		}
		else if( AXIS_RIGHT.toLowerCase().equals(s) )
		{
			loc = AXIS_PERPENDICULAR_2;
		}
		
		return loc;
	}

	
	
	/**
	 * Returns a text string for the axis location in a plane.
	 * @param axis
	 * @return
	 */
	public String getLocationStringInPlane( final SGAxis axis )
	{
		final int loc = this.getLocationInPlane( axis );
		return this.getLocationName( loc );
	}
	
	
	/**
	 * Returns a location in a plane from the location on the cube
	 * and the view direction.
	 * @param axis - an axis
	 * @return The location in the plane such as AXIS_HORIZONTAL_1.
	 */
	public int getLocationInPlane( final SGAxis axis )
	{
		if( axis == null )
		{
			throw new IllegalArgumentException("axis==null");
		}

		final int locationInCube = this.getLocationInCube( axis );
		return this.getLocationInPlane( locationInCube );
	}


	/**
	 * Returns a location in a plane from the location on the cube
	 * and the view direction.
	 * @param locationInCube - LOCATION_XAXIS_1, LOCATION_XAXIS_2 and so on.
	 * @return The location in the plane such as AXIS_HORIZONTAL_1.
	 */
	public int getLocationInPlane( final int locationInCube )
	{
		int loc = -1;
		switch( this.mViewDirection )
		{
			case VIEW_XY :
			{
				switch( locationInCube )
				{
					case LOCATION_XAXIS_1 :
					{
						loc = AXIS_HORIZONTAL_1;
						break;
					}
					case LOCATION_XAXIS_2 :
					{
						loc = AXIS_HORIZONTAL_2;
						break;
					}
					case LOCATION_XAXIS_3 :
					{
						loc = AXIS_HORIZONTAL_2;
						break;
					}
					case LOCATION_XAXIS_4 :
					{
						loc = AXIS_HORIZONTAL_1;
						break;
					}
					case LOCATION_YAXIS_1 :
					{
						loc = AXIS_PERPENDICULAR_1;
						break;
					}
					case LOCATION_YAXIS_2 :
					{
						loc = AXIS_PERPENDICULAR_1;
						break;
					}
					case LOCATION_YAXIS_3 :
					{
						loc = AXIS_PERPENDICULAR_2;
						break;
					}
					case LOCATION_YAXIS_4 :
					{
						loc = AXIS_PERPENDICULAR_2;
						break;
					}
				}

				break;
			}
			case VIEW_XZ :
			{
				// not implemented
				break;
			}
			case VIEW_YZ :
			{
				// not implemented
				break;
			}
			default :
			{
				throw new Error("not defined");
			}
		}

		return loc;
	}



	/**
	 * Returns a location on the edge of a cube from the location in a plane
	 * and the view direction.
	 * @param locationInPlane - AXIS_HORIZONTAL_1, AXIS_HORIZONTAL_2,
	 * 	AXIS_PERPENDICULAR_1 or AXIS_PERPENDICULAR_2.
	 * @return The location of the axis on the edge of a cube.
	 */
	public int getLocationInCube( final int locationInPlane )
	{
		int loc = -1;
		switch( this.mViewDirection )
		{
			case VIEW_XY :
			{
				switch( locationInPlane )
				{
					case AXIS_HORIZONTAL_1 :
					{
						loc = LOCATION_XAXIS_1;
						break;
					}
					case AXIS_HORIZONTAL_2 :
					{
						loc = LOCATION_XAXIS_2;
						break;
					}
					case AXIS_PERPENDICULAR_1 :
					{
						loc = LOCATION_YAXIS_1;
						break;
					}
					case AXIS_PERPENDICULAR_2 :
					{
						loc = LOCATION_YAXIS_4;
						break;
					}
				}

				break;
			}
			case VIEW_XZ :
			{
				// not implemented
				break;
			}
			case VIEW_YZ :
			{
				// not implemented
				break;
			}
			default :
			{
				throw new Error("not defined");
			}
		}

		return loc;
	}



	/**
	 * Returns a text string for the axis location in a plane.
	 * @param locationInCube
	 */
	public String getLocationString( final int locationInCube )
	{
		final int loc = this.getLocationInPlane( locationInCube );
		return this.getLocationName(loc);
	}



	/**
	 * Returns a location on the edge of a cube of given an axis.
	 * @param str - the location of axis in a plane: AXIS_BOTTOM, AXIS_TOP, AXIS_LEFT or AXIS_RIGHT.
	 * @return The location of the axis on the edge of a cube.
	 */
	public int getLocationInCube( final String str )
	{
		final int locationInPlane = this.getLocationInPlane(str);
		if( locationInPlane==-1 )
		{
			return -1;
		}
		final int locationInCube = this.getLocationInCube( locationInPlane );
		return locationInCube;
	}


	
	/**
	 * 
	 * @param str
	 * @return
	 */
	public SGAxis getAxis( final String str )
	{
		final int loc = this.getLocationInCube( str );
		final SGAxis axis = this.getAxisInCube( loc );
		return axis;
	}

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



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



	/**
	 * 
	 */
	private boolean mClickedFlag = false;


	/**
	 * 
	 * @return
	 */
	public ArrayList getPropertyDialogObserverList()
	{
		ArrayList list = new ArrayList();
		if( this.mClickedFlag )
		{
			list.add( this );
		}
		return list;
	}


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



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


	// edited string
	private SGDrawingElementString2D mEditingStringElement = null;


	// returns editing now
	private boolean isEditing()
	{
		return this.mTextField.isVisible();
	}


	/**
	 * 
	 */
	private boolean showEditField( SGDrawingElementString2D el )
	{
		JTextField tf = this.mTextField;

		this.mEditingStringElement = el;

		final Rectangle2D sRect = el.getStringRect();
		final Rectangle2D eRect = el.getElementBounds();
		final float fontSize = this.getMagnification()*this.getFontSize();

		final int x = (int)( eRect.getX() - tf.getInsets().left );
		final int y = (int)( eRect.getY() - fontSize/2.0f );
		final int w = (int)( sRect.getWidth() + fontSize );
		final int h = (int)( sRect.getHeight() + fontSize );
		tf.setLocation( x, y );
		tf.setSize( w, h );

		Font font = new Font( this.getFontName(), this.getFontStyle(), (int)(fontSize) );
		tf.setFont( font );
		tf.setForeground( this.mStringColor );
		tf.setText( el.getString() );

		// show the text field
		tf.setVisible(true);
		tf.requestFocus();
		tf.setCaretPosition(0);

		return true;
	}




	/**
	 * 
	 */
	public boolean commit()
	{
		// ダイアログを出す前後でプロパティが変更されている場合のみ、
		// 履歴を更新する
		SGProperties pTemp = this.mTemporaryProperties;
		SGProperties pPresent = this.getProperties();
		if( pTemp.equals(pPresent) == false )
		{
			// オブジェクト履歴を更新
			this.setChanged( true );
		}

		this.mTemporaryProperties = null;

		this.createAllDrawingElements();
		this.repaint();

		this.notifyChange();

		return true;
	}



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

		this.mTemporaryProperties = null;
		this.mDialog.setVisible(false);

		this.createAllDrawingElements();
		this.repaint();

		this.notifyChange();
		
		return true;
	}



	/**
	 * 
	 */
	public boolean preview()
	{

		if( this.createAllDrawingElements() == false )
		{
			return false;
		}
		this.repaint();

		this.notifyChange();

		return true;
	}




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

		this.createAllDrawingElements();
		this.notifyChangeOnUndo();

//		repaint();

		return true;
	}


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

		this.createAllDrawingElements();
		this.notifyChangeOnUndo();

//		repaint();

		return true;
	}


	
//	/**
//	 * 
//	 */
//	public boolean updateHistory()
//	{
//		return this.updateHistory( new ArrayList() );
//	}


	/**
	 * 
	 */
	private float getMaxLengthOfScaleNumbers( final ElementsGroupOfAxis group )
	{

		final ArrayList numberList = group.mNumberList;
		double maxLength = Double.MIN_VALUE;
		for( int ii=0; ii<numberList.size(); ii++ )
		{
			final SGDrawingElementString2D str = (SGDrawingElementString2D)numberList.get(ii);
			final Rectangle2D rect = str.getElementBounds();
			final double width = rect.getWidth();
//System.out.println(ii+"  "+width);
			if( width > maxLength )
			{
				maxLength = width;
			}
		}

		return (float)maxLength;
	}




	/**
	 * 
	 */
	private boolean createAllDrawingElements()
	{
//System.out.println("<< SGAxisElement::createAllDrawingElements >>");

		for( int ii=0; ii<this.mElementsGroupList.size(); ii++ )
		{
			final ElementsGroupOfAxis group = (ElementsGroupOfAxis)this.mElementsGroupList.get(ii);
			if( group.createDrawingElements() == false )
			{
				return false;
			}
		}

		return true;
	}


	/**
	 * 
	 */
	private boolean setLocationOfAllDrawingElements()
	{
		for( int ii=0; ii<this.mElementsGroupList.size(); ii++ )
		{
			final ElementsGroupOfAxis group = (ElementsGroupOfAxis)this.mElementsGroupList.get(ii);
			if( group.setLocationOfDrawingElements() == false )
			{
				return false;
			}
		}

		return true;
	}



	/**
	 * 
	 * @return
	 */
	public String getTagName()
	{
		return SGIFigureElementAxis.TAG_NAME_AXES;
	}

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

		// each axes
		for( int ii=0; ii<this.mElementsGroupList.size(); ii++ )
		{
			ElementsGroupOfAxis group = (ElementsGroupOfAxis)this.mElementsGroupList.get(ii);
			Element elAxis = group.createElement( document );
			if( elAxis==null )
			{
				return null;
			}
			el.appendChild( elAxis );
		}

		return el;
	}


	/**
	 * 
	 */
	public boolean createDataObject( final Element el, final SGData data )
	{
		if( super.createDataObject( el, data ) == false )
		{
			return false;
		}

		// set false the flag
		this.mStartFlag = false;

		return true;
	}
	

	/**
	 * 
	 */
	public boolean writeProperty( final Element el )
	{
		el.setAttribute( KEY_AXIS_LINE_WIDTH, Float.toString( this.mAxisLineWidth ) + SGIConstants.pt );
		el.setAttribute( KEY_TICK_MARK_WIDTH, Float.toString( this.mScaleLineWidth ) + SGIConstants.pt );
		el.setAttribute( KEY_TICK_MARK_LENGTH, Float.toString( this.mTickMarkLength*SGIConstants.CM_POINT_RATIO ) + SGIConstants.cm );
		el.setAttribute( KEY_LINE_COLOR, SGUtilityText.getColorString( this.mLineColor ) );

		el.setAttribute( KEY_FONT_NAME, this.mTitleFontName );
		el.setAttribute( KEY_FONT_SIZE, Float.toString( this.mTitleFontSize ) + SGIConstants.pt );
		el.setAttribute( KEY_FONT_STYLE, SGUtilityText.getFontStyleName( this.mTitleFontStyle ) );
		el.setAttribute( KEY_AXIS_STRING_COLOR, SGUtilityText.getColorString( this.mStringColor ) );

		el.setAttribute( KEY_FRAME_LINE_VISIBLE, Boolean.toString( this.mFrameLineVisibleFlag ) );
		el.setAttribute( KEY_FRAME_LINE_WIDTH, Float.toString( this.mFrameLineWidth ) + SGIConstants.pt );
		el.setAttribute( KEY_FRAME_LINE_COLOR, SGUtilityText.getColorString( this.mFrameLineColor ) );

		return true;
	}

	
	
	/**
	 * 
	 */
	public boolean readProperty( final Element element )
	{

		// add axis groups
		ElementsGroupOfAxis group = null;
		group = this.addAxisGroup( SGIFigureElementAxis.LOCATION_XAXIS_1 );
		if( group==null )
		{
			return false;
		}
		group = this.addAxisGroup( SGIFigureElementAxis.LOCATION_XAXIS_2 );
		if( group==null )
		{
			return false;
		}
		group = this.addAxisGroup( SGIFigureElementAxis.LOCATION_YAXIS_1 );
		if( group==null )
		{
			return false;
		}
		group = this.addAxisGroup( SGIFigureElementAxis.LOCATION_YAXIS_4 );
		if( group==null )
		{
			return false;
		}

		// create the property dialog
		if( this.createDialog( SGIFigureElementAxis.TWO_DIMENSIONAL_AXIS ) == false )
		{
			return false;
		}

		// set properties		
		if( this.setProperty( element ) == false )
		{
			return false;
		}
		
		return true;
	}

	

	/**
	 * 
	 * @param element
	 * @return
	 */
	private boolean setCommonProperties( final Element element )
	{
		String str = null;
		Number num = null;
		Color cl = null;
		Boolean b = null;

		// axis line width
		str = element.getAttribute( SGIFigureElementAxis.KEY_AXIS_LINE_WIDTH );
		if( str.length()==0 )
		{
			return false;
		}
		StringBuffer uAxisLineWidth = new StringBuffer();
		num = SGUtilityText.getNumber( str, uAxisLineWidth );
		if( num==null )
		{
			return false;
		}
		final float axisLineWidth = num.floatValue();

		
		// tick mark width
		str = element.getAttribute( SGIFigureElementAxis.KEY_TICK_MARK_WIDTH );
		if( str.length()==0 )
		{
			return false;
		}
		StringBuffer uTickMarkWidth = new StringBuffer();
		num = SGUtilityText.getNumber( str, uTickMarkWidth );
		if( num==null )
		{
			return false;
		}
		final float tickMarkWidth = num.floatValue();
		

		// tick mark length
		str = element.getAttribute( SGIFigureElementAxis.KEY_TICK_MARK_LENGTH );
		if( str.length()==0 )
		{
			return false;
		}
		StringBuffer uTickMarkLength = new StringBuffer();
		num = SGUtilityText.getNumber( str, uTickMarkLength );
		if( num==null )
		{
			return false;
		}
		final float tickMarkLength = num.floatValue();


		// line color
		str = element.getAttribute( SGIFigureElementAxis.KEY_LINE_COLOR );
		if( str.length()==0 )
		{
			return false;
		}
		final Color lineColor = SGUtilityText.getColorFromString(str);


		// font name
		str = element.getAttribute( KEY_FONT_NAME );
		if( str.length()==0 )
		{
			return false;
		}
		final String fontName = str;

		
		// font style
		str = element.getAttribute( KEY_FONT_STYLE );
		if( str.length()==0 )
		{
			return false;
		}
		final int fontStyle = SGUtilityText.getFontStyle(str);
		if( fontStyle==-1 )
		{
			return false;
		}

		
		// font size
		str = element.getAttribute( KEY_FONT_SIZE );
		if( str.length()==0 )
		{
			return false;
		}
		StringBuffer uFontSize = new StringBuffer();
		num = SGUtilityText.getNumber( str, uFontSize );
		if( num==null )
		{
			return false;
		}
		final float fontSize = num.floatValue();

		
		// string color
		str = element.getAttribute( KEY_AXIS_STRING_COLOR );
		if( str.length()==0 )
		{
			return false;
		}
		cl = SGUtilityText.getColorFromString(str);
		if( cl==null )
		{
			return false;
		}
		final Color stringColor = cl;

		
		// frame line visible
		str = element.getAttribute( SGIFigureElementAxis.KEY_FRAME_LINE_VISIBLE );
		if( str.length()==0 )
		{
			return false;
		}
		b = SGUtilityText.getBoolean(str);
		if( b==null )
		{
			return false;
		}
		final boolean frameLineVisible = b.booleanValue();
		
		
		// frame line width
		str = element.getAttribute( SGIFigureElementAxis.KEY_FRAME_LINE_WIDTH );
		if( str.length()==0 )
		{
			return false;
		}
		StringBuffer uFrameLineWidth = new StringBuffer();
		num = SGUtilityText.getNumber( str, uFrameLineWidth );
		if( num==null )
		{
			return false;
		}
		final float frameLineWidth = num.floatValue();
		
		
		// frame line color
		str = element.getAttribute( SGIFigureElementAxis.KEY_FRAME_LINE_COLOR );
		if( str.length()==0 )
		{
			return false;
		}
		cl = SGUtilityText.getColorFromString(str);
		if( cl==null )
		{
			return false;
		}
		final Color frameLineColor = cl;
		
		
		//
		// set properties
		//

		if( this.setAxisLineWidth( axisLineWidth, uAxisLineWidth.toString() ) == false )
		{
			return false;
		}

		if( this.setTickMarkWidth( tickMarkWidth, uTickMarkWidth.toString() ) == false )
		{
			return false;
		}

		if( this.setTickMarkLength( tickMarkLength, uTickMarkLength.toString() ) == false )
		{
			return false;
		}

		if( this.setLineColor( lineColor ) == false )
		{
			return false;
		}

		if( this.setStringColor( stringColor ) == false )
		{
			return false;
		}

		if( this.setFontName( fontName ) == false )
		{
			return false;
		}

		if( this.setFontStyle( fontStyle ) == false )
		{
			return false;
		}

		if( this.setFontSize( fontSize, uFontSize.toString() ) == false )
		{
			return false;
		}

		if( this.setFrameLineVisible( frameLineVisible ) == false )
		{
			return false;
		}

		if( this.setFrameLineWidth( frameLineWidth, uFrameLineWidth.toString() ) == false )
		{
			return false;
		}

		if( this.setFrameLineColor( frameLineColor ) == false )
		{
			return false;
		}

		return true;
	}



	/**
	 * 
	 * @param element
	 * @return
	 */
	private boolean setProperty( final Element element )
	{

		// set common properties
		if( this.setCommonProperties( element ) == false )
		{
			return false;
		}

		// set false the flag
		this.mStartFlag = false;		

		NodeList nList = element.getElementsByTagName( SGIFigureElementAxis.TAG_NAME_AXIS );
		for( int ii=0; ii<nList.getLength(); ii++ )
		{
			Node node = nList.item(ii);
			if( node instanceof Element )
			{
				Element el = (Element)node;

				// location
				String str = el.getAttribute( SGIFigureElementAxis.KEY_POSITION );
				if( str.length()==0 )
				{
					return false;
				}
				final int locInPlane = this.getLocationInPlane( str );
				if( locInPlane==-1 )
				{
					return false;
				}
				final int loc = this.getLocationInCube( locInPlane );

				// get the axis-group
				ElementsGroupOfAxis group = this.getAxisGroupInCube(loc);
				if( group.readAxisProperties( el ) == false )
				{
					return false;
				}
				
				if( group.createDrawingElements() == false )
				{
					return false;
				}
				
			}
		}

		return true;
	}



	public boolean setFontNameDirectly( final String value )
	{
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( this.setFontName( value ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}

	public boolean setFontStyleDirectly( final int value )
	{
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( this.setFontStyle( value ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}

	public boolean setFontSizeDirectly( final float value, final String unit )
	{
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( this.setFontSize( value, unit ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}
	
	public boolean setFontColorDirectly( final Color value )
	{
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( this.setStringColor( value ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}


	public boolean setFrameVisibleDirectly( final boolean value )
	{
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( this.setFrameVisible( value ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}

	public boolean setFrameLineWidthDirectly( final float value, final String unit )
	{
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( this.setFrameLineWidth( value, unit ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}

	public boolean setFrameLineColorDirectly( final Color cl )
	{
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( this.setFrameLineColor( cl ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}

	public boolean setAxisLineWidthDirectly( final float value, final String unit )
	{
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( this.setAxisLineWidth( value, unit ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}

	public boolean setTickMarkWidthDirectly( final float value, final String unit )
	{
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( this.setTickMarkWidth( value, unit ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}

	public boolean setTickMarkLengthDirectly( final float value, final String unit )
	{
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( this.setTickMarkLength( value, unit ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}

	public boolean setLineColorDirectly( final Color value )
	{
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( this.setLineColor( value ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}


	//
	private ElementsGroupOfAxis getAxisGroup( final String location )
	{
		final String l = location.toLowerCase();

		int loc = -1;
		if( AXIS_BOTTOM.toLowerCase().equals( l ) )
		{
			loc = AXIS_HORIZONTAL_1;
		}
		else if( AXIS_TOP.toLowerCase().equals( l ) )
		{
			loc = AXIS_HORIZONTAL_2;
		}
		else if( AXIS_LEFT.toLowerCase().equals( l ) )
		{
			loc = AXIS_PERPENDICULAR_1;
		}
		else if( AXIS_RIGHT.toLowerCase().equals( l ) )
		{
			loc = AXIS_PERPENDICULAR_2;
		}
		
		return this.getAxisGroupInPlane(loc);
	}


	public boolean setAxisVisibleDirectly( final String location, final boolean value )
	{
		ElementsGroupOfAxis g = this.getAxisGroup( location );
		if( g==null )
		{
			return false;
		}
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( g.setAxisVisible( value ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}


	public boolean setTitleVisibleDirectly( final String location, final boolean value )
	{
		ElementsGroupOfAxis g = this.getAxisGroup( location );
		if( g==null )
		{
			return false;
		}
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( g.setTitleVisible( value ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}

	public boolean setTitleDirectly( final String location, final String value )
	{
		ElementsGroupOfAxis g = this.getAxisGroup( location );
		if( g==null )
		{
			return false;
		}
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( g.setTitle( value ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}

	public boolean setMinValueDirectly( final String location, final double value )
	{
		ElementsGroupOfAxis g = this.getAxisGroup( location );
		if( g==null )
		{
			return false;
		}
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( g.setMinValue( value ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}

	public boolean setMaxValueDirectly( final String location, final double value )
	{
		ElementsGroupOfAxis g = this.getAxisGroup( location );
		if( g==null )
		{
			return false;
		}
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( g.setMaxValue( value ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}

	public boolean setScaleTypeDirectly( final String location, final int value )
	{
		ElementsGroupOfAxis g = this.getAxisGroup( location );
		if( g==null )
		{
			return false;
		}
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( g.setScaleType( value ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}

	public boolean setTickMarkVisibleDirectly( final String location, final boolean value )
	{
		ElementsGroupOfAxis g = this.getAxisGroup( location );
		if( g==null )
		{
			return false;
		}
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( g.setTickMarksVisible( value ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}

	public boolean setTickMarkAutoDirectly( final String location, final boolean value )
	{
		ElementsGroupOfAxis g = this.getAxisGroup( location );
		if( g==null )
		{
			return false;
		}
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( g.setCalculateAutomatically( value ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}

	public boolean setTickMarkStepDirectly( final String location, final double value )
	{
		ElementsGroupOfAxis g = this.getAxisGroup( location );
		if( g==null )
		{
			return false;
		}
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( g.setStepValue( value ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}

	public boolean setTickMarkBaseDirectly( final String location, final double value )
	{
		ElementsGroupOfAxis g = this.getAxisGroup( location );
		if( g==null )
		{
			return false;
		}
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( g.setBaselineValue( value ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}

	public boolean setTickMarkInnerDirectly( final String location, final boolean value )
	{
		ElementsGroupOfAxis g = this.getAxisGroup( location );
		if( g==null )
		{
			return false;
		}
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( g.setTickMarksInside( value ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}

	public boolean setFormatVisibleDirectly( final String location, final boolean value )
	{
		ElementsGroupOfAxis g = this.getAxisGroup( location );
		if( g==null )
		{
			return false;
		}
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( g.setNumbersVisible( value ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}

	public boolean setFormatIntegerDirectly( final String location, final boolean value )
	{
		ElementsGroupOfAxis g = this.getAxisGroup( location );
		if( g==null )
		{
			return false;
		}
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( g.setNumbersInteger( value ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}

	public boolean setFormatExponentVisibleDirectly( final String location, final boolean value )
	{
		ElementsGroupOfAxis g = this.getAxisGroup( location );
		if( g==null )
		{
			return false;
		}
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( g.setExponentFlag( value ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}

	public boolean setFormatExponentValueDirectly( final String location, final int value )
	{
		ElementsGroupOfAxis g = this.getAxisGroup( location );
		if( g==null )
		{
			return false;
		}
		if( this.setDirectlyBefore() == false )
		{
			return false;
		}
		if( g.setExponentValue( value ) == false )
		{
			return false;
		}
		return this.setDirectlyAfter();
	}


	private boolean setDirectlyBefore()
	{
		return this.prepare();
	}

	private boolean setDirectlyAfter()
	{
		if( this.commit() == false )
		{
			return false;
		}
		this.notifyChange();
		this.notifyToRoot();
		this.repaint();
		return true;
	}


	// axis line
	private static class ElementLineOfAxis extends SGDrawingElementLine2D
	{
		ElementLineOfAxis()
		{
			super();
		}
	}

	
	// axis title
	private static class ElementStringOfTitle extends SGDrawingElementString2DExtended
	{
		ElementStringOfTitle()
		{
			super();
		}
	}


	// line for tick marks
	private static class ElementLineOfScale extends SGDrawingElementLine2D
	{
		// value in scale
		private double mValue;

		ElementLineOfScale( final SGTuple2f start, final SGTuple2f end )
		{
			super( start, end );
		}

		ElementLineOfScale( final ElementLineOfScale el )
		{
			super();
			this.mValue = el.mValue;
		}
	}


	// string for scale numbers
	private static class ElementStringOfScale
		extends SGDrawingElementString2DExtended
	{
		// value in scale
		private double mValue;

		ElementStringOfScale(
			final String str,
			final String fontName,
			final int fontStyle,
			final float fontSize,
			final Color fontColor,
			final float mag,
			final float angle )
		{
			super( str, fontName, fontStyle, fontSize, fontColor, mag, angle );
		}

		ElementStringOfScale( final ElementStringOfScale el )
		{
			super(el);
			this.mValue = el.mValue;
		}
	}



	// a class for single axis
	/**
	 * @author  okumura
	 */
	private class ElementsGroupOfAxis
		implements ActionListener, SGIAxisPanelObserver, SGIDisposable
	{

		/**
		 * 
		 */
		private int mLocationInCube = -1;


		/**
		 * 
		 */
		private SGAxis mAxis = null;


		/**
		 * 
		 */
		private ElementLineOfAxis mAxisLine = new ElementLineOfAxis();


		/**
		 * 
		 */
		private ElementStringOfTitle mTitle = new ElementStringOfTitle();;


		/**
		 * 
		 */
		private final ArrayList mNumberList = new ArrayList();


		/**
		 * 
		 */
		private final ArrayList mTickMarksList = new ArrayList();


		/**
		 * 
		 */
		private boolean mVisibleFlag = true;


		/**
		 * 
		 */
//		private boolean mAxisLineVisibleFlag = true;


		/**
		 * 
		 */
		private boolean mTitleVisibleFlag = true;


		/**
		 * 
		 */
		private boolean mNumbersVisibleFlag = true;


		/**
		 * 
		 */
		private boolean mTickMarksVisibleFlag = true;


		/**
		 * 
		 */
		private boolean mTickMarksInsideFlag = true;


		/**
		 * 
		 */
		private double[] mAxisValueArray = null;


		/**
		 * 
		 */
		private boolean mAutoCalcFlag = true;


		/**
		 * 
		 */
		private double mStepValue = 0.0;


		/**
		 * 
		 */
		private double mBaselineValue = 0.0;


		/**
		 * 
		 */
		private boolean mScaleNumbersIntegerFlag = false;


		/**
		 * 
		 */
		private boolean mExponentFlag = false;


		/**
		 * 
		 */
		private int mExponentValue = 0;


		/**
		 * 
		 */
		private SGDrawingElementString2DExtended mExponentDrawingElement = null;


		/**
		 * 
		 */
		private SGDrawingElement mDraggingElement = null;


		/**
		 * 
		 */
		private JPopupMenu mPopupMenu = new JPopupMenu();


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


		/**
		 * 
		 */
		private boolean init()
		{
			this.setNumbersVisible( DEFAULT_NUMBER_VISIBLE );
			this.setNumbersInteger( DEFAULT_NUMBER_INTEGER );
			this.setTickMarksVisible( DEFAULT_SCALE_LINE_VISIBLE );
			this.setTickMarksInside( DEFAULT_SCALE_LINE_INNER );

			this.createPopupMenu();

			return true;
		}


		/**
		 * 
		 */
		public void dispose()
		{
			this.mAxis = null;
			this.mAxisValueArray = null;

			this.mAxisLine.dispose();
			this.mAxisLine = null;

			ArrayList nList = this.mNumberList;
			for( int ii=0; ii<nList.size(); ii++ )
			{
				SGDrawingElementString el = (SGDrawingElementString)nList.get(ii);
				el.dispose();
			}
			this.mNumberList.clear();

			ArrayList tList = this.mTickMarksList;
			for( int ii=0; ii<tList.size(); ii++ )
			{
				SGDrawingElementLine el = (SGDrawingElementLine)tList.get(ii);
				el.dispose();
			}
			this.mTickMarksList.clear();

			this.mTitle.dispose();
			this.mTitle = null;

			this.mPopupMenu = null;
		}


		/**
		 * 
		 * @return
		 */
		public boolean isAxisVisible()
		{
			return this.mVisibleFlag;
		}


		/**
		 * 
		 * @return
		 */	
		public boolean isTitleVisible()
		{
			return this.mTitleVisibleFlag;
		}


		/**
		 * 
		 * @return
		 */
		public String getTitleString()
		{
			return this.mTitle.getString();
		}


		/**
		 * 
		 * @return
		 */
		public double getMinValue()
		{
			return this.mAxis.getMinValue();
		}

	
		/**
		 * 
		 * @return
		 */
		public double getMaxValue()
		{
			return this.mAxis.getMaxValue();
		}

		/**
		 * 
		 * @return
		 */
		public boolean isInvertCoordinates()
		{
			return this.mAxis.isInvertCoordinates();
		}
		
		/**
		 * 
		 * @return
		 */
		public int getScaleType()
		{
			return this.mAxis.getScaleType();
		}


		/**
		 * 
		 * @return
		 */
		public boolean isCalculateAutomatically()
		{
			return this.mAutoCalcFlag;
		}


		/**
		 * 
		 * @return
		 */
		public double getStepValue()
		{
			return this.mStepValue;
		}


		/**
		 * 
		 * @return
		 */
		public double getBaselineValue()
		{
			return this.mBaselineValue;
		}


		/**
		 * 
		 * @return
		 */
		public boolean isTickMarksVisible()
		{
			return this.mTickMarksVisibleFlag;
		}


		/**
		 * 
		 * @return
		 */
		public boolean isTickMarksInside()
		{
			return this.mTickMarksInsideFlag;
		}


		/**
		 * 
		 * @return
		 */
		public boolean isNumbersVisible()
		{
			return this.mNumbersVisibleFlag;
		}


		/**
		 * 
		 * @return
		 */
		public boolean isNumbersInteger()
		{
			return this.mScaleNumbersIntegerFlag;
		}


		/**
		 * 
		 * @return
		 */
		public boolean getExponentFlag()
		{
			return this.mExponentFlag;
		}


		/**
		 * 
		 * @return
		 */
		public int getExponentValue()
		{
			return this.mExponentValue;
		}



		/**
		 * 
		 * @param b
		 * @return
		 */
		public boolean setAxisVisible( final boolean b )
		{
			this.mVisibleFlag = b;
			return true;
		}


		/**
		 * 
		 * @param value
		 * @return
		 */
		public boolean setAxisVisible( final String value )
		{
			Boolean b = SGUtilityText.getBoolean( value );
			if( b==null )
			{
				return false;
			}
			return this.setAxisVisible( b.booleanValue() );
		}


		/**
		 * 
		 * @param b
		 * @return
		 */
		public boolean setTitleVisible( final boolean b )
		{
			this.mTitleVisibleFlag = b;
			return true;
		}


		/**
		 * 
		 * @param str
		 * @return
		 */
		public boolean setTitle( final String str )
		{
			this.mTitle.setString( str );
			return true;
		}


		/**
		 * 
		 * @param value
		 * @return
		 */
		public boolean setMinValue( final double value )
		{
			final double max = this.getMaxValue();
			if( max <= value ) return false;
			this.mAxis.setRange( value, this.getMaxValue() );
			return true;
		}


		/**
		 * 
		 * @param value
		 * @return
		 */
		public boolean setMaxValue( final double value )
		{
			final double min = this.getMinValue();
			if( min >= value ) return false;
			this.mAxis.setRange( min, value );
			return true;
		}

		
		/**
		 * 
		 * @param value
		 * @return
		 */
		public boolean setInvertCoordinates( final boolean b )
		{
			this.mAxis.setInvertCoordinates( b );
			return true;
		}
		
		
		/**
		 * 
		 * @param minValue
		 * @param maxValue
		 * @return
		 */
		public boolean setAxisRange(
			final double minValue, final double maxValue )
		{
			if( maxValue <= minValue )
			{
				return false;
			}
			this.mAxis.setRange( minValue, maxValue );
			return true;
		}


		/**
		 * 
		 * @param type
		 * @return
		 */
		public boolean setScaleType( final int type )
		{
			this.mAxis.setScaleType( type );
			return true;
		}


		/**
		 * 
		 * @param b
		 * @return
		 */
		public boolean setCalculateAutomatically( final boolean b )
		{
			this.mAutoCalcFlag = b;
			return true;
		}


		/**
		 * 
		 * @param value
		 * @return
		 */
		public boolean setStepValue( final double value )
		{
			if( value == 0.0 ) return false;
			this.mStepValue = value;
			return true;
		}


		/**
		 * 
		 * @param value
		 * @return
		 */
		public boolean setBaselineValue( final double value )
		{
			this.mBaselineValue = value;
			return true;
		}


		/**
		 * 
		 * @param b
		 * @return
		 */
		public boolean setTickMarksVisible( final boolean b )
		{
			this.mTickMarksVisibleFlag = b;
			return true;
		}


		/**
		 * 
		 * @param b
		 * @return
		 */
		public boolean setTickMarksInside( final boolean b )
		{
			this.mTickMarksInsideFlag = b;
			return true;
		}


		/**
		 * 
		 * @param b
		 * @return
		 */
		public boolean setNumbersVisible( final boolean b )
		{
			this.mNumbersVisibleFlag = b;
			return true;
		}


		/**
		 * 
		 * @param b
		 * @return
		 */
		public boolean setNumbersInteger( final boolean b )
		{
			this.mScaleNumbersIntegerFlag = b;
			return true;
		}


		/**
		 * 
		 * @param b
		 * @return
		 */
		public boolean setExponentFlag( final boolean b )
		{
			this.mExponentFlag = b;
			return true;
		}


		/**
		 * 
		 * @param value
		 * @return
		 */
		public boolean setExponentValue( final int value )
		{
			if( value < AXIS_EXPONENT_MIN ) return false;
			if( value > AXIS_EXPONENT_MAX ) return false;
			this.mExponentValue = value;
			return true;
		}


		/**
		 * 
		 * @return
		 */
		public boolean hasValidAxisValues(
			final Number minValue, final Number maxValue, final Integer scaleType,
			final Number baseValue, final Number stepValue )
		{
			final double min = (minValue!=null) ? minValue.doubleValue() : this.getMinValue();
			final double max = (maxValue!=null) ? maxValue.doubleValue() : this.getMaxValue();
			final int type = (scaleType!=null) ? scaleType.intValue() : this.getScaleType();
//			final double base = (baseValue!=null) ? baseValue.doubleValue() : this.getBaselineValue();
			final double step = (stepValue!=null) ? stepValue.doubleValue() : this.getStepValue();

			// min and max values
			if( min >= max )
			{
				return false;
			}

			// scale type
			if( type==SGAxis.LOG_SCALE )
			{
				if( min <= 0.0 )
				{
					return false;
				}
			}

			// step value
			if( step == 0.0 )
			{
				return false;
			}

//			final double range = max - min;
//			final int rangeOrder = SGUtilityNumber.getOrder(range);
//			final int stepOrder = SGUtilityNumber.getOrder(step);
//			if( stepOrder < rangeOrder -1 )
//			{
//				return false;
//			}

			return true;
		}


		/**
		 * 
		 * @param minValue
		 * @param maxValue
		 * @param scaleType
		 * @return
		 */
		public boolean hasValidAxisRange(
			final Number minValue, final Number maxValue, final Integer scaleType )
		{
			final int type = (scaleType!=null) ? scaleType.intValue() : this.getScaleType();
			final double min = (minValue!=null) ? minValue.doubleValue() : this.getMinValue();
			final double max = (maxValue!=null) ? maxValue.doubleValue() : this.getMaxValue();

			if( min >= max )
			{
				return false;
			}

			if( type==SGAxis.LOG_SCALE )
			{
				if( min <= 0.0 )
				{
					return false;
				}
			}

			return true;
		}


		/**
		 * 
		 * @param baseValue
		 * @param stepValue
		 * @param scaleType
		 * @return
		 */
		public boolean hasValidAxisValues(
			final Number baseValue, final Number stepValue, final Integer scaleType )
		{
//			final int type = (scaleType!=null) ? scaleType.intValue() : this.getScaleType();
//			final double base = (baseValue!=null) ? baseValue.doubleValue() : this.getBaselineValue();
			final double step = (stepValue!=null) ? stepValue.doubleValue() : this.getStepValue();

			if( step == 0.0 )
			{
				return false;
			}

			return true;
		}



		/**
		 * 
		 */
		private boolean createPopupMenu()
		{
			JPopupMenu p = this.mPopupMenu;
			p.setBounds( 0, 0, 100, 100 );

			p.add( new JLabel( "  -- Axis --" ) );
			p.addSeparator();
			
			SGUtility.addItem( p, this, MENUCMD_HIDE );

			p.addSeparator();

			SGUtility.addCheckBoxItem( p, this, MENUCMD_DRAW_LATER );

			p.addSeparator();

			SGUtility.addItem( p, this, MENUCMD_PROPERTY );

			return true;
		}



		/**
		 * 
		 */
		public void actionPerformed( ActionEvent e )
		{
//			Object source = e.getSource();
			String command = e.getActionCommand();
			
			if( command.equals( MENUCMD_HIDE ) )
			{
				this.setAxisVisible(false);
				repaint();
				setChanged(true);
				notifyToRoot();
				return;
			}
			else if( command.equals( MENUCMD_PROPERTY ) )
			{
				this.showPropertyDialog();
			}
			else if( command.equals( MENUCMD_DRAW_LATER) )
			{
				mNotifyChangeOnDraggingFlag = !mNotifyChangeOnDraggingFlag;
			}

		}



		/**
		 * Show the property dialog.
		 *
		 */
		private void showPropertyDialog()
		{
			SGFigureElementAxis.this.mClickedFlag = true;
			SGFigureElementAxis.this.mTempAxisLocation = this.getLocationInPlane();

			SGFigureElementAxis.this.setPropertiesOfSelectedObjects();

			SGFigureElementAxis.this.mClickedFlag = false;
			SGFigureElementAxis.this.mTempAxisLocation = -1;
		}


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

			if( this.isAxisVisible() )
			{
				// axis line
//				if( this.mAxisLineVisibleFlag )
				{
					ElementLineOfAxis line = this.mAxisLine;
					final float width = SGFigureElementAxis.this.mMagnification*line.getLineWidth();
					BasicStroke stroke = new BasicStroke(
						width, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER );
					drawLine( line, g2d, stroke );
				}

				// title
				if( this.isTitleVisible() )
				{
					drawString( this.mTitle, g2d );
					if( this.mTitle.equals( SGFigureElementAxis.this.mPressedElement ) )
					{
						drawStringBounds( this.mTitle, g2d );
					}
				}

				// scale numbers
				if( this.isNumbersVisible() )
				{
					final ArrayList nList = this.mNumberList;
					for( int jj=0; jj<nList.size(); jj++ )
					{
						final ElementStringOfScale el
							= (ElementStringOfScale)nList.get(jj);
						drawString( el, g2d );
//						drawStringBounds( el, g2d );
					}

					// draw temporary number
					if( this.mDraggingElement != null )
					{
						if( this.mDraggingElement instanceof ElementStringOfScale )
						{
							ElementStringOfScale el
								= (ElementStringOfScale)this.mDraggingElement;
							drawString(el,g2d);
							drawStringBounds(el,g2d);
						}
					}

					// exponent
					if( this.getExponentFlag() )
					{
						drawString( this.mExponentDrawingElement, g2d );
					}
				}

				// scale lines
				if( this.isTickMarksVisible() )
				{
					final ArrayList lList = this.mTickMarksList;
					final boolean flag
						= ( this.mDraggingElement != null )
							& ( this.mDraggingElement instanceof ElementLineOfScale );
					final float width = SGFigureElementAxis.this.mMagnification * SGFigureElementAxis.this.mScaleLineWidth;
					final float width_ = flag ? width*2.0f : width;

					if( flag )
					{
						for( int ii=0; ii<lList.size(); ii++ )
						{
							final ElementLineOfScale el
								= (ElementLineOfScale)lList.get(ii);
							el.setLineWidth( width_ );
						}
					}

					BasicStroke stroke = new BasicStroke(
						width_, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL );
					for( int ii=0; ii<lList.size(); ii++ )
					{
						final ElementLineOfScale el
							= (ElementLineOfScale)lList.get(ii);
						drawLine( el, g2d, stroke );
					}

					if( flag )
					{
						for( int ii=0; ii<lList.size(); ii++ )
						{
							final ElementLineOfScale el
								= (ElementLineOfScale)lList.get(ii);
							el.setLineWidth( width );
						}
					}

				}


//				// rubber band
//				if( !mNotifyChangeOnDraggingFlag )
//				{
//					if( this.mDraggingElement!=null )
//					{
//						g2d.setStroke( new BasicStroke(5) );
//						g2d.setColor( Color.RED );
//						g2d.draw( this.mTempRectangle );
//					}
//				}

			}

		}



		/**
		 * 
		 */
		private double getTitleHeight()
		{
			Rectangle2D rect = this.mTitle.getStringRect();
			return rect.getHeight();
		}



		/**
		 * 
		 */
		private double getScaleHeight()
		{
			double height = 0.0;
			if( this.mNumberList.size() == 0 )
			{
				final Font font = new Font(
					SGFigureElementAxis.this.mScaleFontName,
					SGFigureElementAxis.this.mScaleFontStyle,
					(int)(SGFigureElementAxis.this.mMagnification * SGFigureElementAxis.this.mScaleFontSize)
					);
				final Rectangle2D rect = font.getStringBounds(
					"",	new FontRenderContext( null, false, false ) );
				height = rect.getHeight();
			}
			else
			{
				SGDrawingElementString2D el
					= (SGDrawingElementString2D)this.mNumberList.get(0);
				Rectangle2D rect = el.getStringRect();
				height = rect.getHeight();
			}
			return height;
		}


		/**
		 * 
		 */
		private int getLocationInPlane()
		{
			return SGFigureElementAxis.this.getLocationInPlane( this.mLocationInCube );
		}


		/**
		 * 
		 */
		private int getLocationInCube()
		{
			return this.mLocationInCube;
		}


		/**
		 * 
		 */
		private boolean setLocationInPlane( final int locationInPlane )
		{
			this.mLocationInCube = SGFigureElementAxis.this.getLocationInCube( locationInPlane );
			return true;
		}


		/**
		 * 
		 */
		private boolean setLocationInCube( final int locationInCube )
		{
			this.mLocationInCube = locationInCube;
			return true;
		}


		/**
		 * ズーム
		 */
		public boolean zoom( final float mag )
		{
			this.mAxisLine.zoom(mag);

			this.mTitle.zoom(mag);

			ArrayList nList = this.mNumberList;
			for( int ii=0; ii<nList.size(); ii++ )
			{
				ElementStringOfScale el = (ElementStringOfScale)nList.get(ii);
				el.zoom(mag);
			}
			
			ArrayList tList = this.mTickMarksList;
			for( int ii=0; ii<tList.size(); ii++ )
			{
				ElementLineOfScale el = (ElementLineOfScale)tList.get(ii);
				el.zoom(mag);
			}

			if( this.mExponentDrawingElement!=null )
			{
				this.mExponentDrawingElement.zoom(mag);
			}

			return true;
		}



		/**
		 * 
		 * @return
		 */
		private Rectangle2D getBoundingBox()
		{
			if( this.isAxisVisible() == false )
			{
				return null;
			}

			Rectangle2D rect = new Rectangle2D.Float();

			ArrayList list = new ArrayList();

			list.add( this.mAxisLine );

			if( this.isTitleVisible() )
			{
				list.add( this.mTitle );
			}

			if( this.isNumbersVisible() )
			{
				ArrayList nList = this.mNumberList;
				for( int ii=0; ii<nList.size(); ii++ )
				{
					ElementStringOfScale el = (ElementStringOfScale)nList.get(ii);
					if( el.isVisible() )
					{
						list.add(el);
					}
				}

				if( this.getExponentFlag() )
				{
					list.add( this.mExponentDrawingElement );
				}
			}

			if( list.size()!=0 )
			{
				rect.setRect( SGUtilityJava2D.getBoundingBox(list) );
			}

			return rect;
		}





		/**
		 * 
		 */
		public boolean onMouseClicked( final MouseEvent e )
		{
			int x = e.getX();
			int y = e.getY();

			boolean flag;

			// check axis line even when axis is invisible
			flag = this.mAxisLine.contains(x,y);
			if( flag )
			{
				return this.clicked(e);
			}

			// return if axis is invisible
			if( !this.isAxisVisible() )
			{
				return false;
			}

			// title
			if( this.isTitleVisible() )
			{
				flag = this.mTitle.contains(x,y);
				if( flag )
				{
					if( SGFigureElementAxis.this.isEditing() )
					{
						SGFigureElementAxis.this.terminateEditField();
					}

					if( (SwingUtilities.isLeftMouseButton(e) )
						& ( e.getClickCount() == 1 ) )
					{
//						if( SGAxisElement.this.isEditing() )
//						{
//							SGAxisElement.this.terminateEditField();
//						}
//						else
						{
							SGFigureElementAxis.this.showEditField( this.mTitle );
						}

						return true;
					}
					return this.clicked(e);
				}
			}


			// numbers of axis
			if( this.isNumbersVisible() )
			{
				ArrayList list = this.mNumberList;
				for( int ii=0; ii<list.size(); ii++ )
				{
					ElementStringOfScale el = (ElementStringOfScale)list.get(ii);
					flag = el.contains(x,y);
					if( flag )
					{
						return this.clicked(e);
					}
				}
			}


			// scale lines of axis
			if( this.isTickMarksVisible() )
			{
				ArrayList list = this.mTickMarksList;
				for( int ii=0; ii<list.size(); ii++ )
				{
					ElementLineOfScale el = (ElementLineOfScale)list.get(ii);
					flag = el.contains(x,y);
					if( flag )
					{
						return this.clicked(e);
					}
				}
			}


			return false;
		}



		/**
		 * 
		 */
		private boolean clicked( final MouseEvent e )
		{
			final int x = e.getX();
			final int y = e.getY();
			final int cnt = e.getClickCount();

			if( (SwingUtilities.isRightMouseButton(e) )
				& ( cnt == 1 ) )
			{
				this.updatePopupMenu();
				SGFigureElementAxis.this.showPopupMenu( this.mPopupMenu, x, y );
			}
			else if( (SwingUtilities.isLeftMouseButton(e) )
				& ( cnt == 2 ) )
			{
				this.showPropertyDialog();
			}

			return true;
		}


		private void updatePopupMenu()
		{
			Component[] array = this.mPopupMenu.getComponents();
			for( int ii=0; ii<array.length; ii++ )
			{
				if( array[ii] instanceof JMenuItem )
				{
					JMenuItem item = (JMenuItem)array[ii];
					String com = item.getActionCommand();
					if( com.equals( MENUCMD_DRAW_LATER ) )
					{
						item.setSelected( !SGFigureElementAxis.mNotifyChangeOnDraggingFlag );
					}
				}
			}
		}



//		private Rectangle mTempRectangle = null;


		/**
		 * 
		 */
		public boolean onMousePressed( final MouseEvent e )
		{
//System.out.println("$$ onMousePressed $$");

			// If this axis-group is invisible, return false
			if( !this.isAxisVisible() )
			{
				return false;
			}

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

			boolean flag;

			
			// axis line
			flag = this.mAxisLine.contains(x,y);
			if( flag )
			{
				return true;
			}


			// title
			if( this.isTitleVisible() )
			{
				flag = this.mTitle.contains(x,y);
				if( flag )
				{
					SGFigureElementAxis.this.mPressedElement = this.mTitle;
					SGFigureElementAxis.this.mPressedElementOrigin = new Point(
						(int)(e.getX()-this.mTitle.getX()),
						(int)(e.getY()-this.mTitle.getY())
					);
					return true;
				}
			}


			// numbers for axis
			if( this.isNumbersVisible() )
			{
				ArrayList nList = this.mNumberList;
				for( int ii=0; ii<nList.size(); ii++ )
				{
					ElementStringOfScale el = (ElementStringOfScale)nList.get(ii);
					if( el.isVisible() == false )
					{
						continue;
					}
					if( el.contains(x,y) )
					{
						SGFigureElementAxis.this.mPressedElement = el;
						SGFigureElementAxis.this.mPressedElementOrigin = new Point(
							(int)(e.getX()-el.getX()),
							(int)(e.getY()-el.getY())
						);
						this.mTempRange = this.mAxis.getRange();
//						this.mTempRectangle = new Rectangle();
						this.mDraggingElement = new ElementStringOfScale(el);
						this.mDraggingElement.setMagnification( el.getMagnification() );

						return true;
					}
				}
			}


			// scale lines for axis
			if( this.isTickMarksVisible() )
			{
				ArrayList lList = this.mTickMarksList;
				for( int ii=0; ii<lList.size(); ii++ )
				{
					ElementLineOfScale el = (ElementLineOfScale)lList.get(ii);
					if( el.isVisible() == false )
					{
						continue;
					}
					if( el.contains(x,y) )
					{
						SGFigureElementAxis.this.mPressedElement = el;
						SGFigureElementAxis.this.mPressedElementOrigin = e.getPoint();
						this.mTempRange = this.mAxis.getRange();
//						this.mTempRectangle = new Rectangle();
						this.mDraggingElement = new ElementLineOfScale(el);
						this.mDraggingElement.setMagnification( el.getMagnification() );
						return true;
					}
				}
			}


			return false;
		}



		/**
		 * 
		 */
		private SGTuple2d mTempRange = null;



		/**
		 * 
		 */
		public boolean onMouseDragged( final MouseEvent e )
		{
//System.out.println("<< ElementGroupOfAxis::onMouseDragged >>");

			if( this.mDraggingElement==null | this.mTempRange==null )
			{
				return false;
			}

			final int loc = this.getLocationInPlane();
			final int h1 = AXIS_HORIZONTAL_1;
			final int h2 = AXIS_HORIZONTAL_2;
			final int p1 = AXIS_PERPENDICULAR_1;
			final int p2 = AXIS_PERPENDICULAR_2;

			final boolean invcoord = this.mAxis.isInvertCoordinates();
			
			final int scaleType = this.mAxis.getScaleType();

			final Rectangle2D gRect = SGFigureElementAxis.this.getGraphRect();
			final int gx = (int)gRect.getX();
			final int gy = (int)gRect.getY();
			final int gw = (int)gRect.getWidth();
			final int gh = (int)gRect.getHeight();


			// rubber band
			int rbx = gx;
			int rby = gy;
			int rbw = gw;
			int rbh = gh;


			//
			// ElementStringOfScale
			//

			if( this.mDraggingElement instanceof ElementStringOfScale )
			{

				final ElementStringOfScale el
					= (ElementStringOfScale)this.mDraggingElement;
				final Rectangle2D rect = el.getElementBounds();

				double minValueTempInScale;
				double maxValueTempInScale;
				double oldValueInScale;
				if( scaleType==SGAxis.LINEAR_SCALE )
				{
					minValueTempInScale = this.mTempRange.x;
					maxValueTempInScale = this.mTempRange.y;
					oldValueInScale = el.mValue;
				}
				else if( scaleType==SGAxis.LOG_SCALE )
				{
					minValueTempInScale = Math.log(this.mTempRange.x)/Math.log(10.0);
					maxValueTempInScale = Math.log(this.mTempRange.y)/Math.log(10.0);
					oldValueInScale = Math.log(el.mValue)/Math.log(10.0);
				}
				else
				{
					throw new Error();
				}


				double minValueInScale;
				double maxValueInScale;

				// horizontal axes
				if( (loc==h1) | (loc==h2) )
				{

					double draggedCoordinate = e.getX() - SGFigureElementAxis.this.mPressedElementOrigin.x + rect.getWidth()/2.0;
					final float minCoordinate = this.mAxisLine.getStart().x;
					final float maxCoordinate = this.mAxisLine.getEnd().x;
//					final float width = maxCoordinate - minCoordinate;

					if( invcoord ) {
						if( draggedCoordinate < minCoordinate )
						{
							draggedCoordinate = minCoordinate;
						}
						if( draggedCoordinate >= maxCoordinate )
						{
							return false;
						}
					} else {
						if( draggedCoordinate > maxCoordinate )
						{
							draggedCoordinate = maxCoordinate;
						}
						if( draggedCoordinate <= minCoordinate )
						{
							return false;
						}
					}
						
					double valueInScale;
					if (invcoord )
						valueInScale = minValueTempInScale
						+ ( maxValueTempInScale - minValueTempInScale )
						*( maxCoordinate - draggedCoordinate )
						/( maxCoordinate - minCoordinate );
					else
						valueInScale = minValueTempInScale
						+ ( maxValueTempInScale - minValueTempInScale )
							*( draggedCoordinate - minCoordinate )
							/( maxCoordinate - minCoordinate );

					// 新しいレンジの取得
					minValueInScale = minValueTempInScale;
					maxValueInScale = minValueTempInScale
						+ (maxValueTempInScale-minValueTempInScale)
							*(oldValueInScale-minValueTempInScale)/(valueInScale-minValueTempInScale);

					if( scaleType==SGAxis.LINEAR_SCALE )
					{
						maxValueInScale = getNumberInRangeOrder( maxValueInScale, this.mAxis);
					}

					final float x = (float)(draggedCoordinate-rect.getWidth()/2.0);
					el.setX(x);

					final float ratio = (float)((maxValueInScale-minValueInScale)/(maxValueTempInScale-minValueTempInScale));
					if( ratio < 0.05 )
					{
						return false;
					}


					// rubber band
					rbw = (int)(gw/ratio);

				}
				// perpendicular axes
				else if( (loc==p1) | (loc==p2) )
				{

					float draggedCoordinate = e.getY() - SGFigureElementAxis.this.mPressedElementOrigin.y + (float)rect.getHeight()/2.0f;
					final float minCoordinate = this.mAxisLine.getEnd().y;
					final float maxCoordinate = this.mAxisLine.getStart().y;
//					final float width = maxCoordinate - minCoordinate;

					if( invcoord )
					{
						if( draggedCoordinate <= minCoordinate )
						{
							return false;
						}
						if( draggedCoordinate > maxCoordinate )
						{
							draggedCoordinate = maxCoordinate;
						}
					}
					else
					{
						if( draggedCoordinate >= maxCoordinate )
						{
							return false;
						}
						if( draggedCoordinate < minCoordinate )
						{
							draggedCoordinate = minCoordinate;
						}
					}
					
					double valueInScale;
					if ( invcoord )
						valueInScale = minValueTempInScale
							+ ( maxValueTempInScale - minValueTempInScale )
								*( 1.0 - ( maxCoordinate - draggedCoordinate )/( maxCoordinate - minCoordinate ) );
					else
						valueInScale = minValueTempInScale
							+ ( maxValueTempInScale - minValueTempInScale )
								*( 1.0 - ( draggedCoordinate - minCoordinate )/( maxCoordinate - minCoordinate ) );

					// 新しいレンジの取得
					minValueInScale = minValueTempInScale;
					maxValueInScale = minValueTempInScale
						+ (maxValueTempInScale-minValueTempInScale)
							*(oldValueInScale-minValueTempInScale)/(valueInScale-minValueTempInScale);

					if( scaleType==SGAxis.LINEAR_SCALE )
					{
						maxValueInScale = getNumberInRangeOrder( maxValueInScale, this.mAxis);
					}

					final float y = (float)(draggedCoordinate-rect.getHeight()/2.0);
					el.setY(y);

					final float ratio = (float)((maxValueInScale-minValueInScale)/(maxValueTempInScale-minValueTempInScale));
					if( ratio < 0.05 )
					{
						return false;
					}

					// rubber band
					rbh = (int)(gh/ratio);
					rby = gy + gh - rbh;

				}
				else
				{
					throw new Error();
				}


				// 軸にレンジを設定
				double minValue;
				double maxValue;
				if( scaleType==SGAxis.LINEAR_SCALE )
				{
					minValue = minValueInScale;
					maxValue = maxValueInScale;
				}
				else if( scaleType==SGAxis.LOG_SCALE )
				{
					minValue = Math.pow( 10.0, minValueInScale );
					maxValue = Math.pow( 10.0, maxValueInScale );
				}
				else
				{
					throw new Error();
				}

				this.mAxis.setRange( minValue, maxValue );


			}
			//
			// ElementLineOfScale
			//
			else if( this.mDraggingElement instanceof ElementLineOfScale )
			{

				final ElementLineOfScale el = (ElementLineOfScale)this.mDraggingElement;

				double minValueTempInScale;
				double maxValueTempInScale;
				double oldValueInScale;
				if( scaleType==SGAxis.LINEAR_SCALE )
				{
					minValueTempInScale = this.mTempRange.x;
					maxValueTempInScale = this.mTempRange.y;
					oldValueInScale = el.mValue;
				}
				else if( scaleType==SGAxis.LOG_SCALE )
				{
					minValueTempInScale = Math.log(this.mTempRange.x)/Math.log(10.0);
					maxValueTempInScale = Math.log(this.mTempRange.y)/Math.log(10.0);
					oldValueInScale = Math.log(el.mValue)/Math.log(10.0);
				}
				else
				{
					throw new Error();
				}


				double minValueInScale;
				double maxValueInScale;

				// horizontal axes
				if( (loc==h1) | (loc==h2) )
				{

					// マウスボタンをリリースした位置の座標値の計算
					float releasedCoordinate = e.getX();
					if( SGFigureElementAxis.this.mPressedElementOrigin.x == releasedCoordinate )
					{
						return false;
					}

					float minCoordinate = this.mAxisLine.getStart().x;
					float maxCoordinate = this.mAxisLine.getEnd().x;
					
					if( releasedCoordinate > maxCoordinate )
					{
						releasedCoordinate = maxCoordinate;
					}
					if( releasedCoordinate < minCoordinate )
					{
						releasedCoordinate = minCoordinate;
					}
					
					double releasedValue;
					if( invcoord )
						releasedValue = minValueTempInScale
							+ ( maxValueTempInScale - minValueTempInScale )
								*( maxCoordinate - releasedCoordinate )/( maxCoordinate - minCoordinate );
					else
						releasedValue = minValueTempInScale
							+ ( maxValueTempInScale - minValueTempInScale )
								*( releasedCoordinate - minCoordinate )/( maxCoordinate - minCoordinate );
					double diff = Math.abs( releasedValue - oldValueInScale );


					// 新しいレンジの取得
					if( releasedValue > oldValueInScale )
					{
						minValueInScale = minValueTempInScale - diff;
						maxValueInScale = maxValueTempInScale - diff;
					}
					else
					{
						minValueInScale = minValueTempInScale + diff;
						maxValueInScale = maxValueTempInScale + diff;
					}


					if( scaleType == SGAxis.LINEAR_SCALE )
					{
						minValueInScale = getNumberInRangeOrder( minValueInScale, this.mAxis );
						maxValueInScale = getNumberInRangeOrder( maxValueInScale, this.mAxis );
					}

				}
				else if( (loc==p1) | (loc==p2) )
				{

					// マウスボタンをリリースした位置の座標値の計算
					float releasedCoordinate = e.getY();
					if( SGFigureElementAxis.this.mPressedElementOrigin.y == releasedCoordinate )
					{
						return false;
					}

					float minCoordinate = this.mAxisLine.getEnd().y;
					float maxCoordinate = this.mAxisLine.getStart().y;
					if( releasedCoordinate > maxCoordinate )
					{
						releasedCoordinate = maxCoordinate;
					}
					if( releasedCoordinate < minCoordinate )
					{
						releasedCoordinate = minCoordinate;
					}
					double releasedValue;
					if ( invcoord )
						releasedValue = minValueTempInScale
							+ ( maxValueTempInScale - minValueTempInScale )
								*( 1.0 - ( maxCoordinate - releasedCoordinate )/( maxCoordinate - minCoordinate ) );
					else 
						releasedValue = minValueTempInScale
							+ ( maxValueTempInScale - minValueTempInScale )
								*( 1.0 - ( releasedCoordinate - minCoordinate )/( maxCoordinate - minCoordinate ) );
					double diff = Math.abs( releasedValue - oldValueInScale );

					// get new range
//					double min;
//					double max;
					if( releasedValue > oldValueInScale )
					{
						minValueInScale = minValueTempInScale - diff;
						maxValueInScale = maxValueTempInScale - diff;
					}
					else
					{
						minValueInScale = minValueTempInScale + diff;
						maxValueInScale = maxValueTempInScale + diff;
					}


					if( scaleType == SGAxis.LINEAR_SCALE )
					{
						minValueInScale = getNumberInRangeOrder( minValueInScale, this.mAxis );
						maxValueInScale = getNumberInRangeOrder( maxValueInScale, this.mAxis );
					}

				}
				else
				{
					throw new Error();
				}



				// 軸にレンジを設定
				double minValue;
				double maxValue;
				if( scaleType==SGAxis.LINEAR_SCALE )
				{
					minValue = minValueInScale;
					maxValue = maxValueInScale;
				}
				else if( scaleType==SGAxis.LOG_SCALE )
				{
					minValue = Math.pow( 10.0, minValueInScale );
					maxValue = Math.pow( 10.0, maxValueInScale );
				}
				else
				{
					throw new Error();
				}

				this.mAxis.setRange( minValue, maxValue );

			}


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


			// set the rubber band
			final Rectangle rubberband = new Rectangle();
			rubberband.setRect( rbx, rby, rbw, rbh );
//			this.mTempRectangle = rubberband;


			// notify to listeners
			if( mNotifyChangeOnDraggingFlag )
			{
				notifyChange();
			}

			return true;
		}



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

			if( this.mTempRange!=null | this.mDraggingElement!=null )
			{
				this.mTempRange = null;
				this.mDraggingElement = null;
//				this.mTempRectangle = null;

				// horizontal axes
				if( (this.getLocationInPlane()==AXIS_HORIZONTAL_1)
					|| (this.getLocationInPlane()==AXIS_HORIZONTAL_2) )
				{
					ElementsGroupOfAxis group = getAxisGroupInPlane( AXIS_PERPENDICULAR_1 );
				}
				// perpendicular axes
				else if( (this.getLocationInPlane()==AXIS_PERPENDICULAR_1)
					|| (this.getLocationInPlane()==AXIS_PERPENDICULAR_2) )
				{
					ElementsGroupOfAxis group = getAxisGroupInPlane( AXIS_HORIZONTAL_1 );
				}

				return true;
			}

			return false;
		}



		/**
		 * 
		 */
		public boolean onDrawingElement( final int x, final int y )
		{
			boolean flag = false;
			if( this.isAxisVisible() )
			{
				flag = this.contains(x,y);
			}
			else
			{
				flag = this.mAxisLine.contains(x,y);
			}

			if( flag )
			{
				SGFigureElementAxis.this.setMouseCursor( Cursor.HAND_CURSOR );
				return true;
			}

			return false;
		}



		/**
		 * 
		 * @param x
		 * @param y
		 * @return
		 */
		public boolean contains( final int x, final int y )
		{
			// axis line
			if( this.mAxisLine.contains(x,y) )
			{
				return true;
			}

			// title
			if( this.isTitleVisible() )
			{
				if( this.mTitle.contains(x,y) )
				{
					return true;
				}
			}

			// numbers of axis
			if( this.isNumbersVisible() )
			{
				final ArrayList nList = this.mNumberList;
				for( int ii=0; ii<nList.size(); ii++ )
				{
					final ElementStringOfScale el = (ElementStringOfScale)nList.get(ii);
					if( el.contains(x,y) )
					{
						return true;
					}
				}
			}

			// scale lines of axis
			if( this.isTickMarksVisible() )
			{
				final ArrayList sList = this.mTickMarksList;
				for( int ii=0; ii<sList.size(); ii++ )
				{
					final ElementLineOfScale el = (ElementLineOfScale)sList.get(ii);
					if( el.contains(x,y) )
					{
						return true;
					}
				}
			}

			// exponent
			if( this.getExponentFlag() )
			{
				if( this.mExponentDrawingElement.contains(x,y) )
				{
					return true;
				}
			}

			return false;
		}



		/**
		 * 
		 */
		private boolean createDrawingElements()
		{

// The order of calling these methods are important.

			// axis line
			if( this.setAxisLineProperties() == false )
			{
				return false;
			}
			if( this.setAxisLineLocation() == false )
			{
				return false;
			}
//System.out.println("axis line");

			// numbers and scale lines
			if( this.createScaleDrawingElements() == false )
			{
				return false;
			}
//System.out.println("numbers and scale lines");

			// title
			if( this.setTitleProperties() == false )
			{
				return false;
			}
			if( this.setLocationOfTitleElement() == false )
			{
				return false;
			}
//System.out.println("title");

			return true;
		}



		/**
		 * 
		 * @return
		 */
		private boolean setLocationOfDrawingElements()
		{

			// axis line
			if( this.setAxisLineLocation() == false )
			{
				return false;
			}

			// scale numbers
			if( this.isNumbersVisible() )
			{
				if( this.setLocationOfScaleNumbers() == false )
				{
					return false;
				}
			}


			// scale lines
			if( this.isTickMarksVisible() )
			{
				if( this.createScaleLines() == false )
				{
					return false;
				}
			}


			// title
			if( this.isTitleVisible() )
			{
				if( this.setLocationOfTitleElement() == false )
				{
					return false;
				}
			}

			return true;
		}



		/**
		 * 
		 * @return
		 */
		private boolean createScaleDrawingElements()
		{

			// 目盛り数字の計算
			if( this.calcValueArrayInScale() == false )
			{
				return false;
			}
//System.out.println("calcValueArrayInScale");


			// 数字の描画要素を作成する
			if( this.createScaleNumberInstances() == false )
			{
				return false;
			}
//System.out.println("createScaleNumberInstances");


			// 数字の描画要素に位置を指定する
			if( this.setLocationOfScaleNumbers() == false )
			{
				return false;
			}
//System.out.println("createScaleLines");
//System.out.println(this.mNumberList);

			// 目盛り線の作成
			if( this.createScaleLines() == false )
			{
				return false;
			}
//System.out.println("createScaleLines");


			return true;

		}


		/**
		 * 
		 * @return
		 */
		private boolean setAxisLineLocation()
		{
			float x1;
			float y1;
			float x2;
			float y2;

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

			switch( this.getLocationInPlane() )
			{

				case AXIS_HORIZONTAL_1 :
				{
					x1 = gx;
					y1 = gy + gh;
					x2 = gx + gw;
					y2 = y1;
					break;
				}

				case AXIS_HORIZONTAL_2 :
				{
					x1 = gx;
					y1 = gy;
					x2 = gx + gw;
					y2 = y1;
					break;
				}

				case AXIS_PERPENDICULAR_1 :
				{
					x1 = gx;
					y1 = gy + gh;
					x2 = x1;
					y2 = gy;
					break;
				}

				case AXIS_PERPENDICULAR_2 :
				{
					x1 = gx + gw;
					y1 = gy + gh;
					x2 = x1;
					y2 = gy;
					break;
				}

				default :
				{
					throw new Error();
				}

			}

			this.mAxisLine.setTermPoints( x1, y1, x2, y2 );

			return true;
		}



		/**
		 * 
		 */
		private boolean setAxisLineProperties()
		{
			this.mAxisLine.setLineWidth( SGFigureElementAxis.this.mAxisLineWidth );
			this.mAxisLine.setColor( SGFigureElementAxis.this.mLineColor );
			return true;
		}



		/**
		 * 
		 */
		private boolean setLocationOfTitleElement()
		{
			final float gx = SGFigureElementAxis.this.mGraphRectX;
			final float gy = SGFigureElementAxis.this.mGraphRectY;
			final float gw = SGFigureElementAxis.this.mGraphRectWidth;
			final float gh = SGFigureElementAxis.this.mGraphRectHeight;

			final float mag = SGFigureElementAxis.this.mMagnification;

			final float spaceLN = getSpaceAxisLineAndNumber()*mag;
			final float spaceNT = getSpaceNumberAndTitle()*mag;

			float scaleNumberHeight = 0.0f;
			float maxWidth = 0.0f;
//			if( this.mScaleNumbersVisibleFlag )
			{
				scaleNumberHeight = (float)getScaleHeight();
				maxWidth = getMaxLengthOfScaleNumbers(this);
			}

			switch( this.getLocationInPlane() )
			{
				case SGIFigureElementAxis.AXIS_HORIZONTAL_1 :
				{
					Rectangle2D rectTitle = this.mTitle.getElementBounds();
					this.mTitle.setLocation(
						gx + ( gw - (float)rectTitle.getWidth() )/2.0f,
						gy + gh + scaleNumberHeight + ( spaceLN + spaceNT )
					);

					break;
				}

				case SGIFigureElementAxis.AXIS_HORIZONTAL_2 :
				{
					Rectangle2D rectTitle = this.mTitle.getElementBounds();
					this.mTitle.setLocation(
						gx + ( gw - (float)rectTitle.getWidth() )/2.0f,
						gy - scaleNumberHeight - (float)rectTitle.getHeight()
							- ( spaceLN + spaceNT )
					);
					break;
				}

				case SGIFigureElementAxis.AXIS_PERPENDICULAR_1 :
				{
					this.mTitle.setAngle( 90.0f*RADIAN_DEGREE_RATIO );	// 90度回転
					Rectangle2D rectTitle = this.mTitle.getElementBounds();
					this.mTitle.setLocation(
						gx - maxWidth - (float)rectTitle.getWidth()
							- ( spaceLN + spaceNT ),
						gy + ( gh + (float)rectTitle.getHeight() )/2.0f
					);
					break;
				}

				case SGIFigureElementAxis.AXIS_PERPENDICULAR_2 :
				{
					this.mTitle.setAngle( 90.0f*RADIAN_DEGREE_RATIO );	// 90度回転
					Rectangle2D rectTitle = this.mTitle.getElementBounds();
					this.mTitle.setLocation(
						gx + gw + maxWidth + ( spaceLN + spaceNT ),
						gy + ( gh + (float)rectTitle.getHeight() )/2.0f
					);
					break;
				}

				default :
				{
				
				}

			}

			return true;

		}



		/**
		 * 
		 * @return
		 */
		private boolean setTitleProperties()
		{
			this.mTitle.setColor( SGFigureElementAxis.this.mStringColor );
			this.mTitle.setFont(
					SGFigureElementAxis.this.mTitleFontName,
					SGFigureElementAxis.this.mTitleFontStyle,
					SGFigureElementAxis.this.mTitleFontSize
					);
			return true;
		}


		/**
		 * 
		 * @return
		 */
		private boolean createScaleNumberInstances()
		{

			// clear
			this.mNumberList.clear();
			this.mExponentDrawingElement = null;


			// scale type
			final int scaleType = this.mAxis.getScaleType();

			final double[] vArray = this.mAxisValueArray;

			// exponent
			double[] valueArray = null;
			final int eValue = this.getExponentValue();
			if( this.getExponentFlag() )
			{
				valueArray = new double[this.mAxisValueArray.length];
				for( int ii=0; ii<valueArray.length; ii++ )
				{
					BigDecimal db = new BigDecimal( Double.toString( vArray[ii] ) );
					db = db.movePointLeft( eValue );
					valueArray[ii] = db.doubleValue();
				}
			}
			else
			{
				valueArray = vArray;
			}


			// create string array
			String[] strArray = new String[valueArray.length];
			if( scaleType == SGAxis.LINEAR_SCALE )
			{
				if( this.isNumbersInteger() )
				{
					for( int ii=0; ii<strArray.length; ii++ )
					{
						strArray[ii] = Integer.toString( (int)valueArray[ii] );
					}
				}
				else
				{
					for( int ii=0; ii<strArray.length; ii++ )
					{
						strArray[ii] = Double.toString( valueArray[ii] );
					}
				}
			}
			else if( scaleType == SGAxis.LOG_SCALE )
			{
				for( int ii=0; ii<strArray.length; ii++ )
				{
					final int order = SGUtilityNumber.getOrder( valueArray[ii] );
					strArray[ii] = SGUtilityText.getSuperscriptString(
						"10", Integer.toString(order) );
				}
			}


			// create drawing elements of the scale numbers
			final float mag = SGFigureElementAxis.this.mMagnification;
			final Color cl = SGFigureElementAxis.this.mStringColor;
			final String name = SGFigureElementAxis.this.mScaleFontName;
			final int style = SGFigureElementAxis.this.mScaleFontStyle;
			final float size = SGFigureElementAxis.this.mScaleFontSize;
			final float angle = 0.0f;
			for( int ii=0; ii<vArray.length; ii++ )
			{
				ElementStringOfScale el =
					new ElementStringOfScale( strArray[ii], name, style, size, cl, mag, angle );
				el.mValue = vArray[ii];
				if( this.mAxis.insideRange(el.mValue)==false )
				{
					el.setVisible(false);
				}
				el.setMagnification( mag );
				this.mNumberList.add(el);
			}


			// create the exponent drawing element
			if( this.getExponentFlag() )
			{
				this.createExponentDrawingElement();
			}


			return true;

		}



		/**
		 * 
		 * @return
		 */
		private boolean createExponentDrawingElement()
		{
			// craete an instance
			String str = multiply + "10";
			str = SGUtilityText.getSuperscriptString(
				str, Integer.toString( this.getExponentValue() ) );
			final float angle = 0.0f;
			SGDrawingElementString2DExtended el
				= new SGDrawingElementString2DExtended(
					str, 
					SGFigureElementAxis.this.mScaleFontName,
					SGFigureElementAxis.this.mScaleFontStyle,
					SGFigureElementAxis.this.mScaleFontSize,
					SGFigureElementAxis.this.mStringColor,
					SGFigureElementAxis.this.mMagnification, angle );

			// set to the attribute
			this.mExponentDrawingElement = el;

			// set the location
			this.setLocationOfExponentDrawingElement();

			return true;
		}



		/**
		 * 
		 * @return
		 */
		private boolean setLocationOfExponentDrawingElement()
		{
			SGDrawingElementString2D el = this.mExponentDrawingElement;

			final Rectangle2D rect = el.getElementBounds();

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

			final float mag = SGFigureElementAxis.this.mMagnification;

			final float spaceLN = getSpaceAxisLineAndNumber()*mag;
			final float spaceNT = getSpaceNumberAndTitle()*mag;

			float x = 0.0f;
			float y = 0.0f;
			switch( this.getLocationInPlane() )
			{

				case AXIS_HORIZONTAL_1 :
				{
					x = gx + gw - 0*(float)rect.getWidth();
					y = gy + gh + (float)( spaceLN + getScaleHeight() + spaceNT );
					break;
				}

				case AXIS_HORIZONTAL_2 :
				{
					x = gx + gw - 0*(float)rect.getWidth();
					y = gy - (float)( spaceLN + getScaleHeight() + spaceNT + getTitleHeight() );
					break;
				}

				case AXIS_PERPENDICULAR_1 :
				{
					x = gx - (float)( spaceLN + getMaxLengthOfScaleNumbers(this) + spaceNT + rect.getWidth() );
					y = gy - (float)rect.getHeight();
					break;
				}

				case AXIS_PERPENDICULAR_2 :
				{
					x = gx + gw + spaceLN + getMaxLengthOfScaleNumbers(this) + spaceNT;
					y = gy - (float)rect.getHeight();
					break;
				}

				default :
				{
					throw new Error();
				}

			}

			el.setLocation(x,y);

			return true;
		}




		/**
		 * 
		 */
		private boolean setLocationOfScaleNumbers()
		{

			final int loc = this.getLocationInPlane();
			final boolean invcoord = this.isInvertCoordinates();
			
			final float gx = SGFigureElementAxis.this.mGraphRectX;
			final float gy = SGFigureElementAxis.this.mGraphRectY;
			final float gw = SGFigureElementAxis.this.mGraphRectWidth;
			final float gh = SGFigureElementAxis.this.mGraphRectHeight;

			int scaleType = this.mAxis.getScaleType();

			double[] valueArrayInScale = null;
			if( scaleType == SGAxis.LINEAR_SCALE )
			{
				valueArrayInScale = this.mAxisValueArray;
			}
			else if( scaleType == SGAxis.LOG_SCALE )
			{
				valueArrayInScale = new double[this.mAxisValueArray.length];
				for( int ii=0; ii<valueArrayInScale.length; ii++ )
				{
					valueArrayInScale[ii] = Math.log( this.mAxisValueArray[ii] );
				}
			}

			double axisMinInScale = 0.0;
			double axisMaxInScale = 0.0;
			if( scaleType == SGAxis.LINEAR_SCALE )
			{
				axisMinInScale = this.mAxis.getMinValue();
				axisMaxInScale = this.mAxis.getMaxValue();
			}
			else if( scaleType == SGAxis.LOG_SCALE )
			{
				axisMinInScale = Math.log(this.mAxis.getMinValue());
				axisMaxInScale = Math.log(this.mAxis.getMaxValue());
			}

			final float mag = SGFigureElementAxis.this.mMagnification;

//			final float spaceNT = getSpaceNumberAndTitle()*mag;
			final float spaceLN = getSpaceAxisLineAndNumber()*mag;

			for( int ii=0; ii<this.mNumberList.size(); ii++ )
			{
				ElementStringOfScale el
					= (ElementStringOfScale)this.mNumberList.get(ii);

				Rectangle2D rect = el.getElementBounds();
				final float width = (float)rect.getWidth();
				final float height = (float)rect.getHeight();

				switch( loc )
				{
					case AXIS_HORIZONTAL_1 : // bottom
					{
						float x;
						if( invcoord )
							x = (float)( gx + gw*(axisMaxInScale - valueArrayInScale[ii])/(axisMaxInScale-axisMinInScale) );
						else
							x = (float)( gx + gw*(valueArrayInScale[ii]-axisMinInScale)/(axisMaxInScale-axisMinInScale) );
						final float y = gy + gh + spaceLN;
						el.setLocation( ( x-0.50f*width ), y );
						break;
					}

					case AXIS_HORIZONTAL_2 : // top
					{
						float x;
						if( invcoord )
							x = (float)( gx + gw*(axisMaxInScale - valueArrayInScale[ii])/(axisMaxInScale-axisMinInScale) );
						else
							x = (float)( gx + gw*(valueArrayInScale[ii]-axisMinInScale)/(axisMaxInScale-axisMinInScale) );
						final float y = (float)( gy - spaceLN - rect.getHeight() );
						el.setLocation( ( x-0.50f*width ), y );
						break;
					}

					// 目盛り数字のうち、最も長いものの左端を（タイトルの右端＋スペース）に合わせる
					case AXIS_PERPENDICULAR_1 : // left
					{
						float y;
						if( invcoord )
							y = (float)( gy + gh*(1.0-(axisMaxInScale - valueArrayInScale[ii])/(axisMaxInScale-axisMinInScale)) );
						else
							y = (float)( gy + gh*(1.0-(valueArrayInScale[ii]-axisMinInScale)/(axisMaxInScale-axisMinInScale)) );
						final float x = (float)( gx - spaceLN - rect.getWidth() );
						el.setLocation( x, ( y - 0.5f*height ) );
						break;
					}

					case AXIS_PERPENDICULAR_2 : // right
					{
						float y;
						if( invcoord )
							y = (float)( gy + gh*(1.0-(axisMaxInScale - valueArrayInScale[ii])/(axisMaxInScale-axisMinInScale)) );
						else
							y = (float)( gy + gh*(1.0-(valueArrayInScale[ii]-axisMinInScale)/(axisMaxInScale-axisMinInScale)) );
						final float x = gx + gw + spaceLN;
						el.setLocation( x, ( y - 0.5f*height ) );
						break;
					}

					default :
					{
						throw new Error();
					}

				}

			}


			// the exponent drawing element
			if( this.getExponentFlag() )
			{
				this.setLocationOfExponentDrawingElement();
			}


			return true;
		}




		/**
		 * 
		 */
		private boolean createScaleLines()
		{
			// clear the list
			this.mTickMarksList.clear();


			boolean flag = true;
			switch( this.mAxis.getScaleType() )
			{
				case SGAxis.LINEAR_SCALE :
				{
					flag = this.createScaleLinesInLinearScale();
					break;
				}
				
				case SGAxis.LOG_SCALE :
				{
					flag = this.createScaleLinesInLogScale();
					break;
				}
				
				default :
				{
					throw new Error();
				}
				
			}

			return flag;
		}



		/**
		 * 
		 */
		private boolean createScaleLinesInLinearScale()
		{

			final float mag = SGFigureElementAxis.this.mMagnification;
			final float length = mag * SGFigureElementAxis.this.mTickMarkLength;
			final Color cl = SGFigureElementAxis.this.mLineColor;
			final double[] valueArray = this.mAxisValueArray;

			
			//
			// 目盛り線の描画要素の作成
			//

			for( int ii=0; ii<valueArray.length; ii++ )
			{
				final double value = valueArray[ii];

				ElementLineOfScale el = this.createSingleScaleLine( value, length );
				if( el!=null )
				{
					el.mValue = value;
					el.setMagnification( mag );
					el.setColor( cl );

					this.mTickMarksList.add(el);
				}
			}


			//
			// create scale lines between scale numbers
			//

			for( int ii=0; ii<valueArray.length; ii++ )
			{

				if( ii==valueArray.length-1 )
				{
					break;
				}

				final double value = (
					valueArray[ii] + valueArray[ii+1] )/2.0;

				ElementLineOfScale el = this.createSingleScaleLine( value, length );
				if( el!=null )
				{
					el.mValue = value;
					el.setMagnification( mag );
					el.setColor( cl );

					this.mTickMarksList.add(el);
				}
			}

			
			return true;
		}



		/**
		 * 
		 */
		private boolean createScaleLinesInLogScale()
		{
//System.out.println("<< createScaleLinesInLogScale >>");

//for( int ii=0; ii<this.mAxisValueArray.length; ii++ )
//{
//	System.out.println(ii+"  "+this.mAxisValueArray[ii]);
//}
//System.out.println();


			// create the main scale lines
			final float length = SGFigureElementAxis.this.mMagnification * SGFigureElementAxis.this.mTickMarkLength;
			for( int ii=0; ii<this.mAxisValueArray.length; ii++ )
			{
				final double value = this.mAxisValueArray[ii];

				ElementLineOfScale el = this.createSingleScaleLine(
					value, length );
				if( el!=null )
				{
					el.mValue = value;
					el.setMagnification( SGFigureElementAxis.this.mMagnification );
					el.setColor( SGFigureElementAxis.this.mLineColor );

					this.mTickMarksList.add(el);
				}
			}


			// create the sub scale lines
			final float ratio = 1.0f;
			for( int ii=0; ii<this.mAxisValueArray.length; ii++ )
			{
				for( int jj=2; jj<10; jj++ )
				{
					final double value = this.mAxisValueArray[ii]*0.10*jj;

					ElementLineOfScale el = this.createSingleScaleLine(
						value, ratio*length );
					if( el!=null )
					{
						el.mValue = value;
						el.setMagnification( SGFigureElementAxis.this.mMagnification );
						el.setColor( SGFigureElementAxis.this.mLineColor );

						this.mTickMarksList.add(el);
					}
				}
			}


			//
			if( this.mAxisValueArray.length >= 1 )
			{
				for( int jj=2; jj<10; jj++ )
				{
					final double value
						= this.mAxisValueArray[this.mAxisValueArray.length-1]*jj;
					ElementLineOfScale el = this.createSingleScaleLine(
						value, ratio*length );
					if( el!=null )
					{
						el.mValue = value;
						el.setMagnification( SGFigureElementAxis.this.mMagnification );
						el.setColor( SGFigureElementAxis.this.mLineColor );

						this.mTickMarksList.add(el);
					}
				}
			}


			return true;
		}




		/**
		 * 
		 * @param value
		 * @param length
		 * @return
		 */
		private ElementLineOfScale createSingleScaleLine(
			final double value, final float length )
		{
//System.out.println("<< createSingleScaleLine >>");

			if( this.mAxis.insideRange(value) == false )
			{
				return null;
			}

			final float gx = SGFigureElementAxis.this.mGraphRectX;
			final float gy = SGFigureElementAxis.this.mGraphRectY;
			final float gw = SGFigureElementAxis.this.mGraphRectWidth;
			final float gh = SGFigureElementAxis.this.mGraphRectHeight;
			
			final float mag = SGFigureElementAxis.this.mMagnification;
			final boolean inside = this.isTickMarksInside();
			final float width = SGFigureElementAxis.this.mScaleLineWidth;

			final boolean invcoord = this.isInvertCoordinates();
			
			double min;
			double max;
			double valueInScale;
			switch( this.mAxis.getScaleType() )
			{
				case SGAxis.LINEAR_SCALE :
				{
					min = this.mAxis.getMinValue();
					max = this.mAxis.getMaxValue();
					valueInScale = value;
					break;
				}
				
				case SGAxis.LOG_SCALE :
				{
					min = Math.log( this.mAxis.getMinValue() );
					max = Math.log( this.mAxis.getMaxValue() );
					valueInScale = Math.log(value);
					break;
				}
				
				default :
				{
					throw new Error();
				}
			}


			ElementLineOfScale el = null;

			switch( this.getLocationInPlane() )
			{
				case AXIS_HORIZONTAL_1 : // bottom
				{
					double x;
					if( invcoord )
						x = gx + gw*(max-valueInScale)/(max-min);
					else
						x = gx + gw*(valueInScale-min)/(max-min);
					final double yStart = gy+gh;
					double yEnd = 0.0;
					if( inside )
					{
						yEnd = yStart - length;
					}
					else
					{
						yEnd = yStart + length;
					}

					final SGTuple2f start = new SGTuple2f( (float)x, (float)yStart );
					final SGTuple2f end = new SGTuple2f( (float)x, (float)yEnd );
					el = new ElementLineOfScale( start, end );
					el.setLineWidth( width );
					el.setMagnification( mag );
					break;
				}

				case AXIS_HORIZONTAL_2 : // top
				{
					double x;
					if( invcoord )
						x = gx + gw*(max-valueInScale)/(max-min);
					else
						x = gx + gw*(valueInScale-min)/(max-min);
					final double yStart = gy;
					double yEnd = 0.0;
					if( inside )
					{
						yEnd = yStart + length;
					}
					else
					{
						yEnd = yStart - length;
					}

					SGTuple2f start = new SGTuple2f( (float)x, (float)yStart );
					SGTuple2f end = new SGTuple2f( (float)x, (float)yEnd );
					el = new ElementLineOfScale( start, end );
					el.setLineWidth( width );
					el.setMagnification( mag );
					break;
				}

				case AXIS_PERPENDICULAR_1 : // left
				{
					double y;
					if( invcoord )
						y = gy + gh*(1.0-(max-valueInScale)/(max-min));
					else
						y = gy + gh*(1.0-(valueInScale-min)/(max-min));
					final double xStart = gx;
					double xEnd = 0.0;
					if( inside )
					{
						xEnd = xStart + length;
					}
					else
					{
						xEnd = xStart - length;
					}

					final SGTuple2f start = new SGTuple2f( (float)xStart, (float)y );
					final SGTuple2f end = new SGTuple2f( (float)xEnd, (float)y );
					el = new ElementLineOfScale( start, end );
					el.setLineWidth( width );
					el.setMagnification( mag );
					break;
				}

				case AXIS_PERPENDICULAR_2 : // right
				{
					double y;
					if( invcoord )
						y = gy + gh*(1.0-(max-valueInScale)/(max-min));
					else
						y = gy + gh*(1.0-(valueInScale-min)/(max-min));
					final double xStart = gx+gw;
					double xEnd = 0.0;
					if( inside )
					{
						xEnd = xStart - length;
					}
					else
					{
						xEnd = xStart + length;
					}

					final SGTuple2f start = new SGTuple2f( (float)xStart, (float)y );
					final SGTuple2f end = new SGTuple2f( (float)xEnd, (float)y );
					el = new ElementLineOfScale( start, end );
					el.setLineWidth( width );
					el.setMagnification( mag );
					break;
				}

				default :
				{
					throw new Error();
				}

			}

			return el;
		}


		/**
		 * 軸のスケールタイプに合わせて数列を作り直す
		 */
		private boolean calcValueArrayInScale()
		{

			// 目盛りの数値を計算する
			double[] array = null;
			switch( this.mAxis.getScaleType() )
			{
				case SGAxis.LINEAR_SCALE :
				{
					array = this.calcScaleValuesInLinearScale();
					break;
				}
				
				case SGAxis.LOG_SCALE :
				{
					array = this.calcScaleValuesInLogScale();
					break;
				}
				
				default :
				{

				}
				
			}


			// 属性に設定
			this.mAxisValueArray = array;


			return true;
		}



//		/**
//		 * 
//		 */
//		private int getRangeOrder()
//		{
//			SGTuple2d range = this.mAxis.getRange();
//			final int order = SGUtilityNumber.getOrder( range.y - range.x );
//			return order;
//		}



		/**
		 * Calculate the numbers of scale in for the linear scale.
		 * @return
		 */
		private double[] calcScaleValuesInLinearScale()
		{
			SGAxis axis = this.mAxis;

			// minimum and maximum values of axis range
			SGTuple2d range = axis.getRange();
			final double min = range.x;
			final double max = range.y;

			// get the order of axis range
			final int order = SGUtilityNumber.getOrder( max - min );

			// get reference value and increment value
			if( this.isCalculateAutomatically() )
			{
				this.setBaselineValue( 0.0 );
				this.setStepValue( calcStepValue(axis) );
			}

			final double baseline = this.getBaselineValue();
			final double step = Math.abs( this.getStepValue() );

			// get an array of numbers
			final ArrayList valueList = new ArrayList();
			if( baseline > max )
			{
				if( this.mAxis.insideRange( baseline - step ) )
				{
					valueList.add( new Double( baseline ) );
				}
			}
			else
			{
				int cnt = 0;
				while( true )
				{
					final double value = baseline + cnt*step;
					if( value < min )
					{
						if( this.mAxis.insideRange( value + step ) )
						{
							this.addNumberToList( value, valueList, order, true );
						}
						cnt++;
						continue;
					}

					this.addNumberToList( value, valueList, order, true );
					cnt++;
					if( value > max )
					{
						break;
					}
				}
			}
			if( baseline < min )
			{
				if( this.mAxis.insideRange( baseline + step ) )
				{
					valueList.add( 0, new Double( baseline ) );
				}
			}
			else
			{
				int cnt = 0;
				while( true )
				{
					final double value = baseline - cnt*step;
					if( value > max )
					{
						if( this.mAxis.insideRange( value - step ) )
						{
							this.addNumberToList( value, valueList, order, false );
						}
						cnt++;
						continue;
					}

					this.addNumberToList( value, valueList, order, false );
					cnt++;
					if( value < min )
					{
						break;
					}
				}
			}

			// array of values for scale
			double[] axisValueArray = new double[valueList.size()];
			for( int ii=0; ii<axisValueArray.length; ii++ )
			{
				axisValueArray[ii] = ((Double)valueList.get(ii)).doubleValue();
			}


			// set scale numbers integer when all numbers
			// can be replaced with an integer
			if( SGFigureElementAxis.this.mStartFlag )
			{
				boolean flag = true;
				for( int ii=0; ii<axisValueArray.length; ii++ )
				{
					final double value = axisValueArray[ii];
					final long round = Math.round(value);
					final double diff = Math.abs(value-round);
					if( diff!=0.0 )
					{
						flag = false;
						break;
					}
				}
				this.setNumbersInteger( flag );
			}


			// When the scale numbers are set to be integer,
			// cast values to integer
			if( this.isNumbersInteger() )
			{

				final ArrayList numList = new ArrayList();
				for( int ii=0; ii<axisValueArray.length; ii++ )
				{
					double value;
					if( this.getExponentFlag() )
					{
						BigDecimal db = new BigDecimal(
							Double.toString( axisValueArray[ii] ) );
						db = db.movePointLeft( this.getExponentValue() );
						value = db.doubleValue();
					}
					else
					{
						value = axisValueArray[ii];
					}
					final int num = (int)value;
					if( Math.abs(num-value) < Double.MIN_VALUE )
					{
						numList.add( new Integer(num) );
					}
				}

				// remove the same values
				for( int ii=numList.size()-1; ii>=1; ii-- )
				{
					final Integer n1 = (Integer)numList.get(ii);

					for( int jj=ii-1; jj>=0; jj-- )
					{
						final Integer n2 = (Integer)numList.get(jj);

						if( n2.intValue() == n1.intValue() )
						{
							numList.remove(ii);
							break;
						}
					}
				}

				final double[] valueArray = new double[numList.size()];
				for( int ii=0; ii<valueArray.length; ii++ )
				{
					double value = ((Integer)numList.get(ii)).doubleValue();
					if( this.getExponentFlag() )
					{
						BigDecimal db = new BigDecimal(
							Double.toString(value) );
						db = db.movePointRight( this.getExponentValue() );
						value = db.doubleValue();
					}
					valueArray[ii] = value;
				}
				axisValueArray = valueArray;
			}

			// this returned value reflects the integer flag,
			// but is not influenced by the exponent flag
			return axisValueArray;

		}


		private void addNumberToList(
			final double value, final ArrayList list, final int order, final boolean toLast )
		{
			final double tValue = SGUtilityNumber.roundOffNumber( value, order-AXIS_SCALE_EFFECTIVE_DIGIT );
			Double d = new Double(tValue);
			if( toLast )
			{
				list.add(d);
			}
			else
			{
				list.add(0,d);
			}
		}


		/**
		 * Calculate the numbers of scale in for the linear scale.
		 * @return
		 */
		private double[] calcScaleValuesInLogScale()
		{
//System.out.println("<< calcScaleValuesInLogScale >>");

			// minimum and maximum values of axis range
			final SGTuple2d range = this.mAxis.getRange();
			final double min = range.x;
			final double max = range.y;

			// array of values for scale
			double[] axisValueArray = null;

			final int minOrder = SGUtilityNumber.getOrder(min);
			final int maxOrder = SGUtilityNumber.getOrder(max);

//System.out.println(min+"  "+minOrder);
//System.out.println(max+"  "+maxOrder);

//final double diff = max - min;
//final int diffOrder = SGUtility.getOrder( (1.0-1.0E-14)*diff );

			ArrayList list = new ArrayList();
			for( int ii=minOrder; ii<=maxOrder; ii++ )
			{
				list.add( new Integer(ii) );
			}

//System.out.println(list);

			axisValueArray = new double[list.size()];
			for( int ii=0; ii<axisValueArray.length; ii++ )
			{
				final int num = ((Integer)list.get(ii)).intValue();
				axisValueArray[ii] = SGUtilityNumber.getPowersOfTen( num );
			}

//System.out.println();

			return axisValueArray;
		}



		/**
		 * 
		 * @return
		 */
		public String getTagName()
		{
			return SGIFigureElementAxis.TAG_NAME_AXIS;
		}

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


		/**
		 * 
		 */
		public boolean writeProperty( final Element el )
		{

			final SGTuple2d range = this.mAxis.getRange();

			final int loc = this.getLocationInCube();
			final String str = getLocationString(loc);
			el.setAttribute( KEY_POSITION, str );

			el.setAttribute( KEY_AXIS_VISIBLE, Boolean.toString( this.isAxisVisible() ) );

			el.setAttribute( KEY_AXIS_SCALE_TYPE, SGUtilityText.getScaleTypeName( this.mAxis.getScaleType() ) );
			el.setAttribute( KEY_AXIS_MIN_VALUE, Double.toString( range.x ) );
			el.setAttribute( KEY_AXIS_MAX_VALUE, Double.toString( range.y ) );
			el.setAttribute( KEY_AXIS_INVERT_COORDINATES, Boolean.toString( this.isInvertCoordinates() ) );
			
			el.setAttribute( KEY_AUTO_CALC_NUMBER, Boolean.toString( this.isCalculateAutomatically() ) );
			el.setAttribute( KEY_STEP_VALUE, Double.toString( this.getStepValue() ) );
			el.setAttribute( KEY_BASELINE_VALUE, Double.toString( this.getBaselineValue() ) );

			el.setAttribute( KEY_TITLE_VISIBLE, Boolean.toString( this.isTitleVisible() ) );
			el.setAttribute( KEY_TITLE_TEXT, this.getTitleString() );

			el.setAttribute( KEY_NUMBER_VISIBLE, Boolean.toString( this.isNumbersVisible() ) );
			el.setAttribute( KEY_NUMBER_INTEGER, Boolean.toString( this.isNumbersInteger() ) );

			el.setAttribute( KEY_TICK_MARK_VISIBLE, Boolean.toString( this.isTickMarksVisible() ) );
			el.setAttribute( KEY_TICK_MARK_INSIDE, Boolean.toString( this.isTickMarksInside() ) );

			el.setAttribute( KEY_EXPONENT_VISIBLE, Boolean.toString( this.getExponentFlag() ) );
			el.setAttribute( KEY_EXPONENT_VALUE, Integer.toString( this.getExponentValue() ) );

			return true;

		}


		/**
		 * 
		 * @param element
		 * @return
		 */
		private boolean readAxisProperties(
			final Element element )
		{
			String str = null;
			Number num = null;
//			Color cl = null;
			Boolean b = null;

			// axis visible
			str = element.getAttribute( SGIFigureElementAxis.KEY_AXIS_VISIBLE );
			if( str.length()==0 )
			{
				return false;
			}
			b = SGUtilityText.getBoolean(str);
			if( b==null )
			{
				return false;
			}
			final boolean axisVisible = b.booleanValue();
		
		
			// scale type
			str = element.getAttribute( SGIFigureElementAxis.KEY_AXIS_SCALE_TYPE );
			if( str.length()==0 )
			{
				return false;
			}
			final int scaleType = SGUtilityText.getScaleType( str );
			if( scaleType==-1 )
			{
				return false;
			}

		
			// min value
			str = element.getAttribute( SGIFigureElementAxis.KEY_AXIS_MIN_VALUE );
			if( str.length()==0 )
			{
				return false;
			}
			num = SGUtilityText.getDouble(str);
			if( num==null )
			{
				return false;
			}
			final double minValue = num.doubleValue();

		
			// max value
			str = element.getAttribute( SGIFigureElementAxis.KEY_AXIS_MAX_VALUE );
			if( str.length()==0 )
			{
				return false;
			}
			num = SGUtilityText.getDouble(str);
			if( num==null )
			{
				return false;
			}
			final double maxValue = num.doubleValue();

			// invert coordinates
			str = element.getAttribute( SGIFigureElementAxis.KEY_AXIS_INVERT_COORDINATES );
			if( str.length()==0 )
			{
				b = Boolean.FALSE; //  version >= 1.0.4
			} else {
				b = SGUtilityText.getBoolean(str); // version > 1.0.5
			}
			final boolean invCoord = b.booleanValue();
		
			// auto calc
			str = element.getAttribute( SGIFigureElementAxis.KEY_AUTO_CALC_NUMBER );
			if( str.length()==0 )
			{
				return false;
			}
			b = SGUtilityText.getBoolean(str);
			if( b==null )
			{
				return false;
			}
			final boolean autoCalc = b.booleanValue();
		
		
			// step value
			str = element.getAttribute( SGIFigureElementAxis.KEY_STEP_VALUE );
			if( str.length()==0 )
			{
				return false;
			}
			num = SGUtilityText.getDouble(str);
			if( num==null )
			{
				return false;
			}
			final double stepValue = num.doubleValue();

		
			// baseline value
			str = element.getAttribute( SGIFigureElementAxis.KEY_BASELINE_VALUE );
			if( str.length()==0 )
			{
				return false;
			}
			num = SGUtilityText.getDouble(str);
			if( num==null )
			{
				return false;
			}
			final double baselineValue = num.doubleValue();
		

			// title visible
			str = element.getAttribute( SGIFigureElementAxis.KEY_TITLE_VISIBLE );
			if( str.length()==0 )
			{
				return false;
			}
			b = SGUtilityText.getBoolean(str);
			if( b==null )
			{
				return false;
			}
			final boolean titleVisible = b.booleanValue();
		

			// title string
			str = element.getAttribute( SGIFigureElementAxis.KEY_TITLE_TEXT );
			// null string is ok
//			if( str.length()==0 )
//			{
//				return false;
//			}
			final String titleString = str;

		
			// scale number visible
			str = element.getAttribute( SGIFigureElementAxis.KEY_NUMBER_VISIBLE );
			if( str.length()==0 )
			{
				return false;
			}
			b = SGUtilityText.getBoolean(str);
			if( b==null )
			{
				return false;
			}
			final boolean numberVisible = b.booleanValue();


			// number integer
			str = element.getAttribute( SGIFigureElementAxis.KEY_NUMBER_INTEGER );
			if( str.length()==0 )
			{
				return false;
			}
			b = SGUtilityText.getBoolean(str);
			if( b==null )
			{
				return false;
			}
			final boolean numberInteger = b.booleanValue();

		
			// tick mark visible
			str = element.getAttribute( SGIFigureElementAxis.KEY_TICK_MARK_VISIBLE );
			if( str.length()==0 )
			{
				return false;
			}
			b = SGUtilityText.getBoolean(str);
			if( b==null )
			{
				return false;
			}
			final boolean tickMarkVisible = b.booleanValue();

		
			// tick mark inside
			str = element.getAttribute( SGIFigureElementAxis.KEY_TICK_MARK_INSIDE );
			if( str.length()==0 )
			{
				return false;
			}
			b = SGUtilityText.getBoolean(str);
			if( b==null )
			{
				return false;
			}
			final boolean tickMarkInside = b.booleanValue();
		

			// exponent visible
			str = element.getAttribute( SGIFigureElementAxis.KEY_EXPONENT_VISIBLE );
			if( str.length()==0 )
			{
				return false;
			}
			b = SGUtilityText.getBoolean(str);
			if( b==null )
			{
				return false;
			}
			final boolean exponentVisible = b.booleanValue();

		
			// exponent value
			str = element.getAttribute( SGIFigureElementAxis.KEY_EXPONENT_VALUE );
			if( str.length()==0 )
			{
				return false;
			}
			num = SGUtilityText.getInteger(str);
			if( num==null )
			{
				return false;
			}
			final int exponentValue = num.intValue();


			//
			// set properties
			//
			
			if( this.setAxisVisible( axisVisible ) == false )
			{
				return false;
			}
			
			if( this.setScaleType( scaleType ) == false )
			{
				return false;
			}
			
			if( this.setAxisRange( minValue, maxValue ) == false )
			{
				return false;
			}

			if( this.setInvertCoordinates( invCoord ) == false )
			{
				return false;
			}
			
			if( this.setCalculateAutomatically( autoCalc ) == false )
			{
				return false;
			}
			
			if( this.setStepValue( stepValue ) == false )
			{
				return false;
			}

			if( this.setBaselineValue( baselineValue ) == false )
			{
				return false;
			}

			if( this.setTitleVisible( titleVisible ) == false )
			{
				return false;
			}

			if( this.setTitle( titleString ) == false )
			{
				return false;
			}

			if( this.setNumbersVisible( numberVisible ) == false )
			{
				return false;
			}

			if( this.setNumbersInteger( numberInteger ) == false )
			{
				return false;
			}

			if( this.setTickMarksVisible( tickMarkVisible ) == false )
			{
				return false;
			}

			if( this.setTickMarksInside( tickMarkInside ) == false )
			{
				return false;
			}

			if( this.setExponentFlag( exponentVisible ) == false )
			{
				return false;
			}

			if( this.setExponentValue( exponentValue ) == false )
			{
				return false;
			}
		
			return true;
		}
		
		
		
		/**
		 * 
		 */
		private AxisIndividualProperties getProperties()
		{
			AxisIndividualProperties p = new AxisIndividualProperties();

			p.location = this.getLocationInCube();

			p.scaleType = this.mAxis.getScaleType();

			SGTuple2d range = this.mAxis.getRange();
			p.minValue = range.x;
			p.maxValue = range.y;
			
			p.invertCoordinatesFlag = this.isInvertCoordinates();
			p.autoCalcAxisNumberFlag = this.isCalculateAutomatically();
			p.incrementValue = this.getStepValue();
			p.baseTickValue = this.getBaselineValue();
			p.titleString = this.mTitle.getString();
			p.axisVisibleFlag = this.isAxisVisible();
			p.titleVisibleFlag = this.isTitleVisible();
			p.scaleLinesVisibleFlag = this.isTickMarksVisible();
			p.scaleNumbersVisibleFlag = this.isNumbersVisible();
			p.scaleLinesInsideFlag = this.isTickMarksInside();
			p.scaleNumbersIntegerFlag = this.isNumbersInteger();
			p.exponentFlag = this.getExponentFlag();
			p.exponentValue = this.getExponentValue();

			return p;
		}



		/**
		 * 
		 */
		private boolean setProperties( AxisIndividualProperties p )
		{
			this.mLocationInCube = p.location;
			this.mAxis.setScaleType( p.scaleType );
			this.mAxis.setRange( p.minValue, p.maxValue );
			
			this.setInvertCoordinates( p.invertCoordinatesFlag );
			this.setCalculateAutomatically( p.autoCalcAxisNumberFlag );
			this.setStepValue( p.incrementValue );
			this.setBaselineValue( p.baseTickValue );
			this.setTitle( p.titleString );
			this.setAxisVisible( p.axisVisibleFlag );
			this.setTitleVisible( p.titleVisibleFlag );
			this.setTickMarksVisible( p.scaleLinesVisibleFlag );
			this.setNumbersVisible( p.scaleNumbersVisibleFlag );
			this.setTickMarksInside( p.scaleLinesInsideFlag );
			this.setNumbersInteger( p.scaleNumbersIntegerFlag );
			this.setExponentFlag( p.exponentFlag );
			this.setExponentValue( p.exponentValue );

			return true;
		}


	}




	/**
	 * 
	 */
	public SGProperties getProperties()
	{
		AxisProperties wp = new AxisProperties();

		wp.cp = this.getCommonProperties();
		wp.ipArray = new AxisIndividualProperties[this.mElementsGroupList.size()];
		for( int ii=0; ii<wp.ipArray.length; ii++ )
		{
			ElementsGroupOfAxis group
				= (ElementsGroupOfAxis)this.mElementsGroupList.get(ii);
			wp.ipArray[ii] = group.getProperties();
		}

		return wp;
	}



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

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

		AxisProperties wp = (AxisProperties)p;

		if( this.setCommonProperties( wp.cp ) == false )
		{
			return false;
		}

		AxisIndividualProperties[] array = wp.ipArray;
		for( int ii=0; ii<array.length; ii++ )
		{
			ElementsGroupOfAxis group = this.getAxisGroupInCube( array[ii].location );
			if( group.setProperties( array[ii] ) == false )
			{
				return false;
			}
		}

		return true;
	}





	/**
	 * 
	 */
	private AxisCommonProperties getCommonProperties()
	{
		AxisCommonProperties p = new AxisCommonProperties();

		p.viewDirection = this.mViewDirection;
		p.frameLinesVisibleFlag = this.mFrameLineVisibleFlag;
		p.frameLineWidth = this.mFrameLineWidth;
		p.frameLineColor = this.mFrameLineColor;
		p.lineColor = this.mLineColor;
		p.stringColor = this.mStringColor;
		p.axisLineWidth = this.mAxisLineWidth;
		p.tickMarkWidth = this.mScaleLineWidth;
		p.tickMarkLength = this.mTickMarkLength;
		p.fontSize = this.mTitleFontSize;
		p.fontName = this.mTitleFontName;
		p.fontStyle = this.mTitleFontStyle;

		return p;
	}



	/**
	 * 
	 */
	private boolean setCommonProperties( AxisCommonProperties p )
	{
		this.mViewDirection = p.viewDirection;
		this.setFrameLineVisible( p.frameLinesVisibleFlag );
		this.setFrameLineWidth( p.frameLineWidth );
		this.setFrameLineColor( p.frameLineColor );
		this.setLineColor( p.lineColor );
		this.setStringColor( p.stringColor );
		this.setAxisLineWidth( p.axisLineWidth );
		this.setTickMarkWidth( p.tickMarkWidth );
		this.setTickMarkLength( p.tickMarkLength );
		this.setFontSize( p.fontSize );
		this.setFontName( p.fontName );
		this.setFontStyle( p.fontStyle );

		return true;
	}




	/**
	 * @author  okumura
	 */
	public static class AxisProperties extends SGProperties
	{
		AxisCommonProperties cp;
		/**
		 * @uml.property  name="ipArray"
		 * @uml.associationEnd  multiplicity="(0 -1)"
		 */
		AxisIndividualProperties[] ipArray;

		AxisProperties(){}

		public void dispose()
		{
			this.cp.dispose();
			this.cp = null;

			AxisIndividualProperties[] array = this.ipArray;
			for( int ii=0; ii<array.length; ii++ )
			{
				this.ipArray[ii].dispose();
			}
			array = null;
			this.ipArray = null;
		}
		
		/**
		 * 
		 */
		public boolean equals( final Object obj )
		{
			if( ( obj instanceof AxisProperties) == false )
			{
				return false;
			}
			
			AxisProperties p = (AxisProperties)obj;

			if( (p.cp).equals(this.cp) == false ) return false;
			if( p.ipArray.length != this.ipArray.length ) return false;
			for( int ii=0; ii<this.ipArray.length; ii++ )
			{
				if( p.ipArray[ii].equals( this.ipArray[ii] ) == false )
				{
					return false;
				}
			}

			return true;
		}
	}



	/**
	 * 
	 */
	public static class AxisCommonProperties extends SGProperties
	{
		int viewDirection;
		boolean frameLinesVisibleFlag;
		float frameLineWidth;
		Color frameLineColor;
		Color lineColor;
		Color stringColor;
		float axisLineWidth;
		float tickMarkWidth;
		float tickMarkLength;
		float fontSize;
		String fontName;
		int fontStyle;

		public void dispose()
		{
			this.frameLineColor = null;
			this.lineColor = null;
			this.stringColor = null;
			this.fontName = null;
		}


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

			AxisCommonProperties p = (AxisCommonProperties)obj;

			if( p.viewDirection!=this.viewDirection ) return false;
			if( p.frameLinesVisibleFlag!=this.frameLinesVisibleFlag ) return false;
			if( p.frameLineWidth!=this.frameLineWidth ) return false;
			if( p.frameLineColor.equals(this.frameLineColor) == false ) return false;
			if( p.lineColor.equals(this.lineColor) == false ) return false;
			if( p.stringColor.equals(this.stringColor) == false ) return false;
			if( p.axisLineWidth!=this.axisLineWidth ) return false;
			if( p.tickMarkWidth!=this.tickMarkWidth ) return false;
			if( p.tickMarkLength!=this.tickMarkLength ) return false;
			if( p.fontSize!=this.fontSize ) return false;
			if( p.fontName.equals(this.fontName) == false ) return false;
			if( p.fontStyle!=this.fontStyle ) return false;

			return true;
		}


	}



	/**
	 * 
	 */
	public static class AxisIndividualProperties extends SGProperties
	{
		int location;
		int scaleType;
		double minValue;
		double maxValue;
		boolean invertCoordinatesFlag;
		boolean autoCalcAxisNumberFlag;
		double incrementValue;
		double baseTickValue;
		String titleString;
		boolean axisVisibleFlag;
		boolean titleVisibleFlag;
		boolean scaleLinesVisibleFlag;
		boolean scaleNumbersVisibleFlag;
		boolean scaleLinesInsideFlag;
		boolean scaleNumbersIntegerFlag;
		boolean exponentFlag;
		int exponentValue;

		public void dispose()
		{
			this.titleString = null;
		}


		/**
		 * 
		 */
		public boolean equals( final Object obj )
		{
			if( ( obj instanceof AxisIndividualProperties) == false )
			{
				return false;
			}
			
			AxisIndividualProperties p = (AxisIndividualProperties)obj;
			
			if( p.location!=this.location ) return false;
			if( p.scaleType!=this.scaleType ) return false;
			if( p.minValue!=this.minValue ) return false;
			if( p.maxValue!=this.maxValue ) return false;
			if( p.invertCoordinatesFlag!=this.invertCoordinatesFlag ) return false;
			if( p.autoCalcAxisNumberFlag!=this.autoCalcAxisNumberFlag ) return false;
			if( p.incrementValue!=this.incrementValue ) return false;
			if( p.baseTickValue!=this.baseTickValue ) return false;
			if( p.titleString.equals(this.titleString) == false ) return false;
			if( p.axisVisibleFlag!=this.axisVisibleFlag ) return false;
			if( p.titleVisibleFlag!=this.titleVisibleFlag ) return false;
			if( p.scaleLinesVisibleFlag!=this.scaleLinesVisibleFlag ) return false;
			if( p.scaleNumbersVisibleFlag!=this.scaleNumbersVisibleFlag ) return false;
			if( p.scaleLinesInsideFlag!=this.scaleLinesInsideFlag ) return false;
			if( p.scaleNumbersIntegerFlag!=this.scaleNumbersIntegerFlag ) return false;
			if( p.exponentFlag!=this.exponentFlag ) return false;
			if( p.exponentValue!=this.exponentValue ) return false;

			return true;
		}

	}


}


