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

import java.awt.Color;
import java.awt.Font;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.StringTokenizer;

import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;


/**
 * 
 */
public class SGUtilityText implements SGIConstants
{
	
	/**
	 * Array of default available date format.
	 */
	public static final String[] DEFAULT_DATE_FORMAT_ARRAY = {
		"yy/MM/dd",
		"yy.MM.dd",
		"yy-MM-dd",
		"yyyyMMdd",
		"yyMMdd",
		"yy MM dd",
		"yyyy MM dd"
	};


//	public static final DateFormat[] DEFAULT_DATE_FORMAT_ARRAY = {
//		DateFormat.getDateInstance( DateFormat.SHORT ),
//		new SimpleDateFormat("yy.MM.dd"),
//		new SimpleDateFormat("yy-MM-dd"),
//		new SimpleDateFormat("yyyyMMdd"),
//		new SimpleDateFormat("yyMMdd"),
//		new SimpleDateFormat("yy MM dd"),
//		new SimpleDateFormat("yyyy MM dd")
//	};


	// list of date format
	private static final ArrayList DATE_FORMAT_ARRAY_LIST = new ArrayList();



	/**
	 * 
	 * @param args
	 */
	public static void main(String[] args) throws Exception
	{
System.out.println("<< start >>");

/*
		String[] strArray = {
			"2005/05/01",
			"05/05/01",
			"05/5/1",
			"2005.05.01",
			"05.05.01",
			"05.5.1",
			"2005-05-01",
			"2005-5-1",
			"05-05-01",
			"05-5-1",
			"20050501",
			"050501",
			"2005 05 01",
			"05 05 01"
		};

		for( int ii=0; ii<strArray.length; ii++ )
		{
			System.out.println( SGUtilityText.getDate( strArray[ii] ) + "  " + strArray[ii] );
		}
*/


/*
Locale[] array = {
	Locale.US, Locale.GERMANY, Locale.FRANCE, Locale.JAPAN, Locale.CHINESE, Locale.ITALIAN };
for( int ii=0; ii<array.length; ii++ )
{
	Locale currentLocale = array[ii];
	SimpleDateFormat formatter
		= new SimpleDateFormat( "yyyy MMMM dd EEEE", currentLocale );
	Date today = new Date();
	String result = formatter.format( today );
	System.out.println( "Locale: " + currentLocale.toString() );
	System.out.println( "Result: " + result );
	System.out.println();
}
*/

/*
		char[] cArray = {
			'a', 'b', 'c', '\\', '"', '\t', 'd', 'e', 'f', ' ',
			'"', 'g', 'h', 'i', ' ', 'j', 'k', 'l', 'あ',
			' ', 'm', 'n', ' ', '"', 'o', 'p', 'q', ' ',
			'"', 'r', 's', 't', ' ', '"', 'u', '\f', 'v', 'w', '　', 'x'
		};
*/

/*
		char[] cArray = {
			'a', 'b', 'c', '"', 'd', 'e', 'f', ' ', 'g', 'h', 'i', '"'
		};
*/



/*
//		String str = "0.0   0.0    -1.0   1.0   \"a\"";
//		String str = "0.0  0.0\r1.0  1.0\n2.0  0.5\r\n3.0  2.0\r\n\r\n4.0  4.0";
//		String str = new String(cArray);
//System.out.println(str);
//System.out.println();

		StringReader sr = new StringReader(str);
		final BufferedReader br = new BufferedReader(sr);
System.out.println("*****");
		String line = null;
		while( (line=SGUtilityText.readLine(br))!=null )
		{
			System.out.println(line);
		}
System.out.println("*****");
System.out.println();
*/


/*
		ArrayList strList = new ArrayList();
		SGUtilityText.tokenize(str,strList);

System.out.println();
for( int ii=0; ii<strList.size(); ii++ )
{
	String s = (String)strList.get(ii);
//	System.out.println(ii+" *"+s+"*");
}
System.out.println(strList);
*/


/*
String str = "G^{(0)}_n(x_i,y_j) = x_i^{n-1}+y_j^n-1";

		ArrayList charList = new ArrayList();
		ArrayList superList = new ArrayList();
		ArrayList subList = new ArrayList();
		SGUtilityText.getSubscriptAndSuperscriptInfo(str,charList,superList,subList);

		if( charList.size() != superList.size() )
		{
			throw new Error();
		}
		if( superList.size()!=subList.size() )
		{
			throw new Error();
		}

System.out.println();
System.out.println(str);
System.out.println();
for( int ii=0; ii<charList.size(); ii++ )
{
	System.out.println(ii+"  "+charList.get(ii)+"  "+superList.get(ii)+"  "+subList.get(ii) );
}
System.out.println();
*/

/*
		String str = "+.40e03";
		Number num = SGUtilityText.getDouble(str);
		System.out.println(num);
*/


/*
		String str = "aaa 345 \"\" bbb ccc";
		ArrayList strList = new ArrayList();
		SGUtilityText.tokenize(str,strList);
System.out.println(strList);
*/

/*
		String str = "1.0 pt";
		String s = removeUnit( str, str );
		System.out.println("*"+s+"*");
*/


	}



