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

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.MouseEvent;
import java.awt.geom.Area;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import jp.riken.brain.ni.samuraigraph.base.SGAxis;
import jp.riken.brain.ni.samuraigraph.base.SGData;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementAxisBreak;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementAxis;
import jp.riken.brain.ni.samuraigraph.base.SGIConstants;
import jp.riken.brain.ni.samuraigraph.base.SGIDrawingElementConstants;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElement;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementGraph;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementGrid;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementLegend;
import jp.riken.brain.ni.samuraigraph.base.SGIPropertyDialogObserver;
import jp.riken.brain.ni.samuraigraph.base.SGISelectable;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementShape;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementSignificantDifference;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementString;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElementTimingLine;
import jp.riken.brain.ni.samuraigraph.base.SGProperties;
import jp.riken.brain.ni.samuraigraph.base.SGPropertyDialog;
import jp.riken.brain.ni.samuraigraph.base.SGUtilityNumber;
import jp.riken.brain.ni.samuraigraph.base.SGUtilityText;
import jp.riken.brain.ni.samuraigraph.figure.SGDrawingElementLine;
import jp.riken.brain.ni.samuraigraph.figure.SGFigureElement;
import jp.riken.brain.ni.samuraigraph.figure.SGIFigureGridConstants;
import jp.riken.brain.ni.samuraigraph.figure.SGILineConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * An object to draw grid lines.
 */
