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

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
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.JLabel;
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.SGDefaultValues;
import jp.riken.brain.ni.samuraigraph.base.SGDrawingElement;
import jp.riken.brain.ni.samuraigraph.base.SGIAxisBreakElement;
import jp.riken.brain.ni.samuraigraph.base.SGIAxisElement;
import jp.riken.brain.ni.samuraigraph.base.SGIConstants;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElement;
import jp.riken.brain.ni.samuraigraph.base.SGIGraphElement;
import jp.riken.brain.ni.samuraigraph.base.SGIGridElement;
import jp.riken.brain.ni.samuraigraph.base.SGILegendElement;
import jp.riken.brain.ni.samuraigraph.base.SGISelectable;
import jp.riken.brain.ni.samuraigraph.base.SGISignificantDifferenceElement;
import jp.riken.brain.ni.samuraigraph.base.SGIStringElement;
import jp.riken.brain.ni.samuraigraph.base.SGITimingLineElement;
import jp.riken.brain.ni.samuraigraph.base.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.SGITwoDimensionalData;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementLine;
import jp.riken.brain.ni.samuraigraph.figure.SGFigureElement;
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;



/**
 * 軸描画用パネルクラス
 */


public class SGAxisElement extends SGFigureElement
	implements SGIAxisElement, SGIStringConstants, SGIAxisDialogObserver,
		CaretListener, ActionListener
{


	/**
	 * 視点情報
	 */
	private int mViewDirection = VIEW_XY;


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


	/**
	 *
	 */
	private Color mLineColor = SGDefaultValues.AXIS_LINE_COLOR;


	/**
	 *
	 */
	private float mAxisLineWidth = SGDefaultValues.AXIS_LINE_WIDTH;


	/**
	 *
	 */
	private float mScaleLineWidth = SGDefaultValues.SCALE_LINE_WIDTH;


	/**
	 *
	 */
	private Color mStringColor = SGDefaultValues.AXIS_STRING_COLOR;


	/**
	 *
	 */
	private float mTitleFontSize = SGDefaultValues.AXIS_FONT_SIZE;


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


	/**
	 * 
	 */
	private String mTitleFontName = SGDefaultValues.AXIS_FONT_NAME;



	/**
	 *
	 */
	private float mScaleFontSize = SGDefaultValues.AXIS_FONT_SIZE;


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


	/**
	 * 
	 */
	private String mScaleFontName = SGDefaultValues.AXIS_FONT_NAME;


	/**
	 * 
	 */
	private float mScaleLineLength = SGDefaultValues.SCALE_LINE_LENGTH;


	/**
	 * 
	 */
	private float mSpaceAxisLineAndNumber = SGDefaultValues.SPACE_AXIS_LINE_AND_NUMBER;


	/**
	 * 
	 */
	private float mSpaceNumberAndTitle = SGDefaultValues.SPACE_NUMBER_AND_TITLE;


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


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


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


	/**
	 * 
	 */
	private boolean mFrameLinesVisibleFlag = true;


	/**
	 * 
	 */
	private Color mFrameLineColor = SGDefaultValues.AXIS_FRAME_LINE_COLOR;


	/**
	 * 
	 */
	private float mFrameLineWidth = SGDefaultValues.AXIS_FRAME_LINE_WIDTH;


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


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


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



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



	/**
	 * 
	 */
	private boolean init()
	{
		this.setAxisLineWidth( SGDefaultValues.AXIS_LINE_WIDTH );
		this.setScaleLineWidth( SGDefaultValues.SCALE_LINE_WIDTH );
		this.setScaleLineLength( SGDefaultValues.SCALE_LINE_LENGTH );
		this.setLineColor( SGDefaultValues.AXIS_LINE_COLOR );
		this.setFrameLinesVisible( SGDefaultValues.AXIS_FRAME_LINE_VISIBLE );
		this.setFrameLineWidth( SGDefaultValues.AXIS_FRAME_LINE_WIDTH );
		this.setFrameLineColor( SGDefaultValues.AXIS_FRAME_LINE_COLOR );
		this.setFontName( SGDefaultValues.AXIS_FONT_NAME );
		this.setFontSize( SGDefaultValues.AXIS_FONT_SIZE );
		int style = SGUtilityText.getFontStyle( SGDefaultValues.AXIS_FONT_STYLE );
		if( style==-1 )
		{
			return false;
		}
		this.setFontStyle( style );
		this.setStringColor( SGDefaultValues.AXIS_STRING_COLOR );

		return true;
	}


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

		return true;
	}



	/**
	 * 
	 */
	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();

		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 int getFontStyle()
	{
		return this.mTitleFontStyle;
	}


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


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


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


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


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


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


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


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


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


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


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


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



	/**
	 * Returns the axis configuration of the selected tab.
	 * @return
	 */
	public int getAxisConfigurationForSelectedTab()
	{
		return this.mTempAxisConfiguration;
	}
	
	private int mTempAxisConfiguration = -1;




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

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

		}
		else if( element instanceof SGIStringElement )
		{
			
		}
		else if( element instanceof SGILegendElement )
		{
			
		}
		else if( element instanceof SGIAxisElement )
		{
			
		}
		else if( element instanceof SGIAxisBreakElement )
		{
			
		}
		else if( element instanceof SGISignificantDifferenceElement )
		{
			
		}
		else if( element instanceof SGITimingLineElement )
		{
			
		}
		else if( element instanceof SGIGridElement )
		{

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


		return flag;
	}



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



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

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

		return true;
	}


	
	/**
	 * 
	 */
	public boolean onMouseClicked( final MouseEvent e )
	{
		// Axis Groups
		for( int ii=0; ii<mElementsGroupList.size(); ii++ )
		{
			final ElementsGroupOfAxis element = (ElementsGroupOfAxis)mElementsGroupList.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<mElementsGroupList.size(); ii++ )
		{
			final ElementsGroupOfAxis element = (ElementsGroupOfAxis)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<mElementsGroupList.size(); ii++ )
		{
			final ElementsGroupOfAxis element
				= (ElementsGroupOfAxis)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<mElementsGroupList.size(); ii++ )
		{
			final ElementsGroupOfAxis element
				= (ElementsGroupOfAxis)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;
	}



	/**
	 * 
	 */
	private static final double ALTERNATIVE_AXIS_VALUE = 1.0;



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

		super.addData(data,name);


		// 最初にデータを追加するときに軸を作成
		if( this.mElementsGroupList.size() == 0 )
		{

			// in case of two-dimensional data
			if( data instanceof SGITwoDimensionalData )
			{

				SGITwoDimensionalData tData = (SGITwoDimensionalData)data;

				// get the range
				final double xMin = tData.getMinValueX();
				final double xMax = tData.getMaxValueX();
				final double yMin = tData.getMinValueY();
				double yMax = tData.getMaxValueY();

				final double yRange = yMax - yMin;
				final double yMargin = 0.050*yRange;

				double xMin_ = xMin;
				double xMax_ = xMax;
				double yMin_ = yMin - yMargin;
				double yMax_ = yMax + yMargin;

				yMin_ = SGUtilityNumber.getNumberInRangeOrder(
					yMin_, yMin, yMax,
					AXIS_SCALE_EFFECTIVE_DIGIT );
				yMax_ = SGUtilityNumber.getNumberInRangeOrder(
					yMax_, yMin, yMax,
					AXIS_SCALE_EFFECTIVE_DIGIT );


				// if the min and max values are extremely close,
				// set the alternative values
				double aValue = ALTERNATIVE_AXIS_VALUE;
				if( Math.abs(xMax-xMin)<Double.MIN_VALUE )
				{
					xMin_ = xMin - aValue;
					xMax_ = xMin + aValue;
				}
				if( Math.abs(yMax-yMin)<Double.MIN_VALUE )
				{
					yMin_ = yMin - aValue;
					yMax_ = yMin + aValue;
				}


				//
				// 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();
					xAxis.setRange( xMin_, xMax_ );
					xAxis.setScaleType( SGAxis.LINEAR_TYPE );

					final ElementsGroupOfAxis group = groupX1;
					group.zoom( this.mMagnification );
					group.setConfigurationInPlane( SGAxisElement.AXIS_HORIZONTAL_1 );
					group.mAxis = xAxis;
					group.mVisibleFlag = SGDefaultValues.BOTTOM_AXIS_VISIBLE;
					group.setTitle( SGDefaultValues.BOTTOM_AXIS_TITLE );
					mElementsGroupList.add(group);
				}

				// X2
				{
					final SGAxis xAxis = new SGAxis();
					xAxis.setRange( xMin_, xMax_ );
					xAxis.setScaleType( SGAxis.LINEAR_TYPE );

					final ElementsGroupOfAxis group = groupX2;
					group.zoom( this.mMagnification );
					group.setConfigurationInPlane( SGAxisElement.AXIS_HORIZONTAL_2 );
					group.mAxis = xAxis;
					group.mVisibleFlag = SGDefaultValues.TOP_AXIS_VISIBLE;
					group.mTitle.setString( SGDefaultValues.TOP_AXIS_TITLE );
					mElementsGroupList.add(group);
				}

				// Y1
				{
					final SGAxis yAxis = new SGAxis();
					yAxis.setRange( yMin_, yMax_ );
					yAxis.setScaleType( SGAxis.LINEAR_TYPE );

					final ElementsGroupOfAxis group = groupY1;
					group.zoom( this.mMagnification );
					group.setConfigurationInPlane( SGAxisElement.AXIS_PERPENDICULAR_1 );
					group.mAxis = yAxis;
					group.mVisibleFlag = SGDefaultValues.LEFT_AXIS_VISIBLE;
					group.mTitle.setString( SGDefaultValues.LEFT_AXIS_TITLE );
					mElementsGroupList.add(group);
				}

				// Y2
				{
					final SGAxis yAxis = new SGAxis();
					yAxis.setRange( yMin_, yMax_ );
					yAxis.setScaleType( SGAxis.LINEAR_TYPE );

					final ElementsGroupOfAxis group = groupY2;
					group.zoom( this.mMagnification );
					group.setConfigurationInPlane( SGAxisElement.AXIS_PERPENDICULAR_2 );
					group.mAxis = yAxis;
					group.mVisibleFlag = SGDefaultValues.RIGHT_AXIS_VISIBLE;
					group.mTitle.setString( SGDefaultValues.RIGHT_AXIS_TITLE );
					mElementsGroupList.add(group);
				}


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


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

			}
			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 setScaleLineWidth( final float width )
	{
		this.mScaleLineWidth = width;
		return true;
	}


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


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


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


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


	/**
	 * 
	 */
	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 setSpaceNumberAndTitle( final float margin )
	{
		this.mSpaceNumberAndTitle = margin;
		return true;
	}



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


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


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


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

	
	/**
	 * 
	 * @param x
	 * @param y
	 * @return
	 */
	private ElementsGroupOfAxis getAxisGroup( final int x, final int y )
	{
		for( int ii=0; ii<this.mElementsGroupList.size(); ii++ )
		{
			final ElementsGroupOfAxis group
				= (ElementsGroupOfAxis)this.mElementsGroupList.get(ii);
			if( group.isAxisVisible() == false )
			{
				continue;
			}
			if( group.contains(x,y) )
			{
				return group;
			}
		}
		return null;
	}



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


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

	
	/**
	 * 
	 * @param group
	 * @param x
	 * @param y
	 * @return
	 */
	private double getValue(
		ElementsGroupOfAxis group, final int x, final int y )
	{
		SGAxis axis = group.mAxis;
		double value = 0.0;
		ArrayList hList = this.getHorizontalAxisList();
		ArrayList pList = this.getPerpendicularAxisList();
		if( hList.contains( axis ) )
		{
			value = calcValue( x, axis, true );
		}
		else if( pList.contains( axis ) )
		{
			value = calcValue( y, axis, false );
		}
		else
		{
			throw new Error();
		}
		value = this.getNumberInRangeOrder( value, group.mAxis );
		
		return value;
	}
	

	/**
	 * 
	 */
	private SGITimingLineElement mTimingLineElement = null;

	
	/**
	 * 
	 */
	public boolean addTimingLine( final int x, final int y )
	{
		// get the axis group
		ElementsGroupOfAxis group = this.getAxisGroup(x,y);
		if( group==null )
		{
			return false;
		}

		// calculate the value
		final double value = this.getValue( group, x, y );
		this.mTimingLineElement.addTimingLine( group.mAxis, value );
		
		return true;
	}


	/**
	 * 
	 * @param element
	 */
	public void setTimingLineElement( SGITimingLineElement element )
	{
		this.mTimingLineElement = element;
	}

	
	
	/**
	 * 新しい軸のグループを追加する
	 */
	private ElementsGroupOfAxis addAxisGroup(
		final int configInCube, final SGTuple2d range, final int scaleType )
	{

//System.out.println(configInCube);

		final ElementsGroupOfAxis group = new ElementsGroupOfAxis();
		final SGAxis axis = new SGAxis();
		axis.setRange( new SGTuple2d(range) );
		axis.setScaleType( scaleType );
		group.mAxis = axis;
		group.setConfigurationInCube( configInCube );
		mElementsGroupList.add(group);

		return group;
	}



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



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

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


		//
		// 描画
		//

		for( int ii=0; ii<mElementsGroupList.size(); ii++ )
		{
			final ElementsGroupOfAxis group = (ElementsGroupOfAxis)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*mFrameLineWidth ) );

		g2d.drawRect(
			(int)(mGraphRectX),
			(int)(mGraphRectY),
			(int)(mGraphRectWidth),
			(int)(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.drawString(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 config = this.getConfiguration( group.getConfigurationInCube() );
			if( config==AXIS_HORIZONTAL_1 || config==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 config = this.getConfiguration( group.getConfigurationInCube() );
			if( config==AXIS_PERPENDICULAR_1 || config==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 configInCube )
	{
		final ElementsGroupOfAxis group = this.getAxisGroupInCube( configInCube );

//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 configInPlane )
	{
		final ElementsGroupOfAxis group = this.getAxisGroupInPlane( configInPlane );

//System.out.println(group);

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

		SGAxis axis = group.mAxis;

//System.out.println(axis);

		return axis;
	}


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


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


	/**
	 * 
	 */
	private ElementsGroupOfAxis getAxisGroupInPlane( final int configInPlane )
	{
		for( int ii=0; ii<mElementsGroupList.size(); ii++ )
		{
			final ElementsGroupOfAxis group
				= (ElementsGroupOfAxis)mElementsGroupList.get(ii);
//System.out.println("ii="+ii+"  "+group.getConfigurationInPlane());
			if( group.getConfigurationInPlane() == configInPlane )
			{
				return group;
			}
		}
		
		return null;		
	}



	/**
	 * 
	 */
	public int getConfigurationInCube( final SGAxis axis )
	{
		if( axis == null )
		{
			return 0;
		}

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

		}

		return config;
	}


	
	/**
	 * 
	 * @param config
	 * @return
	 */
	public String getAxisLocation( final SGAxis axis )
	{
		final int config = this.getConfigurationInPlane(axis);
		return this.getAxisLocation(config);
	}


	/**
	 * 
	 * @param config
	 * @return
	 */
	public String getAxisLocation( final int config )
	{
		String str = null;
		switch( config )
		{
			case AXIS_HORIZONTAL_1 :
			{
				str = AXIS_BOTTOM;
				break;
			}
			
			case AXIS_HORIZONTAL_2 :
			{
				str = AXIS_TOP;
				break;
			}
			
			case AXIS_PERPENDICULAR_1 :
			{
				str = AXIS_LEFT;
				break;
			}

			case AXIS_PERPENDICULAR_2 :
			{
				str = AXIS_RIGHT;
				break;
			}

			default:
			{
				
			}
		}
	
		return str;
	}
	
	
	/**
	 * 
	 * @param str
	 * @return
	 */
	public int getConfigFromString( final String str )
	{
		int config = -1;
		if( AXIS_BOTTOM.equals(str) )
		{
			config = AXIS_HORIZONTAL_1;
		}
		else if( AXIS_TOP.equals(str) )
		{
			config = AXIS_HORIZONTAL_2;
		}
		else if( AXIS_LEFT.equals(str) )
		{
			config = AXIS_PERPENDICULAR_1;
		}
		else if( AXIS_RIGHT.equals(str) )
		{
			config = AXIS_PERPENDICULAR_2;
		}
		
		return config;
	}

	
	
	/**
	 * 
	 * @param axis
	 * @return
	 */
	public String getConfigurationStringInPlane( final SGAxis axis )
	{
		final int config = this.getConfigurationInPlane( axis );
		return this.getAxisLocation( config );
	}
	
	
	/**
	 * 
	 */
	public int getConfigurationInPlane( final SGAxis axis )
	{
		if( axis == null )
		{
			return 0;
		}

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

		}

		return config;
	}


	/**
	 * 
	 * @return
	 */
	public int getConfiguration( final int configurationInCube )
	{

		int config=0;

		switch( mViewDirection )
		{
			case VIEW_XY :
			{

				switch( configurationInCube )
				{
					
					case LOCATION_XAXIS_1 :
					{
						config = AXIS_HORIZONTAL_1;
						break;
					}
					case LOCATION_XAXIS_2 :
					{
						config = AXIS_HORIZONTAL_2;
						break;
					}
					case LOCATION_XAXIS_3 :
					{
						config = AXIS_HORIZONTAL_2;
						break;
					}
					case LOCATION_XAXIS_4 :
					{
						config = AXIS_HORIZONTAL_1;
						break;
					}
					case LOCATION_YAXIS_1 :
					{
						config = AXIS_PERPENDICULAR_1;
						break;
					}
					case LOCATION_YAXIS_2 :
					{
						config = AXIS_PERPENDICULAR_1;
						break;
					}
					case LOCATION_YAXIS_3 :
					{
						config = AXIS_PERPENDICULAR_2;
						break;
					}
					case LOCATION_YAXIS_4 :
					{
						config = AXIS_PERPENDICULAR_2;
						break;
					}
					default :
					{
						config = -1;
					}
						
				}

				break;

			}
			case VIEW_XZ :
			{

				break;
			}
			case VIEW_YZ :
			{

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

		}


		return config;

	}



	/**
	 * 
	 * @return
	 */
	private int getConfigurationInCubeByPlane( final int configurationInPlane )
	{

		int config = 0;

		switch( mViewDirection )
		{
			case VIEW_XY :
			{

				switch( configurationInPlane )
				{
					
					case AXIS_HORIZONTAL_1 :
					{
						config = LOCATION_XAXIS_1;
						break;
					}
					case AXIS_HORIZONTAL_2 :
					{
						config = LOCATION_XAXIS_2;
						break;
					}
					case AXIS_PERPENDICULAR_1 :
					{
						config = LOCATION_YAXIS_1;
						break;
					}
					case AXIS_PERPENDICULAR_2 :
					{
						config = LOCATION_YAXIS_4;
						break;
					}
					default :
					{
						config = -1;
					}
						
				}

				break;

			}
			case VIEW_XZ :
			{

				break;
			}
			case VIEW_YZ :
			{

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

		}

		return config;
	}




	/**
	 * 
	 */
	public String getConfigurationString( final int configInCube )
	{
		final int config = this.getConfiguration( configInCube );
		return this.getAxisLocation(config);
	}



	/**
	 * 
	 */
	public int getConfigurationInCube( final String str )
	{
		final int config = this.getConfigFromString(str);
		final int configInCube = this.getConfigurationInCubeByPlane( config );
		return configInCube;
	}


	
	/**
	 * 
	 * @param str
	 * @return
	 */
	public SGAxis getAxis( final String str )
	{
		final int config = this.getConfigurationInCube( str );
		final SGAxis axis = this.getAxisInCube( config );
		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;
	}



	private SGDrawingElementString2D mEditingStringElement = null;


	/**
	 * 
	 */
	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.mChangedFlag = 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 undo()
	{
		boolean flag = super.undo();
		if( !flag )
		{
			return false;
		}

		this.createAllDrawingElements();
		this.notifyChange();

//		repaint();

		return true;
	}


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

		this.createAllDrawingElements();
		this.notifyChange();

//		repaint();

		return true;
	}


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



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

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

		boolean flag = super.addPropertiesHistory(p);		

		return flag;
	}

	
	

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

		final ArrayList numberList = group.mScaleNumberList;
		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<mElementsGroupList.size(); ii++ )
		{
			final ElementsGroupOfAxis group = (ElementsGroupOfAxis)mElementsGroupList.get(ii);
			if( group.createDrawingElements() == false )
			{
				return false;
			}
		}

		return true;
	}


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

		return true;
	}



	/**
	 * 
	 * @return
	 */
	public String getTagName()
	{
		return SGAxisElement.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 )
	{
		final String cm = SGUtilityNumber.cm;
		final String pt = SGUtilityNumber.pt;

		el.setAttribute( KEY_AXIS_LINE_WIDTH, Float.toString( this.mAxisLineWidth ) + pt );
		el.setAttribute( KEY_TICK_MARK_WIDTH, Float.toString( this.mScaleLineWidth ) + pt );
		el.setAttribute( KEY_TICK_MARK_LENGTH, Float.toString( this.mScaleLineLength*SGIConstants.CM_POINT_RATIO ) + 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 ) + 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.mFrameLinesVisibleFlag ) );
		el.setAttribute( KEY_FRAME_LINE_WIDTH, Float.toString( this.mFrameLineWidth ) + 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( SGAxisElement.LOCATION_XAXIS_1 );
		if( group==null )
		{
			return false;
		}
		group = this.addAxisGroup( SGAxisElement.LOCATION_XAXIS_2 );
		if( group==null )
		{
			return false;
		}
		group = this.addAxisGroup( SGAxisElement.LOCATION_YAXIS_1 );
		if( group==null )
		{
			return false;
		}
		group = this.addAxisGroup( SGAxisElement.LOCATION_YAXIS_4 );
		if( group==null )
		{
			return false;
		}
		
		
		// create the property dialog
		boolean flag = this.createDialog( SGIAxisElement.TWO_DIMENSIONAL_AXIS );
		if( !flag )
		{
			return false;
		}
		
		
		flag = this.setProperty( element );
		if( !flag )
		{
			return false;
		}
		
		return true;
	}
	
	
	
	/**
	 * 
	 * @param element
	 * @return
	 */
	private AxisCommonProperties readCommonProperties( final Element element )
	{
		final String cm = SGUtilityNumber.cm;
		final String pt = SGUtilityNumber.pt;
		final float ratio = SGIConstants.CM_POINT_RATIO;

		String str = null;
		Number num = null;
		Color cl = null;
		Boolean b = null;

		// axis line width
		str = element.getAttribute( SGAxisElement.KEY_AXIS_LINE_WIDTH );
		if( str.length()==0 )
		{
			return null;
		}
		num = SGUtilityText.getFloat(str,pt);
		if( num==null )
		{
			return null;
		}
		final float axisLineWidth = num.floatValue();

		
		// scale line width
		str = element.getAttribute( SGAxisElement.KEY_TICK_MARK_WIDTH );
		if( str.length()==0 )
		{
			return null;
		}
		num = SGUtilityText.getFloat(str,pt);
		if( num==null )
		{
			return null;
		}
		final float scaleLineWidth = num.floatValue();
		

		// scale line length
		str = element.getAttribute( SGAxisElement.KEY_TICK_MARK_LENGTH );
		if( str.length()==0 )
		{
			return null;
		}
		num = SGUtilityText.getFloat(str,cm);
		if( num==null )
		{
			return null;
		}
		final float scaleLineLength = num.floatValue()/ratio;


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


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

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

		
		// font size
		str = element.getAttribute( KEY_FONT_SIZE );
		if( str.length()==0 )
		{
			return null;
		}
		num = SGUtilityText.getFloat(str,pt);
		if( num==null )
		{
			return null;
		}
		final float fontSize = num.floatValue();

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

		
		// frame line visible
		str = element.getAttribute( SGAxisElement.KEY_FRAME_LINE_VISIBLE );
		if( str.length()==0 )
		{
			return null;
		}
		b = SGUtilityText.getBoolean(str);
		if( b==null )
		{
			return null;
		}
		final boolean frameLineVisible = b.booleanValue();
		
		
		// frame line width
		str = element.getAttribute( SGAxisElement.KEY_FRAME_LINE_WIDTH );
		if( str.length()==0 )
		{
			return null;
		}
		num = SGUtilityText.getFloat(str,pt);
		if( num==null )
		{
			return null;
		}
		final float frameLineWidth = num.floatValue();
		
		
		// frame line color
		str = element.getAttribute( SGAxisElement.KEY_FRAME_LINE_COLOR );
		if( str.length()==0 )
		{
			return null;
		}
		cl = SGUtilityText.getColorFromString(str);
		if( cl==null )
		{
			return null;
		}
		final Color frameLineColor = cl;
		
		
		AxisCommonProperties p = new AxisCommonProperties();
		p.axisLineWidth = axisLineWidth;
		p.scaleLineLength = scaleLineLength;
		p.scaleLineWidth = scaleLineWidth;
		p.lineColor = lineColor;
		p.stringColor = stringColor;
		p.fontName = fontName;
		p.fontSize = fontSize;
		p.fontStyle = fontStyle;
		p.frameLinesVisibleFlag = frameLineVisible;
		p.frameLineColor = frameLineColor;
		p.frameLineWidth = frameLineWidth;

		return p;
	}



	/**
	 * 
	 * @param element
	 * @return
	 */
	private AxisIndividualProperties readIndividualProperties(  final Element element )
	{
		final String cm = SGUtilityNumber.cm;
		final String pt = SGUtilityNumber.pt;
		final float ratio = SGIConstants.CM_POINT_RATIO;

		String str = null;
		Number num = null;
		Color cl = null;
		Boolean b = null;


		// configuration
		str = element.getAttribute( SGAxisElement.KEY_POSITION );
		if( str.length()==0 )
		{
			return null;
		}
		final int configInPlane = this.getConfigFromString( str );
		if( configInPlane==-1 )
		{
			return null;
		}
		final int config = this.getConfigurationInCubeByPlane( configInPlane );

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

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

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

		
		// auto calc
		str = element.getAttribute( SGAxisElement.KEY_AUTO_CALC_NUMBER );
		if( str.length()==0 )
		{
			return null;
		}
		b = SGUtilityText.getBoolean(str);
		if( b==null )
		{
			return null;
		}
		final boolean autoCalc = b.booleanValue();
		
		
		// increment value
		str = element.getAttribute( SGAxisElement.KEY_STEP_VALUE );
		if( str.length()==0 )
		{
			return null;
		}
		num = SGUtilityText.getDouble(str);
		if( num==null )
		{
			return null;
		}
		final double incrementValue = num.doubleValue();

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

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

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

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


		// scale numbers integer
		str = element.getAttribute( SGAxisElement.KEY_NUMBER_INTEGER );
		if( str.length()==0 )
		{
			return null;
		}
		b = SGUtilityText.getBoolean(str);
		if( b==null )
		{
			return null;
		}
		final boolean scaleNumbersInteger = b.booleanValue();

		
		// scale line visible
		str = element.getAttribute( SGAxisElement.KEY_TICK_MARK_VISIBLE );
		if( str.length()==0 )
		{
			return null;
		}
		b = SGUtilityText.getBoolean(str);
		if( b==null )
		{
			return null;
		}
		final boolean scaleLinesVisible = b.booleanValue();

		
		// scale lines inside
		str = element.getAttribute( SGAxisElement.KEY_TICK_MARK_INSIDE );
		if( str.length()==0 )
		{
			return null;
		}
		b = SGUtilityText.getBoolean(str);
		if( b==null )
		{
			return null;
		}
		final boolean scaleLinesInside = b.booleanValue();
		

		// exponent value
		str = element.getAttribute( SGAxisElement.KEY_EXPONENT_VISIBLE );
		if( str.length()==0 )
		{
			return null;
		}
		b = SGUtilityText.getBoolean(str);
		if( b==null )
		{
			return null;
		}
		final boolean exponentFlag = b.booleanValue();

		
		// exponent flag
		str = element.getAttribute( SGAxisElement.KEY_EXPONENT_VALUE );
		if( str.length()==0 )
		{
			return null;
		}
		num = SGUtilityText.getInteger(str);
		if( num==null )
		{
			return null;
		}
		final int exponentValue = num.intValue();
		
		
		AxisIndividualProperties p = new AxisIndividualProperties();
		
		p.configuration = config;
		p.axisVisibleFlag = axisVisible;
		p.scaleType = scaleType;
		p.minValue = minValue;
		p.maxValue = maxValue;
		p.autoCalcAxisNumberFlag = autoCalc;
		p.incrementValue = incrementValue;
		p.baseTickValue = baselineValue;
		p.titleVisibleFlag = titleVisible;
		p.titleString = titleString;
		p.scaleNumbersVisibleFlag = scaleNumbersVisible;
		p.scaleNumbersIntegerFlag = scaleNumbersInteger;
		p.scaleLinesInsideFlag = scaleLinesInside;
		p.scaleLinesVisibleFlag = scaleLinesVisible;
		p.exponentFlag = exponentFlag;
		p.exponentValue = exponentValue;
		
		return p;
	}



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

		AxisCommonProperties cp = this.readCommonProperties( element );
		if( cp==null )
		{
			return false;
		}


		boolean flag = this.setCommonProperties(cp);
		if( !flag )
		{
			return false;
		}


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

				AxisIndividualProperties ip = this.readIndividualProperties(el);

				// get the axis-group
				ElementsGroupOfAxis group = this.getAxisGroupInCube( ip.configuration );
				flag = group.setProperties(ip);
				if( !flag )
				{
					return false;
				}

				if( group.createDrawingElements() == false )
				{
					return false;
				}

				
			}
		}
		
		
		return true;
	}




	/**
	 * 軸の線のクラス
	 */
	public static class ElementLineOfAxis extends SGDrawingElementLine2D
	{
		/**
		 *
		 */
		protected ElementLineOfAxis()
		{
			super();
		}
	}

	
	

	/**
	 * タイトル文字列のクラス
	 */
	public static class ElementStringOfTitle extends SGDrawingElementString2DExtended
	{
		/**
		 *
		 */
		protected ElementStringOfTitle()
		{
			super();
		}
	}




	/**
	 * 目盛りの線のクラス
	 */
	public static class ElementLineOfScale extends SGDrawingElementLine2D
	{
		/**
		 * 
		 */
		private double mValue;


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

		/**
		 * 
		 * @param el
		 */
		protected ElementLineOfScale( final ElementLineOfScale el )
		{
			super();
			this.mValue = el.mValue;
		}

	
	}




	/**
	 * 目盛りの数字のクラス
	 */
	public static class ElementStringOfScale extends SGDrawingElementString2DExtended
	{

		/**
		 * 
		 */
		private double mValue;


		/**
		 * 
		 * @param str
		 * @param fontStyle
		 * @param fontSize
		 */
		protected ElementStringOfScale(
			final String str,
			final String fontName,
			final int fontStyle,
			final float fontSize )
		{
			super( str, fontName, fontStyle, fontSize );
		}


		/**
		 * 
		 * @param el
		 */
		protected ElementStringOfScale( final ElementStringOfScale el )
		{
			super(el);
			this.mValue = el.mValue;
		}


	}



	/**
	 * 
	 */
	class ElementsGroupOfAxis implements ActionListener, SGIAxisPanelObserver
	{

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




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


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


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


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


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


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


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


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


		/**
		 * 
		 */
		private boolean mScaleNumbersVisibleFlag = true;


		/**
		 * 
		 */
		private boolean mScaleLinesVisibleFlag = true;


		/**
		 * 目盛り線を内側に描くかどうか
		 */
		private boolean mScaleLinesInsideFlag = true;


		/**
		 * 目盛りの数値の配列
		 */
		private double[] mAxisValueArray = null;


		/**
		 * 
		 */
		private boolean mAutoCalcAxisNumberFlag = true;


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


		/**
		 * 
		 */
		private double mBaseTickValue = 0.0;


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


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


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


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


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


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

		
		
		/**
		 * 
		 */
		private boolean mGridLineVisibleFlag;
		

		/**
		 * 
		 */
		private float mGridLineWidth;

		
		/**
		 * 
		 */
		private int mGridLineStyle;
		
		
		/**
		 * 
		 */
		private Color mGridLineColor;
		
		

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


		/**
		 * 
		 */
		private boolean init()
		{
			this.mScaleNumbersVisibleFlag = SGDefaultValues.NUMBER_VISIBLE;
			this.mScaleNumbersIntegerFlag = SGDefaultValues.NUMBER_INTEGER;
			this.mScaleLinesVisibleFlag = SGDefaultValues.SCALE_LINE_VISIBLE;
			this.mScaleLinesInsideFlag = SGDefaultValues.SCALE_LINE_INNER;
			this.mGridLineVisibleFlag = SGDefaultValues.AXIS_GRID_LINE_VISIBLE;
			this.mGridLineWidth = SGDefaultValues.AXIS_GRID_LINE_WIDTH;
			final Integer style = SGDrawingElementLine.getLineTypeFromName( SGDefaultValues.AXIS_GRID_LINE_TYPE );
			if( style==null )
			{
				return false;
			}
			this.mGridLineStyle = style.intValue();
			this.mGridLineColor = SGDefaultValues.AXIS_GRID_LINE_COLOR;

			this.createPopupMenu();

			return true;
		}



		/**
		 * 
		 * @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 int getScaleType()
		{
			return this.mAxis.getScaleType();
		}


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


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


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


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


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


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


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


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


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



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


		/**
		 * 
		 * @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 )
		{
			this.mAxis.setRange( value, this.getMaxValue() );
			return true;
		}


		/**
		 * 
		 * @param value
		 * @return
		 */
		public boolean setMaxValue( final double value )
		{
			this.mAxis.setRange( this.getMinValue(), value );
			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.mAutoCalcAxisNumberFlag = b;
			return true;
		}


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


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


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


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


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


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


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


		/**
		 * 
		 * @param value
		 * @return
		 */
		public boolean setExponentValue( final int value )
		{
			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_TYPE )
			{
				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;
		}





		public static final String MENUCMD_HIDE = "Hide Axis";


		/**
		 * 
		 */
		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.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.mVisibleFlag = false;
				repaint();
				setChanged(true);
				notifyToRoot();
				return;
			}
			else if( command.equals( MENUCMD_PROPERTY ) )
			{
				this.showPropertyDialog();
			}

		}



		/**
		 * Show the property dialog.
		 *
		 */
		private void showPropertyDialog()
		{
			SGAxisElement.this.mClickedFlag = true;
			SGAxisElement.this.mTempAxisConfiguration = this.getConfigurationInPlane();

			SGAxisElement.this.setPropertiesOfSelectedObjects();

			SGAxisElement.this.mClickedFlag = false;
			SGAxisElement.this.mTempAxisConfiguration = -1;
		}


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

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

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

				// scale numbers
				if( this.mScaleNumbersVisibleFlag )
				{
					final ArrayList nList = this.mScaleNumberList;
					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( mExponentFlag )
					{
						drawString( this.mExponentDrawingElement, g2d );
					}
				}

				// scale lines
				if( this.mScaleLinesVisibleFlag )
				{
					final ArrayList lList = this.mScaleLineList;
					final boolean flag
						= ( this.mDraggingElement != null )
							& ( this.mDraggingElement instanceof ElementLineOfScale );
					final float width = mMagnification*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 );
						}
					}

				}

			}

		}



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



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


		/**
		 * 
		 */
		private int getConfigurationInPlane()
		{
			return getConfiguration( this.mConfigurationInCube );
		}


		/**
		 * 
		 */
		private int getConfigurationInCube()
		{
			return this.mConfigurationInCube;
		}


		/**
		 * 
		 */
		private boolean setConfigurationInPlane( final int configurationInPlane )
		{
			this.mConfigurationInCube = getConfigurationInCubeByPlane( configurationInPlane );
			return true;
		}


		/**
		 * 
		 */
		private boolean setConfigurationInCube( final int configurationInCube )
		{
			this.mConfigurationInCube = configurationInCube;
			return true;
		}


		/**
		 * ズーム
		 */
		public boolean zoom( final float mag )
		{
			this.mAxisLine.zoom(mag);
			this.mTitle.zoom(mag);
			for( int ii=0; ii<this.mScaleNumberList.size(); ii++ )
			{
				ElementStringOfScale el = (ElementStringOfScale)this.mScaleNumberList.get(ii);
				el.zoom(mag);
			}
			for( int ii=0; ii<this.mScaleLineList.size(); ii++ )
			{
				ElementLineOfScale el = (ElementLineOfScale)this.mScaleLineList.get(ii);
				el.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.mTitleVisibleFlag )
			{
				list.add( this.mTitle );
			}

			if( this.mScaleNumbersVisibleFlag )
			{
				for( int ii=0; ii<this.mScaleNumberList.size(); ii++ )
				{
					ElementStringOfScale el = (ElementStringOfScale)this.mScaleNumberList.get(ii);
					if( el.isVisible() )
					{
						list.add(el);
					}
				}

				if( this.mExponentFlag )
				{
					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;

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


			if( !this.mVisibleFlag )
			{
				return false;
			}


			// title
			if( this.mTitleVisibleFlag )
			{
				flag = this.mTitle.contains(x,y);
				if( flag )
				{
					if( (SwingUtilities.isLeftMouseButton(e) )
						&& ( e.getClickCount() == 1 ) )
					{
						SGAxisElement.this.showEditField( this.mTitle );
						return true;
					}
					else
					{
						return this.clicked(e);
					}
				}
			}


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


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


			return false;
		}



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

			boolean flag;

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

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


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

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


			return false;

		}



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

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

			return true;
		}




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