	/**
	 * 
	 */
	public static String getSuperscriptString( final String a, final String b )
	{
		String str = a + "^{" + b + "}";
		return str;
	}



	/**
	 * 
	 */
	public static String getSubscriptString( final String a, final String b )
	{
		String str = a + "_{" + b + "}";
		return str;
	}



	/**
	 * 
	 * @param line			A line.
	 * @param charList		List of the characters.
	 * @param superList	List of superscript strings.
	 * @param subList		List of subscript strings.
	 * @return
	 */
	public static boolean getSubscriptAndSuperscriptInfo(
		final String line,
		final ArrayList charList,
		final ArrayList superList,
		final ArrayList subList )
	{

		if( line==null || charList==null || superList==null || subList==null )
		{
			return false;
		}
		if( line.length()==0 )
		{
			return true;
		}

		// mode flag
		boolean ssModeFlag = false;
		boolean stringModeFlag = false;

		// working variables
		char c;
		int cnt = 0;
		Boolean bTemp = null;
		ArrayList list = new ArrayList();

//System.out.println("length="+line.length());

		// read the input line
		while( true )
		{

			// get a character
			c = line.charAt(cnt);
//System.out.println(cnt+"  "+c);

			// outer the mode
			if( !ssModeFlag )
			{

				if( c=='^' || c=='_' )
				{

					// set the mode flag
					ssModeFlag = true;

					// if a caret or an underbar is located at the start of the line,
					// return false
					if( cnt==0 )
					{
						return false;
					}

					// set the value to the temporary variable
					if( c=='^' )
					{
						bTemp = new Boolean(true);
					}
					else if( c=='_' )
					{
						bTemp = new Boolean(false);
					}

				}
				else
				{
					charList.add( new Character(c) );
					superList.add( null );
					subList.add( null );
				}
				
			}
			// inner the mode
			else
			{

				// in the string mode
				if( stringModeFlag )
				{

					if( c == '}' )
					{
						stringModeFlag = false;

						String str = SGUtilityText.createString(list);

						if( bTemp.booleanValue() )
						{
							Object obj = superList.remove(superList.size()-1);
							if( obj != null )
							{
								String str_ = (String)obj;
								str = str_ + str;
							}
							superList.add(str);
						}
						else
						{
							Object obj = subList.remove(subList.size()-1);
							if( obj != null )
							{
								String str_ = (String)obj;
								str = str_ + str;
							}
							subList.add(str);
						}

						// break the mode
						ssModeFlag = false;

						// clear a temporary variable
						bTemp = null;

						list.clear();

					}
					else
					{
						list.add( new Character(c) );
					}
					
				}
				// outer the string mode
				else
				{

					if( c == '{' )
					{
						stringModeFlag = true;
					}
					else
					{
						ArrayList list_ = new ArrayList();
						list_.add( new Character(c) );
						String str = SGUtilityText.createString(list_);


						if( bTemp.booleanValue() )
						{
							Object obj = superList.remove(superList.size()-1);
							if( obj != null )
							{
								String str_ = (String)obj;
								str = str_ + str;
							}
							superList.add(str);
						}
						else
						{
							Object obj = subList.remove(subList.size()-1);
							if( obj != null )
							{
								String str_ = (String)obj;
								str = str_ + str;
							}
							subList.add(str);
						}

						// break the mode
						ssModeFlag = false;

						// clear a temporary variable
						bTemp = null;
					}
					
				}

				
			}


			// increment the counter
			cnt++;


			// break at the end of the line
			if( cnt == line.length() )
			{
				if( ssModeFlag )
				{
					return false;
				}

				break;
			}

		}


		return true;
	}






