
package jp.riken.brain.ni.samuraigraph.base;


/**
 * The axis with the range and the scale type.
 */
public class SGAxis
{

	/**
	 * A constant for the linear scale.
	 */
	public static final int LINEAR_SCALE = 0;


	/**
	 * A constant for the log scale.
	 */
	public static final int LOG_SCALE = 1;


	// The type of scale.
	private int mScaleType = LINEAR_SCALE;


	// The minimum value.
	private double mMinValue;


	// The maximum value.
	private double mMaxValue;


	/**
	 * Creates an axis object with the given minimum and maximum value.
	 * The scale is linear type by default.
	 * The minValue must be smaller than maxValue.
	 * @param minValue - the minumum value
	 * @param maxValue - the maximum value
	 */
	public SGAxis( final double minValue, final double maxValue )
	{
		this( minValue, maxValue, LINEAR_SCALE );
	}


	/**
	 * Creates an axis object with the given minimum and maximum value.
	 * The scale is linear type by default.
	 * The minValue must be smaller than maxValue.
	 * @param minValue - the minumum value
	 * @param maxValue - the maximum value
	 * @param type - scale type
	 */
	public SGAxis( final double minValue, final double maxValue, final int type )
	{
		super();
		this.setRange( minValue, maxValue );
		this.setScaleType( type );
	}


	/**
	 * Creates an axis object with the given range.
	 * The scale is linear type by default.
	 * @param range - range of the axis
	 */
	public SGAxis( final SGTuple2d range )
	{
		this( range, LINEAR_SCALE );
	}


	/**
	 * Creates an axis object with the given range.
	 * @param range - range of the axis
	 * @param type - scale type
	 */
	public SGAxis( final SGTuple2d range, final int type )
	{
		super();
		this.setRange(range);
		this.setScaleType(type);
	}


	/**
	 * Set the axis range.
	 * @param minValue - the minumum value
	 * @param maxValue - the maximum value
	 * @throws IllegalArgumentException
	 * @return
	 */
	public boolean setRange(
		final double minValue, final double maxValue )
	{
		if( minValue>=maxValue )
		{
			new IllegalArgumentException("minValue>=maxValue");
		}

		// nonpositive value is not accepted in the log scale
		if( this.getScaleType()==LOG_SCALE && minValue<=0.0 )
		{
			new IllegalArgumentException(
				"this.getScaleType()==LOG_SCALE && minValue<=0.0");
		}

		// set to the attribute
		this.mMinValue = minValue;
		this.mMaxValue = maxValue;

		return true;
	}


	/**
	 * Set the axis range.
	 * @param range - axis range
	 * @throws NullPointerException
	 */
	public boolean setRange( final SGTuple2d range )
	{
		if( range==null )
		{
			throw new NullPointerException("range==null");
		}
		return this.setRange( range.x, range.y );
	}


	/**
	 * Set the scale type.
	 * @param scaleType - The scale type.
	 * @throws IllegalArgumentException - 
	 * @return true:succeeded, false:failed
	 */
	public boolean setScaleType( final int scaleType )
	{
		// for the wrong input value
		if( scaleType!=LINEAR_SCALE && scaleType!=LOG_SCALE )
		{
			new IllegalArgumentException(
				"scaleType!=LINEAR_SCALE && scaleType!=LOG_SCALE");
		}

		// nonpositive value is not accepted in the log scale
		if( scaleType==LOG_SCALE && this.getMinValue()<=0.0 )
		{
			new IllegalArgumentException(
				"scaleType==LOG_SCALE && this.getMinValue()<=0.0");
		}

		// set to attribute
		this.mScaleType = scaleType;

		return true;
	}


	/**
	 * Returns the minimum value.
	 * @return the minimum value of this axis.
	 */
	public double getMinValue()
	{
		return this.mMinValue;
	}
	
	
	/**
	 * Returns the maximum value.
	 * @return the maximum value of this axis.
	 */
	public double getMaxValue()
	{
		return this.mMaxValue;
	}


	/**
	 * Returns the range.
	 * @return the range of this axis.
	 */
	public SGTuple2d getRange()
	{
		return new SGTuple2d( this.mMinValue, this.mMaxValue );
	}


	/**
	 * Returns the scale type.
	 * @return the scale type of this axis.
	 */
	public int getScaleType()
	{
		return this.mScaleType;
	}


	/**
	 * Returns whether the given value is inside the range.
	 * @param value - the value to be checked
	 * @return whether the given value is inside the range.
	 */
	public boolean insideRange( final double value )
	{
		return ( this.mMinValue<=value && value<=this.mMaxValue );
	}


	/**
	 * Returns whether the given value is "valid" in the present axis.
	 * @param value - the value to be checked
	 * @return whether the given value is "valid" in the present axis.
	 */
	public boolean isValidValue( final double value )
	{
		final int type = this.getScaleType();

		// negative value is "invalid" in the log scale
		if( type==SGAxis.LOG_SCALE )
		{
			if( value<=0.0 )
			{
				return false;
			}
		}

		return true;
	}

}

