/*
 * 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;
import java.util.ArrayList;
import java.util.StringTokenizer;


/**
 * @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 value
	 * @param unitOld
	 * @param unitNew
	 * @return
	 */
	public static float convert(
		final float value, final String unitOld, final String unitNew )
	{
		// check
		if( unitOld==null || unitNew==null )
		{
			throw new IllegalArgumentException();
		}
		final String[] units = getUnitsArrayOfLength();
		final float[] ratioArray = {
			1.0f, 0.10f, SGIConstants.CM_POINT_RATIO, SGIConstants.CM_INCH_RATIO
		};
		int indexOld = -1;
		for( int ii=0; ii<units.length; ii++ )
		{
			if( units[ii].equals(unitOld) )
			{
				indexOld = ii;
				break;
			}
		}
		if( indexOld==-1 )
		{
			throw new IllegalArgumentException();
		}
		int indexNew = -1;
		for( int ii=0; ii<units.length; ii++ )
		{
			if( units[ii].equals(unitNew) )
			{
				indexNew = ii;
				break;
			}
		}
		if( indexNew==-1 )
		{
			throw new IllegalArgumentException();
		}

		// no needs of conversion
		if( unitOld.equals(unitNew) )
		{
			return value;
		}

		final float ratio = ratioArray[indexOld]/ratioArray[indexNew];

		return value*ratio;
	}





	/**
	 * 
	 * @param str
	 * @return
	 */
	public static String convertString( final String str, final String unit )
	{
		if( str==null )
		{
			return null;
		}
		if( str.length()==0 )
		{
			return null;
		}

		// check whether the string ends with the suffix of unit
		String[] unitsArray = getUnitsArrayOfLength();
		String suffix = null;
		for( int ii=0; ii<unitsArray.length; ii++ )
		{
			if( str.endsWith( unitsArray[ii] ) )
			{
				suffix = unitsArray[ii];
				break;
			}
		}
		if( suffix==null )
		{
			return null;
		}

		String value = removeUnit( str, suffix );
		if( value==null )
		{
			return null;
		}
		final float num = (Float.valueOf( value )).floatValue();

		//
		final float numNew = SGUtilityNumber.convert( num, suffix, unit );
		String valueNew = ( new Float(numNew) ).toString();

		return valueNew;
	}



	/**
	 * 
	 * @param str
	 * @param unit
	 * @return
	 */
	public static String removeUnit( final String str, final String unit )
	{
		if( str==null )
		{
			return null;
		}
		if( str.length()==0 )
		{
			return null;
		}
		if( unit==null )
		{
			return str;
		}

		if( str.endsWith( unit ) == false )
		{
			return str;
		}

		// create a new string without suffix
		int index = -1;
		while( true )
		{
			int num = str.indexOf(unit,index+1);
			if( num==-1 )
			{
				break;
			}
			index = num;
		}
		String sub = str.substring(0,index);
		if( sub.length()==0 )
		{
			return null;
		}


		//
		StringTokenizer st = new StringTokenizer(sub);
		ArrayList tokenList = new ArrayList();
		while( st.hasMoreTokens() )
		{
			tokenList.add( st.nextToken() );
		}
		if( tokenList.size()!=1 )
		{
			return null;
		}
		String value = (String)tokenList.get(0);
		float num = 0.0f;
		try
		{
			num = (Float.valueOf( value )).floatValue();
		}
		catch( NumberFormatException ex )
		{
			return null;
		}

		return value;
	}




	/**
	 * 
	 * @return
	 */
	public static String[] getUnitsArrayOfLength()
	{
		String[] array = { cm, mm, pt, inch };
		return array;
	}


	/**
	 * 
	 * @param unit
	 * @return
	 */
	public static boolean isLengthUnit( final String unit )
	{
		String[] array = getUnitsArrayOfLength();
		boolean flag = false;
		for( int ii=0; ii<array.length; ii++ )
		{
			if( array[ii].equals(unit) )
			{
				flag = true;
				break;
			}
		}
		return flag;
	}



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


}