	/**
	 * 区切り文字(半角空白文字' '、タブ文字'\t'、改行文字'\n'、復帰改行文字'\r'、および
	 * 用紙送り文字'\f')で区切られた文字列を分割する。
	 * また、二つの連続するダブルクォーテーションマーク('"')で挟まれた領域は一つの文字列と
	 * みなし、その中に存在する区切り文字は区切り文字とは解釈せずに、文字列の一部とみなす。
	 * 尚、ダブルクォーテーションマークは区切り文字として解釈される。
	 * 文字列中にダブルクォーテーションマークを含めたい場合には、直前にバックスラッシュ('\\')を
	 * 付加して \" とする。
	 * バックスラッシュが文字列中に単独で存在する場合には無視される。
	 */
	public static boolean tokenize(
		final String str,
		final ArrayList strList )
	{

		if( str==null | strList==null )
		{
			throw new IllegalArgumentException("str==null | strList==null");
		}

		if( str.length()==0 )
		{
			return true;
		}


		// get characters array
		final char[] charArray = str.toCharArray();


		// '"'
		boolean dqModeFlag = false;
		
		// '\\'
		boolean bsModeFlag = false;


		//
		ArrayList delimiterSet = new ArrayList();
		for( int ii=0; ii<SGIConstants.DELIMITER_SET.length; ii++ )
		{
			delimiterSet.add( new Character( SGIConstants.DELIMITER_SET[ii] ) );
		}


		//
		int cnt = 0;
		final ArrayList charList = new ArrayList();	// list for temporary use
		while( true )
		{

			// get a character that the counter indicates
			final char c = str.charAt(cnt);
//System.out.print(cnt+"  "+new Character(c)+"  ");


			// double quotation mark
			if( c=='"' )
			{
//System.out.print("*** dq ***");
//System.out.println("  "+dqModeFlag);

				if( bsModeFlag )
				{
					charList.add( new Character(c) );
					bsModeFlag = false;
				}
				else
				{

					if( charList.size() != 0 )
					{
						final String str_ = createString(charList);
						strList.add(str_);
						charList.clear();
					}
					else
					{
						// to accept quoted zero-length string
						if( dqModeFlag )
						{
							strList.add("");
							charList.clear();
						}
					}

					// reverse the flag of double quotation mode
					dqModeFlag = !dqModeFlag;
				}
			
			}
			// back slash
			else if( c=='\\' )
			{
//System.out.print("*** \\ ***");
//System.out.println("  "+dqModeFlag);

				bsModeFlag = true;

			}
			// the delimiter set
			else if( delimiterSet.contains( new Character(c) ) )
			{
//System.out.print("*** delimiter ***");
//System.out.println("  "+dqModeFlag);

				if( dqModeFlag )
				{
//System.out.println("aaaaa");
					charList.add( new Character(c) );
				}
				else
				{
					if( charList.size() != 0 )
					{
						final String str_ = createString(charList);
						strList.add(str_);
//System.out.println("*"+str_+"*");
						charList.clear();
					}
				}

				bsModeFlag = false;

			}
			// other characters
			else
			{
//System.out.print("*** others ***");
//System.out.println("  "+dqModeFlag);

				// dqMode
				charList.add( new Character(c) );

				bsModeFlag = false;
			}


			// increment the counter
			cnt++;


			// at the end of the input string
			if( cnt == str.length() )
			{
				if( dqModeFlag )
				{
//System.out.println("文体が不正です！");
					return false;
				}


				final String str_ = createString(charList);
				if( str_==null || str_.length()==0 )
				{
					break;
				}

				strList.add(str_);
				charList.clear();

				break;

			}

		}



		return true;

	}