//System.out.println("$$ onMousePressed $$");

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


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

			boolean flag;

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


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


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

						return true;
					}
				}
			}


			// scale lines for axis
			if( this.mScaleLinesVisibleFlag )
			{
				for( int ii=0; ii<this.mScaleLineList.size(); ii++ )
				{
					ElementLineOfScale el
						= (ElementLineOfScale)(this.mScaleLineList).get(ii);
					if( el.isVisible() == false )
					{
						continue;
					}
					if( el.contains(x,y) )
					{
						mPressedElement = el;
						mPressedElementOrigin = e.getPoint();
						this.mTempRange = this.mAxis.getRange();
						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 scaleType = this.mAxis.getScaleType();


			//
			// 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_TYPE )
				{
					minValueTempInScale = this.mTempRange.x;
					maxValueTempInScale = this.mTempRange.y;
					oldValueInScale = el.mValue;
				}
				else if( scaleType==SGAxis.LOG_TYPE )
				{
					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( (this.getConfigurationInPlane()==AXIS_HORIZONTAL_1)
					|| (this.getConfigurationInPlane()==AXIS_HORIZONTAL_2) )
				{

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

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

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

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

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

					if( ( maxValueInScale - minValueInScale ) < 0.05*( maxValueTempInScale - minValueTempInScale ) )
					{
						return false;
					}


				}
				// perpendicular axes
				else if( (this.getConfigurationInPlane()==AXIS_PERPENDICULAR_1)
					|| (this.getConfigurationInPlane()==AXIS_PERPENDICULAR_2) )
				{

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

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

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

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

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

					if( ( maxValueInScale - minValueInScale ) < 0.05*( maxValueTempInScale - minValueTempInScale ) )
					{
						return false;
					}

				}
				else
				{
					throw new Error();
				}


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

				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_TYPE )
				{
					minValueTempInScale = this.mTempRange.x;
					maxValueTempInScale = this.mTempRange.y;
					oldValueInScale = el.mValue;
				}
				else if( scaleType==SGAxis.LOG_TYPE )
				{
					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( (this.getConfigurationInPlane()==AXIS_HORIZONTAL_1)
					|| (this.getConfigurationInPlane()==AXIS_HORIZONTAL_2) )
				{

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

					float minCoordinate = mAxisLine.getStart().x;
					float maxCoordinate = mAxisLine.getEnd().x;
					if( releasedCoordinate > maxCoordinate )
					{
						releasedCoordinate = maxCoordinate;
					}
					if( releasedCoordinate < minCoordinate )
					{
						releasedCoordinate = minCoordinate;
					}
					double 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_TYPE )
					{
						minValueInScale = getNumberInRangeOrder( minValueInScale, this.mAxis );
						maxValueInScale = getNumberInRangeOrder( maxValueInScale, this.mAxis );
					}

				}
				else if( (this.getConfigurationInPlane()==AXIS_PERPENDICULAR_1)
					|| (this.getConfigurationInPlane()==AXIS_PERPENDICULAR_2) )
				{

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

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

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


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

				}
				else
				{
					throw new Error();
				}



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

				mAxis.setRange( minValue, maxValue );

			}



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

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

//			repaint();


			return true;
		}



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

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

				// horizontal axes
				if( (this.getConfigurationInPlane()==AXIS_HORIZONTAL_1)
					|| (this.getConfigurationInPlane()==AXIS_HORIZONTAL_2) )
				{
					ElementsGroupOfAxis group = getAxisGroupInPlane( AXIS_PERPENDICULAR_1 );
				}
				// perpendicular axes
				else if( (this.getConfigurationInPlane()==AXIS_PERPENDICULAR_1)
					|| (this.getConfigurationInPlane()==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 )
			{
				SGAxisElement.this.setMouseCursor( Cursor.HAND_CURSOR );
				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.mScaleNumbersVisibleFlag )
			{
				if( this.setLocationOfScaleNumbers() == false )
				{
					return false;
				}
			}


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


			// title
			if( this.mTitleVisibleFlag )
			{
				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");


			// 目盛り線の作成
			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 = mGraphRectX;
			final float gy = mGraphRectY;
			final float gw = mGraphRectWidth;
			final float gh = mGraphRectHeight;

			switch( this.getConfigurationInPlane() )
			{

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

			}

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

			return true;
		}



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



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

			final float mag = 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.getConfigurationInPlane() )
			{
				case SGAxisElement.AXIS_HORIZONTAL_1 :
				{
					Rectangle2D rectTitle = mTitle.getElementBounds();
					mTitle.setLocation(
						gx + ( gw - (float)rectTitle.getWidth() )/2.0f,
						gy + gh + scaleNumberHeight + ( spaceLN + spaceNT )
					);

					break;
				}

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

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

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

				default :
				{
				
				}

			}

			return true;

		}



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


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

			// clear
			this.mScaleNumberList.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.mExponentValue;
			if( this.mExponentFlag )
			{
				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_TYPE )
			{
				if( this.mScaleNumbersIntegerFlag )
				{
					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_TYPE )
			{
				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 = mMagnification;
			final Color cl = mStringColor;
			final String name = mScaleFontName;
			final int style = mScaleFontStyle;
			final float size = mScaleFontSize;
			for( int ii=0; ii<vArray.length; ii++ )
			{
				ElementStringOfScale el = new ElementStringOfScale(
					strArray[ii],
					name,
					style,
					size );
				el.mValue = vArray[ii];
				if( this.mAxis.insideRange(el.mValue)==false )
				{
					el.setVisible(false);
				}
				el.setMagnification( mag );
				el.setColor( cl );
				this.mScaleNumberList.add(el);
			}


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


			return true;

		}



		/**
		 * 
		 * @return
		 */
		private boolean createExponentDrawingElement()
		{
			// craete an instance
			String str = multiply + "10";
			str = SGUtilityText.getSuperscriptString(
				str, Integer.toString( this.mExponentValue ) );
			SGDrawingElementString2DExtended el
				= new SGDrawingElementString2DExtended(
					str, mScaleFontName, mScaleFontStyle, mScaleFontSize );
			el.setMagnification( mMagnification );
			el.setColor( mStringColor );


			// 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 = mGraphRectX;
			final float gy = mGraphRectY;
			final float gw = mGraphRectWidth;
			final float gh = mGraphRectHeight;

			final float mag = mMagnification;

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

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

				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 config = this.getConfigurationInPlane();

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

			int scaleType = this.mAxis.getScaleType();

			double[] valueArrayInScale = null;
			if( scaleType == SGAxis.LINEAR_TYPE )
			{
				valueArrayInScale = this.mAxisValueArray;
			}
			else if( scaleType == SGAxis.LOG_TYPE )
			{
				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_TYPE )
			{
				axisMinInScale = this.mAxis.getMinValue();
				axisMaxInScale = this.mAxis.getMaxValue();
			}
			else if( scaleType == SGAxis.LOG_TYPE )
			{
				axisMinInScale = Math.log(this.mAxis.getMinValue());
				axisMaxInScale = Math.log(this.mAxis.getMaxValue());
			}

			final float mag = mMagnification;

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

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

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

				switch( config )
				{
					case AXIS_HORIZONTAL_1 :
					{
						final float 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 :
					{
						final float 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 :
					{
						final float 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 :
					{
						final float 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.mExponentFlag )
			{
				this.setLocationOfExponentDrawingElement();
			}


			return true;
		}




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


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

			return flag;
		}



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

			final float mag = mMagnification;
			final float length = mag*mScaleLineLength;
			final Color cl = 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.mScaleLineList.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.mScaleLineList.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 = mMagnification*mScaleLineLength;
			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( mMagnification );
					el.setColor( mLineColor );

					this.mScaleLineList.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( mMagnification );
						el.setColor( mLineColor );

						this.mScaleLineList.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( mMagnification );
						el.setColor( mLineColor );

						this.mScaleLineList.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 = mGraphRectX;
			final float gy = mGraphRectY;
			final float gw = mGraphRectWidth;
			final float gh = mGraphRectHeight;
			
			final float mag = mMagnification;
			final boolean inside = this.mScaleLinesInsideFlag;
			final float width = mScaleLineWidth;

			double min;
			double max;
			double valueInScale;
			switch( this.mAxis.getScaleType() )
			{
				case SGAxis.LINEAR_TYPE :
				{
					min = this.mAxis.getMinValue();
					max = this.mAxis.getMaxValue();
					valueInScale = value;
					break;
				}
				
				case SGAxis.LOG_TYPE :
				{
					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.getConfigurationInPlane() )
			{
				case AXIS_HORIZONTAL_1 :
				{
					final double 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 :
				{
					final double 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 :
				{
					final double 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 :
				{
					final double 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_TYPE :
				{
					array = this.calcScaleValuesInLinearScale();
					break;
				}
				
				case SGAxis.LOG_TYPE :
				{
					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.mAutoCalcAxisNumberFlag )
			{
				this.mBaseTickValue = 0.0;
				this.mStepValue = calcStepValue(axis);
			}

			final double reference = this.mBaseTickValue;
			final double increment = this.mStepValue;

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

					this.addNumberToList( value, valueList, order, true );
					cnt++;
					if( value > max )
					{
						break;
					}
				}
			}
/*
if( this.getConfigurationInPlane() == SGAxisElement.AXIS_HORIZONTAL_1 )
{
	System.out.println("upper:"+valueList);
	System.out.println(reference < min);
	System.out.println(this.mAxis.insideRange( reference + increment ));
}
ArrayList list = new ArrayList();
*/
			if( reference < min )
			{
				if( this.mAxis.insideRange( reference + increment ) )
				{
					valueList.add( 0, new Double( reference ) );
				}
			}
			else
			{
				int cnt = 0;
				while( true )
				{
					final double value = reference - cnt*increment;
					if( value > max )
					{
						if( this.mAxis.insideRange( value - increment ) )
						{
							this.addNumberToList( value, valueList, order, false );
						}
						cnt++;
						continue;
					}

					this.addNumberToList( value, valueList, order, false );
//list.add( new Double(tValue) );
					cnt++;
					if( value < min )
					{
						break;
					}
				}
			}
/*
if( this.getConfigurationInPlane() == SGAxisElement.AXIS_HORIZONTAL_1 )
{
	System.out.println("lower:"+list);
	System.out.println(valueList);
	System.out.println();
}
*/

			// 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();
			}

/*
if( this.getConfigurationInPlane() == SGAxisElement.AXIS_HORIZONTAL_1 )
{
	System.out.println("before");
	for( int ii=0; ii<axisValueArray.length; ii++ )
	{
		System.out.println(ii+"  "+axisValueArray[ii]);
	}
	System.out.println();
}
*/

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


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

				final ArrayList numList = new ArrayList();
				for( int ii=0; ii<axisValueArray.length; ii++ )
				{
					double value;
					if( this.mExponentFlag )
					{
						BigDecimal db = new BigDecimal(
							Double.toString( axisValueArray[ii] ) );
						db = db.movePointLeft( this.mExponentValue );
						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.mExponentFlag )
					{
						BigDecimal db = new BigDecimal(
							Double.toString(value) );
						db = db.movePointRight( this.mExponentValue );
						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-5 );
			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 double min = this.mAxis.getRange().x;
			final double max = this.mAxis.getRange().y;

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

			final int minOrder = SGUtilityNumber.getOrder( (1.0-1.0E-14)*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+1; 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 SGAxisElement.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 config = this.getConfigurationInCube();
			final String str = getConfigurationString(config);
			el.setAttribute( KEY_POSITION, str );

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

			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_AUTO_CALC_NUMBER, Boolean.toString( this.mAutoCalcAxisNumberFlag ) );
			el.setAttribute( KEY_STEP_VALUE, Double.toString( this.mStepValue ) );
			el.setAttribute( KEY_BASELINE_VALUE, Double.toString( this.mBaseTickValue ) );

			el.setAttribute( KEY_TITLE_VISIBLE, Boolean.toString( this.mTitleVisibleFlag) );
			el.setAttribute( KEY_TITLE_TEXT, this.mTitle.getString() );

			el.setAttribute( KEY_NUMBER_VISIBLE, Boolean.toString( this.mScaleNumbersVisibleFlag ) );
			el.setAttribute( KEY_NUMBER_INTEGER, Boolean.toString( this.mScaleNumbersIntegerFlag ) );

			el.setAttribute( KEY_TICK_MARK_VISIBLE, Boolean.toString( this.mScaleLinesVisibleFlag ) );
			el.setAttribute( KEY_TICK_MARK_INSIDE, Boolean.toString( this.mScaleLinesInsideFlag ) );

			el.setAttribute( KEY_EXPONENT_VISIBLE, Boolean.toString( this.mExponentFlag ) );
			el.setAttribute( KEY_EXPONENT_VALUE, Integer.toString( this.mExponentValue ) );

			el.setAttribute( KEY_GRID_LINE_VISIBLE, Boolean.toString( this.mGridLineVisibleFlag ) );
			el.setAttribute( KEY_GRID_LINE_WIDTH, Float.toString( this.mGridLineWidth ) + SGUtilityNumber.pt );
			el.setAttribute( KEY_GRID_LINE_STYLE, SGDrawingElementLine.getLineTypeName( this.mGridLineStyle ) );
			el.setAttribute( KEY_GRID_LINE_COLOR, SGUtilityText.getColorString( this.mGridLineColor ) );
			
			return true;

		}
		
		
		
		/**
		 * 
		 */
		private AxisIndividualProperties getProperties()
		{
			AxisIndividualProperties p = new AxisIndividualProperties();

			p.configuration = this.getConfigurationInCube();

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

			SGTuple2d range = this.mAxis.getRange();
			p.minValue = range.x;
			p.maxValue = range.y;
			
			p.autoCalcAxisNumberFlag = this.mAutoCalcAxisNumberFlag;
			p.incrementValue = this.mStepValue;
			p.baseTickValue = this.mBaseTickValue;
			p.titleString = this.mTitle.getString();
			p.axisVisibleFlag = this.mVisibleFlag;
			p.titleVisibleFlag = this.mTitleVisibleFlag;
			p.scaleLinesVisibleFlag = this.mScaleLinesVisibleFlag;
			p.scaleNumbersVisibleFlag = this.mScaleNumbersVisibleFlag;
			p.scaleLinesInsideFlag = this.mScaleLinesInsideFlag;
			p.scaleNumbersIntegerFlag = this.mScaleNumbersIntegerFlag;
			p.exponentFlag = this.mExponentFlag;
			p.exponentValue = this.mExponentValue;

			return p;
		}



		/**
		 * 
		 */
		private boolean setProperties( AxisIndividualProperties p )
		{

			this.mConfigurationInCube = p.configuration;
			this.mAxis.setScaleType( p.scaleType );
			this.mAxis.setRange( p.minValue, p.maxValue );
			this.mAutoCalcAxisNumberFlag = p.autoCalcAxisNumberFlag;
			this.mStepValue = p.incrementValue;
			this.mBaseTickValue = p.baseTickValue;
			this.mTitle.setString( p.titleString );
			this.mVisibleFlag = p.axisVisibleFlag;
			this.mTitleVisibleFlag = p.titleVisibleFlag;
			this.mScaleLinesVisibleFlag = p.scaleLinesVisibleFlag;
			this.mScaleNumbersVisibleFlag = p.scaleNumbersVisibleFlag;
			this.mScaleLinesInsideFlag = p.scaleLinesInsideFlag;
			this.mScaleNumbersIntegerFlag = p.scaleNumbersIntegerFlag;
			this.mExponentFlag = p.exponentFlag;
			this.mExponentValue = 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].configuration );
			if( group.setProperties( array[ii] ) == false )
			{
				return false;
			}
		}

		return true;
	}





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

		p.viewDirection = this.mViewDirection;
		p.frameLinesVisibleFlag = this.mFrameLinesVisibleFlag;
		p.frameLineWidth = this.mFrameLineWidth;
		p.frameLineColor = this.mFrameLineColor;
		p.lineColor = this.mLineColor;
		p.stringColor = this.mStringColor;
		p.axisLineWidth = this.mAxisLineWidth;
		p.scaleLineWidth = this.mScaleLineWidth;
		p.scaleLineLength = this.mScaleLineLength;
		p.fontSize = this.mTitleFontSize;
		p.fontName = this.mTitleFontName;
		p.fontStyle = this.mTitleFontStyle;

		return p;
	}



	/**
	 * 
	 */
	private boolean setCommonProperties( AxisCommonProperties p )
	{
		
		this.mViewDirection = p.viewDirection;
		this.setFrameLinesVisible( p.frameLinesVisibleFlag );
		this.setFrameLineWidth( p.frameLineWidth );
		this.setFrameLineColor( p.frameLineColor );
		this.setLineColor( p.lineColor );
		this.setStringColor( p.stringColor );
		this.setAxisLineWidth( p.axisLineWidth );
		this.setScaleLineWidth( p.scaleLineWidth );
		this.setScaleLineLength( p.scaleLineLength );
		this.setFontSize( p.fontSize );
		this.setFontName( p.fontName );
		this.setFontStyle( p.fontStyle );

		return true;
	}




	/**
	 * 
	 */
	public static class AxisProperties extends SGProperties
	{
		AxisCommonProperties cp;
		AxisIndividualProperties[] ipArray;

		AxisProperties(){}
		
		/**
		 * 
		 */
		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 scaleLineWidth;
		float scaleLineLength;
		float fontSize;
		String fontName;
		int fontStyle;



		/**
		 * 
		 */
		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.scaleLineWidth!=this.scaleLineWidth ) return false;
			if( p.scaleLineLength!=this.scaleLineLength ) 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 configuration;
		int scaleType;
		double minValue;
		double maxValue;
		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 boolean equals( final Object obj )
		{
			if( ( obj instanceof AxisIndividualProperties) == false )
			{
				return false;
			}
			
			AxisIndividualProperties p = (AxisIndividualProperties)obj;
			
			if( p.configuration!=this.configuration ) 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.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;
		}

	}


}


