/*
 * Created on 2004/07/30
 *
 * To change the template for this generated file go to
 * Window>Preferences>Java>Code Generation>Code and Comments
 */
package jp.riken.brain.ni.samuraigraph.base;

import java.math.BigDecimal;


/**
 * @author kuromaru
 *
 * To change the template for this generated type comment go to
 * Window>Preferences>Java>Code Generation>Code and Comments
 */
public class SGUtilityNumber implements SGIConstants
{

	/**
	 * 
	 * @param d
	 * @return
	 */
	public static int getOrder( final double d )
	{
		if( d < 0.0 )
		{
			throw new IllegalArgumentException("d < 0.0");
		}

		BigDecimal bd = new BigDecimal(d);
		int cnt = 0;
		int order = 0;
		if( d > 1.0 )
		{
			while( true )
			{
				if( bd.doubleValue() < 1.0 )
				{
					break;
				}
				bd = bd.movePointLeft(1);
				cnt++;
			}
			order = cnt -1;
		}
		else
		{
			while( true )
			{
				if( bd.doubleValue() >= 1.0 )
				{
					break;
				}
				bd = bd.movePointRight(1);
				cnt++;
			}
			order = - cnt;
		}

		return order;
	}



	/**
	 * 
	 * @param order
	 * @return
	 */
	public static double getPowersOfTen( final int order )
	{
		BigDecimal bd = getBigDecimalPowersOfTen(order);
		return bd.doubleValue();
	}



	/**
	 * 
	 * @param order
	 * @return
	 */
	public static BigDecimal getBigDecimalPowersOfTen( final int order )
	{
		BigDecimal bd = new BigDecimal("1.0");
		bd = bd.movePointRight( order );
		return bd;
	}




	/**
	 * 10のorder乗未満の数字を切り捨てる
	 * 例：value=8715.61, order=2　→　8700.0
	 */
	public static double truncateNumber( final double value, final int order )
	{
		return truncateNumber( new Double(value).toString(), order );
	}



	/**
	 * 
	 * @param value
	 * @param order
	 * @return
	 */
	public static double truncateNumber( final String value, final int order )
	{
		BigDecimal bd = new BigDecimal(value);
		bd = bd.movePointLeft( order );
		final int num = (int)bd.doubleValue();
		bd = new BigDecimal( num );
		bd = bd.movePointRight( order );
		return bd.doubleValue();
	}




	/**
	 * 10のorder乗の桁の数字で四捨五入する
	 * 例：value=8715.61, order=1　→　8700.0
	 * 例：value=8765.61, order=1　→　8800.0
	 */
	public static double roundOffNumber( final double value, final int order )
	{
		return roundOffNumber( Double.toString(value), order );
	}

	public static double roundOffNumber( final String value, final int order )
	{
		BigDecimal bd = new BigDecimal(value);
		bd = bd.movePointLeft(order+1);
		final double num = Math.rint( bd.doubleValue() );
		bd = new BigDecimal(num);
		bd = bd.movePointRight(order+1);
		return bd.doubleValue();
	}


	/**
	 * 10のorder乗の桁の数字で切り上げる
	 * 例：value=8715.61, order=1　→　8800.0
	 */
	public static double roundOutNumber( final double value, final int order )
	{
		return roundOutNumber( Double.toString(value), order );
	}

	public static double roundOutNumber( final String value, final int order )
	{
		BigDecimal bd = new BigDecimal(value);
		bd = bd.movePointLeft(order+1);
		final double num = Math.ceil( bd.doubleValue() );
		bd = new BigDecimal(num);
		bd = bd.movePointRight(order+1);
		return bd.doubleValue();
	}



	/**
	 * 
	 * @param x1
	 * @param y1
	 * @param x2
	 * @param y2
	 * @return
	 */
	public static boolean isOverlapping(
		final double x1, final double y1, final double x2, final double y2 )
	{
		final double value = getOverlap(x1,y1,x2,y2);
		return !(value==0.0);
	}



	/**
	 * 
	 * @param x1
	 * @param y1
	 * @param x2
	 * @param y2
	 * @return
	 */
	public static double getOverlap(
		final double x1, final double y1, final double x2, final double y2 )
	{
		final double min1 = x1<y1 ? x1 : y1 ;
		final double max1 = x1<y1 ? y1 : x1 ;
		final double min2 = x2<y2 ? x2 : y2 ;
		final double max2 = x2<y2 ? y2 : x2 ;

//System.out.println(min1+"  "+max1);
//System.out.println(min2+"  "+max2);
//System.out.println();

		if( !( min1<max2 || min2<max1 ) )
		{
			return 0.0;
		}

		double value;
		if( min1<min2 )
		{
			value = max1 - min2;
		}
		else
		{
			value = max2 - min1;
		}

		return value;
	}



	/**
	 * 
	 * @param min
	 * @param max
	 * @param value
	 * @return
	 */
	public static boolean contains(
		final double x1, final double x2, final double value )
	{
		double min;
		double max;
		if( x1<=x2 )
		{
			min = x1;
			max = x2;
		}
		else
		{
			min = x2;
			max = x1;
		}
		return ( min<=value && value<=max );
	}




	/**
	 * 
	 * @param x1
	 * @param y1
	 * @param x2
	 * @param y2
	 * @return
	 */
	public static boolean contains(
		final double x1, final double y1, final double x2, final double y2 )
	{
		final double min1 = x1<y1 ? x1 : y1 ;
		final double max1 = x1<y1 ? y1 : x1 ;
		final double min2 = x2<y2 ? x2 : y2 ;
		final double max2 = x2<y2 ? y2 : x2 ;

//System.out.println(min1+"  "+max1);
//System.out.println(min2+"  "+max2);
//System.out.println();

		final boolean flag = min1<=min2 && max2<=max1;
		return flag;
	}



	/**
	 * 
	 * @param flag
	 * @param value
	 * @param min
	 * @param max
	 * @param step
	 * @param err
	 * @return
	 */
	public static float stepValue(
		final boolean flag, final float value,
		final float min, final float max,
		final float step, final float err )
	{

		final int indexMax = (int)Math.rint(max/step);

		final int indexNearest = (int)Math.rint(value/step);
		final float valueNearest = indexNearest*step;

		int indexNew;
		if( Math.abs( value - valueNearest ) < err )
		{
			if( flag )
			{
				indexNew = indexNearest + 1;
			}
			else
			{
				indexNew = indexNearest - 1;
			}
		}
		else
		{
			if( flag )
			{
				indexNew = (int)Math.floor(value/step) + 1;
			}
			else
			{
				indexNew = (int)Math.floor(value/step);
			}
		}

		final float valueNew = indexNew*step;

		return valueNew;
	}



	/**
	 * 
	 */
	public static double getNumberInRangeOrder(
		final double value,
		final double min,
		final double max,
		final int digit )
	{
		final int order = SGUtilityNumber.getOrder( max - min )
			- digit + 1;
		BigDecimal bd = new BigDecimal( Double.toString(value) );
		bd = bd.movePointLeft(order);
		bd = bd.setScale(0,BigDecimal.ROUND_HALF_UP);
		bd = bd.movePointRight(order);
		return bd.doubleValue();
	}


}