	/**
	 * 
	 * @param charList
	 * @return
	 */
	public static String createString( final ArrayList charList )
	{
		final char[] cArray = new char[charList.size()];
		for( int ii=0; ii<cArray.length; ii++ )
		{
			cArray[ii] = ((Character)charList.get(ii)).charValue();
		}
		final String str = new String(cArray);
		return str;
	}



	/**
	 * 長さが0で無い文字列を取得する
	 */
	public static String readLine( final BufferedReader br )
	{
		String line = null;
		try
		{
			while( true )
			{
				line = br.readLine();
				if( line == null )
				{
					return null;
				}

				if( line.length()!=0 )
				{
					break;
				}
			}
		}
		catch( Exception ex )
		{
			return null;
		}

		return line;
	}



	/**
	 * "{(r1,g1,b1,a1),(r2,g2,b2,a2),...}"の形で色リストの文字列を作成する
	 */
	public static String getColorListString( final ArrayList colorList )
	{
		String str = "{";

		for( int ii=0; ii<colorList.size(); ii++ )
		{
			final Color color = (Color)colorList.get(ii);
			final String strColor = SGUtilityText.getColorString(color);
			str += strColor;
			if( ii!=colorList.size()-1 )
			{
				str += ',';
			}
			else
			{
				str += "}";
			}
		}
		
		return str;
	}



	/**
	 * "key={(r1,g1,b1,a1),(r2,g2,b2,a2),...}"の形で色リストの情報を書き出す
	 */
	public static boolean writeColorListPropertyLine(
		final Writer writer, final String key, final ArrayList colorList )
		throws IOException
	{
		writer.write( key + "=" );
		String str = getColorListString( colorList );
		writer.write( str + "\n" );
		return true;
	}



	/**
	 * 引数で渡された文字列の最初の方から文字startを、最後の方から文字endを検索し、
	 * 最初に見つかった文字で挟まれた領域の文字列を返す
	 */
	public static String getInnerString( String str, int sChar, int eChar )
	{
		if( str==null )
		{
			return null;
		}

		if( str.length() < 2 )
		{
			return null;
		}

		int start = str.indexOf(sChar) +1;
		int end = str.lastIndexOf(eChar);
		if( end <= start )
		{
			return null;
		}

		String sub = str.substring( start, end );

		return sub;

	}





	/**
	 * 引数で渡された"(r,g,b,a)"のフォーマットの色情報の文字列から色を作成して返す
	 */
	public static Color getColorFromString( final String str )
	{

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

		String sub = SGUtilityText.getInnerString( str, '(', ')' );

		StringTokenizer st = new StringTokenizer( sub, "," );
		ArrayList strList = new ArrayList();
		while( st.hasMoreTokens() )
		{
			strList.add( st.nextToken() );
		}

		if( strList.size()!=4 )
		{
			return null;
		}


		int[] array = new int[strList.size()];

		try
		{
			for( int ii=0; ii<strList.size(); ii++ )
			{
				String sNum = (String)strList.get(ii);
				int num = Integer.valueOf( sNum ).intValue();
				if( num<0 || num>255 )
				{
					return null;
				}
				array[ii] = num;
			}
		}
		catch( Exception ex )
		{
			ex.printStackTrace();
		}


		Color color = new Color( array[0], array[1], array[2], array[3] );

		return color;
	}



	/**
	 * 引数で渡された色から"(r,g,b,a)"のフォーマットで色情報の文字列を作成して返す
	 */
	public static String getColorString( final Color color )
	{

		final String strColor = new String( "("
			+ color.getRed() +","
			+ color.getGreen() +","
			+ color.getBlue() +","
			+ color.getAlpha() +")"
		);

		
		return strColor;
	}