public class SGFigureElementGrid extends SGFigureElement
	implements SGIFigureElementGrid, SGILineConstants, SGIPropertyDialogObserver,
		SGIDrawingElementConstants, SGIFigureGridConstants
{

	/**
	 * An SGIAxisElement object.
	 */	
	private SGIFigureElementAxis mAxisElement;


	/**
	 * X-axis.
	 */
	private SGAxis mXAxis;


	/**
	 * Y-axis.
	 */
	private SGAxis mYAxis;


	/**
	 * The stepping value for X-axis.
	 */
	private double mStepValueX = 1.0;


	/**
	 * The baseline value for X-axis.
	 */	
	private double mBaselineValueX = 0.0;


	/**
	 * The stepping value for Y-axis.
	 */
	private double mStepValueY = 1.0;


	/**
	 * The baseline value for Y-axis.
	 */	
	private double mBaselineValueY = 0.0;


	/**
	 * Visible flag.
	 */
	private boolean mVisibleFlag;


	/**
	 * A flag whether to set location of grid lines automatically.
	 */
	private boolean mAutoRangeFlag = true;


	/**
	 * Line width.
	 */
	private float mLineWidth;


	/**
	 * Line type.
	 */
	private int mLineType;


	/**
	 * Line color.
	 */
	private Color mColor;


	/**
	 * 
	 */
	private int mCap = BasicStroke.CAP_BUTT;


	/**
	 * 
	 */
	private int mJoin = BasicStroke.JOIN_ROUND;


	/**
	 * 
	 */
	private float mMiterLimit = 1.0f;


	/**
	 * 
	 */
	private float mDashPhase = 0.0f;


	/**
	 * Set of grid lines.
	 */
	private HashSet mLineSet;



	/**
	 * 
	 */
	protected SGProperties mTemporaryProperties = null;


	
	/**
	 * Default constructor.
	 */
	public SGFigureElementGrid()
	{
		super();
		this.init();
	}


	private void init()
	{
		this.setGridVisible( DEFAULT_GRID_VISIBLE );
		this.setAutoRangeFlag( DEFAULT_GRID_AUTO_CALC );
		this.setLineWidth( DEFAULT_GRID_LINE_WIDTH, LINE_WIDTH_UNIT );
		this.setLineType( DEFAULT_GRID_LINE_TYPE );
		this.setColor( DEFAULT_GRID_COLOR );
	}


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

		this.mColor = null;
		this.mXAxis = null;
		this.mYAxis = null;
		this.mAxisElement = null;
		this.mLineSet.clear();
		this.mLineSet = null;
		this.mPressedPoint = null;
		this.mTemporaryProperties = null;
	}


	/**
	 * 
	 */
	public String toString()
	{
		return "SGGridElement";
	}


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



	/**
	 * Set the SGIAxisElement object.
	 * @param el - an SGIAxisElement object
	 */
	public void setAxisElement( SGIFigureElementAxis el )
	{
		this.mAxisElement = el;
	}


	/**
	 * 
	 */
	public boolean addData( SGData data, String name )
	{
		if( super.addData( data, name ) == false )
		{
			return false;
		}

		SGIFigureElementAxis el = this.mAxisElement;
		if( this.mXAxis==null )
		{
			this.mXAxis = el.getAxis( DEFAULT_GRID_HORIZONTAL_AXIS );
		}
		if( this.mYAxis==null )
		{
			this.mYAxis = el.getAxis( DEFAULT_GRID_PERPENDICULAR_AXIS );
		}
		this.createAll();

		return true;
	}


	/**
	 * 
	 */
	public boolean setGraphRect(
		final float x, final float y, final float width, final float height )
	{
		super.setGraphRect( x, y, width, height );
		this.createAll();
		return true;
	}



	/**
	 * 
	 */
	public void paintGraphics( Graphics g, boolean clip )
	{
		if( !this.isGridVisible() )
		{
			return;
		}

		final Graphics2D g2d = (Graphics2D)g;

		// set properties
		final float width = this.mMagnification*this.mLineWidth;
		g2d.setPaint( this.getColor() );

		// set stroke
		Stroke stroke = SGUtilityJava2D.getBasicStroke(
			this.mLineType, width, this.mCap,
			this.mJoin, this.mMiterLimit, this.mDashPhase );
		g2d.setStroke( stroke );


		// clip the rectangle
		if( clip )
		{
			SGUtilityForFigureElementJava2D.clipGraphRect(this,g2d);
		}


		// draw lines
		HashSet set = this.mLineSet;
		if( set!=null )
		{
			Iterator itr = set.iterator();
			if( clip )
			{
				while( itr.hasNext() )
				{
					Shape sh = (Shape)itr.next();
					g2d.draw(sh);
				}
			}
			else
			{
				Area clipArea = new Area( this.getGraphRect() );
				while( itr.hasNext() )
				{
					Shape sh = (Shape)itr.next();
					Area shArea = new Area( stroke.createStrokedShape(sh) );
					shArea.intersect( clipArea );
					g2d.fill(shArea);
				}
			}
		}

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

	}



	/**
	 * 
	 */
	public boolean synchronize( SGIFigureElement element, String msg )
	{

		boolean flag = true;
		if( element instanceof SGIFigureElementGraph )
		{
			
		}
		else if( element instanceof SGIFigureElementString )
		{
			
		}
		else if( element instanceof SGIFigureElementLegend )
		{
			
		}
		else if( element instanceof SGIFigureElementAxis )
		{
			this.createAll();
		}
		else if( element instanceof SGIFigureElementAxisBreak )
		{
			
		}
		else if( element instanceof SGIFigureElementSignificantDifference )
		{
			
		}
		else if( element instanceof SGIFigureElementTimingLine )
		{
			
		}
		else if( element instanceof SGIFigureElementGrid )
		{

		}
		else if( element instanceof SGIFigureElementShape )
		{

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

		return true;
	}


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


	/**
	 * Create all drawing elements.
	 *
	 */
	private void createAll()
	{
		HashSet set = new HashSet();
		if( this.isGridVisible() )
		{
			// create line objects for X and Y axes
			if( this.mXAxis!=null )
			{
				Set s = this.create( this.mXAxis, this.mBaselineValueX, true );
				set.addAll(s);
			}
			if( this.mYAxis!=null )
			{
				Set s = this.create( this.mYAxis, this.mBaselineValueY, false );
				set.addAll(s);
			}
		}
		this.mLineSet = set;
//		this.getComponent().repaint();
	}


	/**
	 * 
	 * @param axis
	 * @param baseline
	 * @param horizontal
	 * @return
	 */
	private Set create(
		SGAxis axis,
		final double baseline,
		final boolean horizontal )
	{
		final int type = axis.getScaleType();
		float[] array = null;
		if( type == SGAxis.LINEAR_SCALE )
		{
			array = this.calcLocationLinear( axis, baseline, horizontal );
		}
		else if( type == SGAxis.LOG_SCALE )
		{
			array = this.calcLocationLog( axis, baseline, horizontal );
		}
		else
		{
			throw new Error();
		}

		final int size = array.length;


		// create drawing elements
		final float gx = this.getGraphRectX();
		final float gy = this.getGraphRectY();
		final float gw = this.getGraphRectWidth();
		final float gh = this.getGraphRectHeight();
		HashSet lineSet = new HashSet();
		if( horizontal )
		{
			for( int ii=0; ii<size; ii++ )
			{
				final float x = array[ii];
				Line2D line = new Line2D.Float( x, gy, x, gy+gh );
				lineSet.add( line );
			}
		}
		else
		{
			for( int ii=0; ii<size; ii++ )
			{
				final float y = array[ii];
				Line2D line = new Line2D.Float( gx, y, gx+gw, y );
				lineSet.add( line );
			}
		}
		
		return lineSet;
	}



	/**
	 * 
	 * @param axis
	 * @param baseline
	 * @param horizontal
	 * @return
	 */
	private float[] calcLocationLinear(
		SGAxis axis,
		final double baseline,
		final boolean horizontal )
	{
		double step;
		if( this.mAutoRangeFlag )
		{
			step = this.calcStepValue( axis );
		}
		else
		{
			if( horizontal )
			{
				step = Math.abs( this.mStepValueX );
			}
			else
			{
				step = Math.abs( this.mStepValueY );
			}
		}


		final double min = axis.getMinValue();
		final double max = axis.getMaxValue();

		HashSet set = new HashSet();
		set.add( new Double(baseline) );

		double value = baseline;
		while( true )
		{
			value += step;
			set.add( new Double(value) );
			if( value>max )
			{
				break;
			}
		}

		value = baseline;
		while( true )
		{
			value -= step;
			set.add( new Double(value) );
			if( value<min )
			{
				break;
			}
		}

		final int size = set.size();
		float[] array = new float[size];
		Iterator itr = set.iterator();
		int cnt=0;
		while( itr.hasNext() )
		{
			final Double d = (Double)itr.next();
			array[cnt] = this.calcLocation( d.doubleValue(), axis, horizontal );
			cnt++;
		}

		return array;
	}



	/**
	 * 
	 * @param axis
	 * @param baseline
	 * @param horizontal
	 * @return
	 */
	private float[] calcLocationLog(
		SGAxis axis,
		final double baseline,
		final boolean horizontal )
	{
		// minimum and maximum values of axis range
		final double min = axis.getRange().x;
		final double max = axis.getRange().y;

		final int minOrder = SGUtilityNumber.getOrder( (1.0-1.0E-14)*min );
		final int maxOrder = SGUtilityNumber.getOrder(max);

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

		// array of values for scale
		double[] axisValueArray = new double[len];
		for( int ii=0; ii<len; ii++ )
		{
			final int num = ((Integer)list.get(ii)).intValue();
			axisValueArray[ii] = SGUtilityNumber.getPowersOfTen( num );
		}

		final float[] locationArray = new float[len];
		for( int ii=0; ii<len; ii++ )
		{
			locationArray[ii] = this.calcLocation( axisValueArray[ii], axis, horizontal );
		}

		return locationArray;
	}



	/**
	 * Only returns true.
	 * @param list - a list to be added the focused objects
	 */
	public boolean getFocusedObjectsList( ArrayList list )
	{
		return true;
	}


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


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

		GridProperties gp = (GridProperties)p;
		gp.mXAxis = this.mXAxis;
		gp.mYAxis = this.mYAxis;
		gp.mVisibleFlag = this.mVisibleFlag;
		gp.mBaselineValueX = this.mBaselineValueX;
		gp.mBaselineValueY = this.mBaselineValueY;
		gp.mStepValueX = this.mStepValueX;
		gp.mStepValueY = this.mStepValueY;
		gp.mAutoRangeFlag = this.mAutoRangeFlag;
		gp.mLineWidth = this.mLineWidth;
		gp.mLineType = this.mLineType;
		gp.mColor = this.mColor;
			
		return true;
	}


	/**
	 * 
	 */
	public boolean setProperties(SGProperties p)
	{
		if( ( p instanceof GridProperties ) == false ) return false;

		GridProperties gp = (GridProperties)p;
		this.mXAxis = gp.mXAxis;
		this.mYAxis = gp.mYAxis;
		this.mVisibleFlag = gp.mVisibleFlag;
		this.mBaselineValueX = gp.mBaselineValueX;
		this.mBaselineValueY = gp.mBaselineValueY;
		this.mStepValueX = gp.mStepValueX;
		this.mStepValueY= gp.mStepValueY;
		this.mAutoRangeFlag = gp.mAutoRangeFlag;
		this.mLineWidth = gp.mLineWidth;
		this.mLineType = gp.mLineType;
		this.mColor = gp.mColor;
		return true;
	}


	/**
	 * Only returns true.
	 * @param s - a selectable object to be hidden
	 */
	public boolean hideSelectedObject( SGISelectable s )
	{
		return true;
	}


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


	/**
	 * 
	 */
	public boolean writeProperty(Element el)
	{
		el.setAttribute( KEY_GRID_VISIBLE, Boolean.toString( this.mVisibleFlag ) );
		el.setAttribute( KEY_X_AXIS_POSITION, this.mAxisElement.getLocationName( this.mXAxis ) );
		el.setAttribute( KEY_Y_AXIS_POSITION, this.mAxisElement.getLocationName( this.mYAxis ) );
		el.setAttribute( KEY_AUTO_CALC, Boolean.toString( this.mAutoRangeFlag ) );
		el.setAttribute( KEY_STEP_VALUE_X, Double.toString( this.mStepValueX ) );
		el.setAttribute( KEY_BASELINE_VALUE_X, Double.toString( this.mBaselineValueX ) );
		el.setAttribute( KEY_STEP_VALUE_Y, Double.toString( this.mStepValueY ) );
		el.setAttribute( KEY_BASELINE_VALUE_Y, Double.toString( this.mBaselineValueY ) );
		el.setAttribute( KEY_LINE_WIDTH, Float.toString( this.mLineWidth ) + SGIConstants.pt );
		el.setAttribute( KEY_LINE_TYPE, SGDrawingElementLine.getLineTypeName( this.mLineType ) );
		el.setAttribute( KEY_GRID_COLOR, SGUtilityText.getColorString( this.mColor ) );

		return true;
	}


	/**
	 * 
	 * @param e
	 */
	public boolean onMouseClicked( MouseEvent e )
	{
		return false;
	}


	/**
	 * 
	 * @param e
	 */
	public boolean onMousePressed( MouseEvent e )
	{
		return false;
	}


	/**
	 * 
	 * @param e
	 */
	public boolean onMouseDragged( MouseEvent e )
	{
		return true;
	}



	/**
	 * 
	 * @param e
	 */
	public boolean onMouseReleased( MouseEvent e )
	{
		return true;
	}



	/**
	 * 
	 */
	public boolean onDrawingElement(int x, int y)
	{
		return false;
	}


	/**
	 * 
	 */
	public Element createElement(Document document)
	{
		Element el = this.createThisElement( document );
		if( el==null )
		{
			return null;
		}

		return el;
	}



	/**
	 * 
	 */
	public boolean readProperty( Element el )
	{
		String str = null;
		Number num = null;
		Color cl = null;
		Boolean b = null;

		
		// grid visible
		str = el.getAttribute( SGIFigureElementGrid.KEY_GRID_VISIBLE );
		if( str.length()!=0 )
		{
			b = SGUtilityText.getBoolean(str);
			if( b==null )
			{
				return false;
			}
			final boolean gridVisible = b.booleanValue();
			if( this.setGridVisible( gridVisible ) == false )
			{
				return false;
			}
		}

		
		// set axes
		str = el.getAttribute( KEY_X_AXIS_POSITION );
		if( str.length()!=0 )
		{
			SGAxis xAxis = this.mAxisElement.getAxis(str);
			if( xAxis==null )
			{
				return false;
			}
			if( this.setXAxis( xAxis ) == false )
			{
				return false;
			}
		}

		str = el.getAttribute( KEY_Y_AXIS_POSITION );
		if( str.length()!=0 )
		{
			SGAxis yAxis = this.mAxisElement.getAxis(str);
			if( yAxis==null )
			{
				return false;
			}
			if( this.setYAxis( yAxis ) == false )
			{
				return false;
			}
		}


		// auto calc
		str = el.getAttribute( SGIFigureElementGrid.KEY_AUTO_CALC );
		if( str.length()!=0 )
		{
			b = SGUtilityText.getBoolean(str);
			if( b==null )
			{
				return false;
			}
			final boolean autoCalc = b.booleanValue();
			if( this.setAutoRangeFlag( autoCalc ) == false )
			{
				return false;
			}
		}


		// for x-axis
		str = el.getAttribute( KEY_BASELINE_VALUE_X );
		if( str.length()!=0 )
		{
			num = SGUtilityText.getDouble(str);
			if( num==null )
			{
				return false;
			}
			final double baselineValueX = num.doubleValue();
			if( this.setBaselineValueX( baselineValueX ) == false )
			{
				return false;
			}
		}

		str = el.getAttribute( KEY_STEP_VALUE_X );
		if( str.length()!=0 )
		{
			num = SGUtilityText.getDouble(str);
			if( num==null )
			{
				return false;
			}
			final double stepValueX = num.doubleValue();
			if( this.setStepValueX( stepValueX ) == false )
			{
				return false;
			}
		}


		// for y-axis
		str = el.getAttribute( KEY_BASELINE_VALUE_Y );
		if( str.length()!=0 )
		{
			num = SGUtilityText.getDouble(str);
			if( num==null )
			{
				return false;
			}
			final double baselineValueY = num.doubleValue();
			if( this.setBaselineValueY( baselineValueY ) == false )
			{
				return false;
			}
		}

		str = el.getAttribute( KEY_STEP_VALUE_Y );
		if( str.length()!=0 )
		{
			num = SGUtilityText.getDouble(str);
			if( num==null )
			{
				return false;
			}
			final double stepValueY = num.doubleValue();
			if( this.setStepValueY( stepValueY ) == false )
			{
				return false;
			}
		}


		// line width
		str = el.getAttribute( KEY_LINE_WIDTH );
		if( str!=null )
		{
			StringBuffer uLineWidth = new StringBuffer();
			num = SGUtilityText.getNumber( str, uLineWidth );
			if( num==null )
			{
				return false;
			}
			final float lineWidth = num.floatValue();
			if( this.setLineWidth( lineWidth, uLineWidth.toString() ) == false )
			{
				return false;
			}
		}


		// line type
		str = el.getAttribute( KEY_LINE_TYPE );
		if( str!=null )
		{
			num = SGDrawingElementLine.getLineTypeFromName(str);
			if( num==null )
			{
				return false;
			}
			final int lineType = num.intValue();
			if( this.setLineType( lineType ) == false )
			{
				return false;
			}
		}


		// grid color
		str = el.getAttribute( KEY_GRID_COLOR );
		if( str.length()!=0 )
		{
			cl = SGUtilityText.getColorFromString(str);
			if( cl==null )
			{
				return false;
			}
			final Color gridColor = cl;
			if( this.setColor( gridColor ) == false )
			{
				return false;
			}
		}

		return true;
	}


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


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


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



	/**
	 * 
	 */
	public boolean commit()
	{
		SGProperties pTemp = this.mTemporaryProperties;
		SGProperties pPresent = this.getProperties();
		if( pTemp.equals(pPresent) == false )
		{
			this.setChanged( true );
		}
		this.mTemporaryProperties = null;
		this.createAll();
		this.notifyChange();

		return true;
	}


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

		return true;
	}



	/**
	 * 
	 */
	public boolean preview()
	{
		this.createAll();
		this.notifyChange();

		return true;
	}



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


	/**
	 * 
	 */
	public SGPropertyDialog getPropertyDialog()
	{
		return null;
	}


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




	/**
	 * 
	 */
	public boolean setMementoBackward()
	{
		if( !super.setMementoBackward() )
		{
			return false;
		}
		this.createAll();
		this.notifyChangeOnUndo();
		return true;
	}




	/**
	 * 
	 */
	public boolean setMementoForward()
	{
		if( !super.setMementoForward() )
		{
			return false;
		}
		this.createAll();
		this.notifyChangeOnUndo();
		return true;
	}



	/**
	 * Returns the baseline value for x-axis.
	 * @return baseline value
	 */
	public double getBaselineValueX()
	{
		return this.mBaselineValueX;
	}


	/**
	 * Returns the baseline value for y-axis.
	 * @return baseline value
	 */
	public double getBaselineValueY()
	{
		return this.mBaselineValueY;
	}


	/**
	 * Returns the color of grid.
	 * @return color of grid
	 */
	public Color getColor()
	{
		return this.mColor;
	}


	/**
	 * Returns the line type.
	 * @return line type
	 */
	public int getLineType()
	{
		return this.mLineType;
	}


	/**
	 * Returns the line width.
	 * @return line width
	 */
	public float getLineWidth()
	{
		return this.mLineWidth;
	}

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


	/**
	 * Returns the step value for x-axis.
	 * @return step value
	 */
	public double getStepValueX()
	{
		return this.mStepValueX;
	}


	/**
	 * Returns the step value for y-axis.
	 * @return step value
	 */
	public double getStepValueY()
	{
		return this.mStepValueY;
	}


	/**
	 * 
	 * @param axis
	 */
	public boolean setXAxis( final SGAxis axis )
	{
		this.mXAxis = axis;
		this.createAll();
		return true;
	}


	/**
	 * 
	 * @param axis
	 */
	public boolean setYAxis( final SGAxis axis )
	{
		this.mYAxis = axis;
		this.createAll();
		return true;
	}


	/**
	 * Returns the x-axis.
	 * @return x-axis
	 */
	public SGAxis getXAxis()
	{
		return this.mXAxis;
	}


	/**
	 * Returns the y-axis.
	 * @return y-axis
	 */
	public SGAxis getYAxis()
	{
		return this.mYAxis;
	}


	/**
	 * Set the baseline value for x-axis.
	 * @param d - baseline value
	 */
	public boolean setBaselineValueX( final double d )
	{
		this.mBaselineValueX = d;
		this.createAll();
		return true;
	}


	/**
	 * Set the baseline value for y-axis.
	 * @param d - baseline value
	 */
	public boolean setBaselineValueY( final double d )
	{
		this.mBaselineValueY = d;
		this.createAll();
		return true;
	}


	/**
	 * @param color
	 */
	public boolean setColor(Color color)
	{
		this.mColor = color;
		return true;
	}


	/**
	 * Set the line type
	 * @param i - line type
	 */
	public boolean setLineType( final int i )
	{
		if( SGDrawingElementLine.isValidLineType(i) == false )
		{
			return false;
		}
		this.mLineType = i;
		return true;
	}


	/**
	 * Set the line width.
	 * @param f - line width
	 */
	public boolean setLineWidth( final float f )
	{
		this.mLineWidth = f;
		return true;
	}

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

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


	/**
	 * Set the step value of x-axis.
	 * @param d - value
	 */
	public boolean setStepValueX( final double d )
	{
		if( d==0.0 )
		{
			return false;
		}
		this.mStepValueX = d;
		this.createAll();
		return true;
	}


	/**
	 * Set the step value of y-axis.
	 * @param d - value
	 */
	public boolean setStepValueY( final double d )
	{
		if( d==0.0 )
		{
			return false;
		}
		this.mStepValueY = d;
		this.createAll();
		return true;
	}


	/**
	 * Returns whether the grid is visible.
	 * @return visible flag
	 */
	public boolean isGridVisible()
	{
		return this.mVisibleFlag;
	}


	/**
	 * Set visible the grid.
	 * @param b visible flag
	 */
	public boolean setGridVisible( final boolean b )
	{
		this.mVisibleFlag = b;
		this.createAll();
		return true;
	}


	/**
	 * Returns the flag whether to set range of lines automatically.
	 * @return auto-range flag
	 */
	public boolean isAutoRange()
	{
		return this.mAutoRangeFlag;
	}


	/**
	 * Set whether to set range of lines automatically.
	 * @param b auto-range flag
	 */
	public boolean setAutoRangeFlag( final boolean b )
	{
		this.mAutoRangeFlag = b;
		return true;
	}


	/**
	 * 
	 */
	public int getXAxisLocation()
	{
		return this.mAxisElement.getLocationInPlane( this.mXAxis );
	}


	/**
	 * 
	 */
	public int getYAxisLocation()
	{
		return this.mAxisElement.getLocationInPlane( this.mYAxis );
	}


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

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

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



	/**
	 * 
	 * @param step
	 * @return
	 */
	public boolean hasValidStepXValue( final Number step )
	{
		final double v = step!=null ? step.doubleValue() : this.getStepValueX();
		if( v==0.0 )
		{
			return false;
		}
		return true;
	}


	/**
	 * 
	 * @param step
	 * @return
	 */
	public boolean hasValidStepYValue( final Number step )
	{
		final double v = step!=null ? step.doubleValue() : this.getStepValueY();
		if( v==0.0 )
		{
			return false;
		}
		return true;
	}


	/**
	 * Properties for grid.
	 */
	public static class GridProperties extends SGProperties
	{
		private SGAxis mXAxis;
		private SGAxis mYAxis;
		private double mStepValueX;
		private double mBaselineValueX;
		private double mStepValueY;
		private double mBaselineValueY;
		private boolean mVisibleFlag;
		private boolean mAutoRangeFlag;
		private float mLineWidth;
		private int mLineType;
		private Color mColor;

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

		public void dispose()
		{
			this.mXAxis = null;
			this.mYAxis = null;
			this.mColor = null;
		}

		/**
		 * 
		 */
		public boolean equals( Object obj )
		{
			if( ( obj instanceof GridProperties ) == false ) return false;
			
			GridProperties p = (GridProperties)obj;

			if( this.mXAxis.equals(p.mXAxis) == false ) return false;
			if( this.mYAxis.equals(p.mYAxis) == false ) return false;
			if( this.mBaselineValueX!=p.mBaselineValueX ) return false;
			if( this.mStepValueX!=p.mStepValueX ) return false;
			if( this.mBaselineValueY!=p.mBaselineValueY ) return false;
			if( this.mStepValueY!=p.mStepValueY ) return false;
			if( this.mVisibleFlag!=p.mVisibleFlag ) return false;
			if( this.mAutoRangeFlag!=p.mAutoRangeFlag ) return false;
			if( this.mLineWidth!=p.mLineWidth ) return false;
			if( this.mLineType!=p.mLineType ) return false;
			if( this.mColor.equals(p.mColor) == false ) return false;
			
			return true;
		}

	}


}