	/**
	 * 
	 * @param value
	 * @return
	 */
	public static Boolean getBoolean( final String value )
	{
		if( value==null )
		{
			return null;
		}

		Boolean b = null;
		if( Boolean.TRUE.toString().equals(value) )
		{
			b = Boolean.TRUE;
		}
		else if( Boolean.FALSE.toString().equals(value) )
		{
			b = Boolean.FALSE;
		}
		else
		{
			return null;
		}

		return b;
	}


	/**
	 * 
	 */
	public static Integer getInteger( final String value )
	{
		Number num = parse(value);
		if( num==null )
		{
			return null;
		}
		return new Integer( num.intValue() );
	}


	/**
	 * 
	 */
	public static Float getFloat( final String value )
	{
		Number num = parse(value);
		if( num==null )
		{
			return null;
		}
		return new Float( num.floatValue() );
	}


	/**
	 * 
	 */
	public static Double getDouble( final String value )
	{
		Number num = parse(value);
		if( num==null )
		{
			return null;
		}
		return new Double( num.doubleValue() );
	}



	/**
	 * 
	 * @param line
	 * @return
	 */
	public static ArrayList getColorList( final String line )
	{
		String sub = SGUtilityText.getInnerString( line, '{', '}' );
		if( sub==null )
		{
			return null;
		}

		ArrayList strColorList = SGUtilityText.getStringListFromCommaSeparatedLine( sub );
		ArrayList colorList = new ArrayList();
		for( int ii=0; ii<strColorList.size(); ii++ )
		{
			String strColor = (String)strColorList.get(ii);
			Color color = SGUtilityText.getColorFromString(strColor);
			colorList.add(color);
		}

		return colorList;
	}



	/**
	 * (str1),(str2),...,(strN)　→　文字列リスト
	 */
	public static ArrayList getStringListFromCommaSeparatedLine( String line )
	{
//System.out.println("*** getStringListFromCommaSeparatedLine ***");

		int fromIndex = 0;
		int begin;
		int end;

		ArrayList strList = new ArrayList();
		while( true )
		{
			begin = line.indexOf( "(", fromIndex );
			end = line.indexOf( ")", fromIndex );

//System.out.println("begin="+begin+"  "+"end="+end);

			if( begin >= end )
			{
				break;
			}

			String sub = line.substring( begin, end+1 );
			if( sub==null )
			{
				break;
			}

//System.out.println(sub);

			strList.add(sub);
			fromIndex = end+1;
		}

		return strList;
	}




	/**
	 * 
	 */
	public static String getFontStyleName( final int style )
	{

		String name = null;
		switch( style )
		{

			case Font.PLAIN :
			{
				name = SGIConstants.FONT_PLAIN;
				break;
			}

			case Font.BOLD :
			{
				name = SGIConstants.FONT_BOLD;
				break;
				
			}

			case Font.ITALIC :
			{
				name = SGIConstants.FONT_ITALIC;
				break;
				
			}

			case ( Font.BOLD | Font.ITALIC ) :
			{
				name = SGIConstants.FONT_BOLD_ITALIC;
				break;
				
			}

			default :
			{
				
			}

		}

		return name;
	}


	/**
	 * 
	 */
	public static int getFontStyle( final String name )
	{

		if( name==null )
		{
			return -1;
		}

		int style;
		if( name.equals(SGIConstants.FONT_PLAIN) )
		{
			style = Font.PLAIN;
		}
		else if( name.equals(SGIConstants.FONT_BOLD) )
		{
			style = Font.BOLD;
		}
		else if( name.equals(SGIConstants.FONT_ITALIC) )
		{
			style = Font.ITALIC;
		}
		else if( name.equals(SGIConstants.FONT_BOLD_ITALIC) )
		{
			style = Font.BOLD | Font.ITALIC;
		}
		else
		{
			style = -1;
		}

		return style;
	}



	/**
	 * 
	 */
	public static String getScaleTypeName( final int type )
	{

		String name = null;
		switch( type )
		{
			case SGAxis.LINEAR_TYPE :
			{
				name = SGIConstants.SCALE_TYPE_LINEAR;
				break;
			}
			
			case SGAxis.LOG_TYPE :
			{
				name = SGIConstants.SCALE_TYPE_LOG;
				break;
			}

			default :
			{
				
			}
		}

		return name;
	}



	/**
	 * 
	 */
	public static int getScaleType( final String name )
	{
		if( name==null )
		{
			return -1;
		}

		int type;
		if( name.equals( SGIConstants.SCALE_TYPE_LINEAR ) )
		{
			type = SGAxis.LINEAR_TYPE;
		}
		else if( name.equals( SGIConstants.SCALE_TYPE_LOG ) )
		{
			type = SGAxis.LOG_TYPE;
		}
		else
		{
			type = -1;
		}

		return type;
	}



	/**
	 * 
	 * @param spec
	 * @return
	 */
	public static Document getDocument( String spec )
	{
		Document doc = null;

		// create an URL instance
		try
		{
			URL url = new URL(spec);
			doc = getDocument(url);
		}
		catch( MalformedURLException ex )
		{
			return null;
		}

		return doc;
	}



	/**
	 * 
	 * @return
	 * @throws Exception
	 */
	public static Document getDocument( URL url )
	{
		Document doc = null;
		InputStream bis = null;
		try
		{
			// get input stream
			bis = new BufferedInputStream( url.openStream() );

			// parse input and create a Document object
			try
			{
				doc = DocumentBuilderFactory.newInstance()
					.newDocumentBuilder().parse( bis, url.toString() );
			}
			catch( Exception ex )
			{
				return null;
			}
		}
		catch( IOException ex )
		{
			return null;
		}
		finally
		{
			// close the input stream
			try
			{
				if( bis!=null )
				{
					bis.close();
				}
			}
			catch( IOException ex )
			{
			}
		}

		return doc;
	}

	
	
	/**
	 * 
	 * @param str
	 * @return
	 */
	private static Number parse( final String str )
	{
		if( str==null )
		{
			return null;
		}

		String strNew = str;

		// remove the first character of '+'
		if( str.startsWith("+") )
		{
			if( str.length() > 1 )
			{
				strNew = strNew.substring(1);
			}
		}

		// from e to E
		strNew = strNew.toUpperCase();
		
		// from E+ to E
		strNew = strNew.replaceAll( "E\\+", "E" );

		// parse the string
		ParsePosition pos = new ParsePosition(0);
		Number num = NumberFormat.getInstance().parse( strNew, pos );
		if( pos.getIndex()!=strNew.length() )
		{
			return null;
		}

		return num;
	}
	
	
	/**
	 * 
	 * @param str
	 * @param unit
	 * @return
	 */
	public static Float getFloat( final String str, final String unit )
	{
		Number num = SGUtilityText.removeUnit(str,unit);
		if( num==null )
		{
			return null;
		}
		return new Float( num.floatValue() );
	}

	
	/**
	 * 
	 * @param str
	 * @param unit
	 * @return
	 */
	public static Double getDouble( final String str, final String unit )
	{
		Number num = SGUtilityText.removeUnit(str,unit);
		if( num==null )
		{
			return null;
		}
		return new Double( num.doubleValue() );
	}

	
	
	/**
	 * Check whether the string is valid.
	 * @param str	a string
	 * @return		whether the string is valid
	 */
	public static boolean isValidString( final String str )
	{
		if( str==null )
		{
			return false;
		}

		final int len = str.length();
		
		// if the length of the string equals to zero
		if( len==0 )
		{
			return false;
		}

		// if the string consists of spaces
		boolean flag = false;
		for( int ii=0; ii<len; ii++ )
		{
			final char c = str.charAt(ii);
			if( c!=' ' & c!=twoByteSpaceChar & c!='\t' & c!='\n' & c!='\r' & c!='\f' )
			{
				flag = true;
				break;
			}
		}
		if( !flag )
		{
			return false;
		}

		return true;
	}



	/**
	 * 
	 * @param list
	 * @param name
	 * @return
	 */
	public static String getSerialName(
		ArrayList list, final String name )
	{
		String nameNew = name;

		int max = -1;
		for( int ii=0; ii<list.size(); ii++ )
		{
			String str = (String)list.get(ii);
			if( str.startsWith(name) )
			{
				String sub = str.substring( name.length() );
				if( sub.startsWith("(") & sub.endsWith(")") )
				{
					String sub2 = sub.substring(1,sub.length()-1);
					Integer index = SGUtilityText.getInteger(sub2);
					if( index!=null )
					{
						int n = index.intValue();
						if( n > max )
						{
							max = n;
						}
					}
				}
				else if( sub.equals("") )
				{
					max = 0;
				}
			}
		}

		if( max!=-1 )
		{
			max++;
			nameNew += "(" + max + ")";
		}

		return nameNew;
	}



	/**
	 * Add an available date format
	 * @param format
	 */
	public static void addAvailableDateFormat( final String format )
	{
		DATE_FORMAT_ARRAY_LIST.add( new SimpleDateFormat( format ) );
	}


	
	/**
	 * Parse the string and returns a Date object.
	 * @param str - a text string to be parsed
	 * @return a Date object
	 */
	public static Date getDate( final String str )
	{
		Date date = null;

		ArrayList list = DATE_FORMAT_ARRAY_LIST;
		for( int ii=0; ii<list.size(); ii++ )
		{
			DateFormat df = (DateFormat)list.get(ii);

			// parse the string
			ParsePosition pos = new ParsePosition(0);
			Date d = df.parse( str, pos );
			if( pos.getIndex()==str.length() )
			{
				if( d!=null )
				{
					date = d;
					break;
				}
			}
		}

		return date;
	}



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



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



	/**
	 * 
	 * @param value
	 * @param unitOld
	 * @param unitNew
	 * @return
	 */
	public static double convert(
		final double value, final String unitOld, final String unitNew )
	{
		// check
		if( unitOld==null || unitNew==null )
		{
			throw new IllegalArgumentException();
		}
		final String[] units = SGUtilityText.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;
	}



	/**
	 * Parse and convert to the given unit.
	 * ex. str - 1 inch , unit - cm is converted to "2.54"
	 * @param str - a string to be parsed
	 * @return parsed string
	 */
	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 = SGUtilityText.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;
		}
	
		Number value = SGUtilityText.removeUnit( str, suffix );
		if( value==null )
		{
			return null;
		}
		final double num = value.doubleValue();

		//
		final double numNew = SGUtilityText.convert( num, suffix, unit );
		String valueNew = Double.toString( numNew );
	
		return valueNew;
	}



	/**
	 * Remove the unit from a text string, parse and create a Number object.
	 * @param str - a text string to be parsed
	 * @param unit - a text string of unit to be removed
	 * @return parsed result
	 */
	public static Number removeUnit( final String str, final String unit )
	{
		final String sub = removeSuffix( str, unit );
		if( sub==null )
		{
			return null;
		}

		//
		final StringTokenizer st = new StringTokenizer( sub );
		final ArrayList tokenList = new ArrayList();
		while( st.hasMoreTokens() )
		{
			tokenList.add( st.nextToken() );
		}
		if( tokenList.size()!=1 )
		{
			return null;
		}
		final String value = (String)tokenList.get(0);

		return SGUtilityText.getDouble( value );
	}



	/**
	 * Remove the suffix from a text string.
	 * @param str - a text string to be parsed
	 * @param suffix - a text string to be removed
	 * @return parsed result
	 */
	public static String removeSuffix( final String str, final String suffix )
	{
		if( str==null )
		{
			return null;
		}
		if( str.length()==0 )
		{
			return null;
		}
		if( suffix==null )
		{
			return str;
		}
	
		if( str.endsWith( suffix ) == false )
		{
			return str;
		}
	
		// create a new string without suffix
		int index = -1;
		while( true )
		{
			int num = str.indexOf(suffix,index+1);
			if( num==-1 )
			{
				break;
			}
			index = num;
		}
		String sub = str.substring(0,index);
		if( sub.length()==0 )
		{
			return null;
		}

		return sub;
	}



	// static initializer
	static
	{
		String[] array = DEFAULT_DATE_FORMAT_ARRAY;
		for( int ii=0; ii<array.length; ii++ )
		{
			addAvailableDateFormat( array[ii] );
		}
	};


}

