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

import java.util.*;
import java.io.*;
import java.awt.*;
import java.net.URL;

import org.w3c.dom.*;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;


/**
 * 
 */
public class SGUtilityText
{


	/***
	 * 
	 * @param args
	 */
	public static void main(String[] args)
	{

System.out.println("<< start >>");

/*
		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;
		int style;

		str = SGUtilityText.getFontStyleString( Font.PLAIN );
		style = SGUtilityText.getFontStyle( str );
		System.out.println(style+"  "+str);

		str = SGUtilityText.getFontStyleString( Font.BOLD );
		style = SGUtilityText.getFontStyle( str );
		System.out.println(style+"  "+str);

		str = SGUtilityText.getFontStyleString( Font.ITALIC );
		style = SGUtilityText.getFontStyle( str );
		System.out.println(style+"  "+str);

		str = SGUtilityText.getFontStyleString( Font.BOLD | Font.ITALIC );
		style = SGUtilityText.getFontStyle( str );
		System.out.println(style+"  "+str);

		str = SGUtilityText.getFontStyleString(-10);
		style = SGUtilityText.getFontStyle(str);
		System.out.println(style+"  "+str);
*/


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();


	}



	/**
	 * 
	 */
	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 )
		{
			return false;
		}

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


		// get all characters
		final char[] charArray = new char[str.length()];
		for( int ii=0; ii<charArray.length; ii++ )
		{
			charArray[ii] = str.charAt(ii);
		}


		// '"'
		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 which the counter indicates
			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();
					}

					// 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;
				}
//System.out.println(line.length());

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

		return line;
	}




	/**
	 * "key=value"の形でプロパティを１行書き出す
	 */
	public static boolean writePropertyLine(
		final Writer writer, final String key, final Object value )
		throws IOException
	{

		String str;
		if( value == null )
		{
			str = "";
		}
		else
		{
			str = value.toString();
		}

		writer.write( key + "=" + str + "\n" );
		
		return true;
	}



	/**
	 * "key=(r,g,b,a)"の形で色の情報を書き出す
	 */
	public static boolean writeColorPropertyLine(
		final Writer writer, final String key, final Color color )
		throws IOException
	{

		final String strColor = SGUtilityText.getColorString( color );
		SGUtilityText.writePropertyLine( writer, key, strColor );

		return true;
	}



	/**
	 * "{(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;
	}



	/**
	 * 引数で渡された文字列にダブルクォーテーションを付けて書き出す
	 */
	public static boolean writeStringPropertyLine(
		final Writer writer, final String key, final String str )
		throws IOException
	{

		ArrayList cList = new ArrayList();
		cList.add( new Character('"') );
		for( int ii=0; ii<str.length(); ii++ )
		{
			Character c = new Character( str.charAt(ii) );
			cList.add(c);
		}
		cList.add( new Character('"') );


		char[] cArray = new char[cList.size()];
		for( int ii=0; ii<cArray.length; ii++ )
		{
			cArray[ii] = ((Character)cList.get(ii)).charValue();
		}

		String strNew = new String( cArray );
		
		
		boolean flag = SGUtilityText.writePropertyLine( writer, key, strNew );

		return flag;

	}



	/**
	 * 引数で渡された文字列の最初の方から文字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;
	}



	/**
	 * 
	 */
	public static String getPropertyFromLine( final String line, final String key )
	{

		if( line==null || key==null )
		{
			return null;
		}

		final String str = key+"=";
		if( line.startsWith( str ) )
		{
			String sub = line.substring( str.length() );
			return sub;
		}
		else
		{
			return null;
		}

	}



	/**
	 * プロパティの１行で、ダブルクォーテーションで囲まれた文字列から中身を取り出す
	 */
	public static String getStringPropertyFromLine( final String line, final String key )
	{
		
		String sub = SGUtilityText.getPropertyFromLine( line, key );
		if( sub == null )
		{
			return null;
		}

//		String str = SGUtilityText.getInnerString( sub, '"', '"' );
		
		ArrayList list = new ArrayList();
		SGUtilityText.tokenize(sub,list);
		String str = (String)list.get(0);


		return str;
	}



	/**
	 * 
	 */
	public static Boolean getBooleanPropertyFromLine( final String line, final String key )
	{
		
		String sub = SGUtilityText.getPropertyFromLine( line, key );
		if( sub == null )
		{
			return null;
		}

		Boolean b = null;
		if( "true".equals(sub) )
		{
			b = new Boolean(true);
		}
		else
		if( "false".equals(sub) )
		{
			b = new Boolean(false);
		}
		return b;
		
	}




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

		try
		{
			Boolean b = Boolean.valueOf( value );
			return b;
		}
		catch( NumberFormatException ex )
		{
			return null;
		}
	}


	/**
	 * 
	 */
	public static Integer getInteger( final String value )
	{
		if( value==null )
		{
			return null;
		}

		try
		{
			Integer num = Integer.valueOf( value );
			return num;
		}
		catch( NumberFormatException ex )
		{
			return null;
		}
	}



	/**
	 * 
	 */
	public static Float getFloat( final String value )
	{
		if( value==null )
		{
			return null;
		}

		try
		{
			Float num = Float.valueOf( value );
			return num;
		}
		catch( NumberFormatException ex )
		{
			return null;
		}
	}



	/**
	 * 
	 */
	public static Double getDouble( final String value )
	{
		if( value==null )
		{
			return null;
		}

		try
		{
			Double num = Double.valueOf( value );
			return num;
		}
		catch( NumberFormatException ex )
		{
			return null;
		}
	}




	/**
	 * 
	 */
	public static Integer getIntegerPropertyFromLine( final String line, final String key )
	{
		
		String sub = SGUtilityText.getPropertyFromLine( line, key );

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

		try
		{
			Integer num = Integer.valueOf( sub );
			return num;
		}
		catch( NumberFormatException ex )
		{
			return null;
		}
		
	}


	/**
	 * 
	 */
	public static Double getDoublePropertyFromLine( final String line, final String key )
	{
		
		String sub = SGUtilityText.getPropertyFromLine( line, key );

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

		try
		{
			Double num = Double.valueOf( sub );
			return num;		
		}
		catch( NumberFormatException ex )
		{
			return null;
		}
		
	}



	/**
	 * 
	 */
	public static Color getColorPropertyFromLine( final String line, final String key )
	{
		
		String sub = SGUtilityText.getPropertyFromLine( line, key );
		if( sub == null )
		{
			return null;
		}


		Color color = SGUtilityText.getColorFromString(sub);
		
		return color;
	}



	/**
	 * 
	 */
	public static ArrayList getColorListFromLine( final String line, final String key )
	{

		String sub = SGUtilityText.getPropertyFromLine( line, key );
		if( sub == null )
		{
			return null;
		}

		return getColorList( sub );
	}



	/**
	 * 
	 * @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 Integer getFontStyleFromLine( final String line, final String key)
	{

		String sub = SGUtilityText.getPropertyFromLine( line, key );
		if( sub == null )
		{
			return null;
		}
		
		int style = SGUtilityText.getFontStyle(sub);

		return new Integer(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;
	}





	/**
	 * 
	 */
	public static Integer getScaleTypeFromLine( final String line, final String key )
	{

		String sub = SGUtilityText.getPropertyFromLine( line, key );
		if( sub == null )
		{
			return null;
		}

		int type = SGUtilityText.getScaleType( sub );

		return new Integer(type);
	}



	/**
	 * 
	 * @return
	 * @throws Exception
	 */
	public static Document getDocument( String spec )
	{
		Document doc = null;
		InputStream inURL = null;
		InputStream in = null;

		try
		{
			// create an URL instance
			URL url = new URL(spec);

			// get input stream
			inURL = url.openStream();
			in = new BufferedInputStream( inURL );
	
			// parse input and create a Document object
			doc = DocumentBuilderFactory.newInstance()
					.newDocumentBuilder().parse(in);
		}
		catch( Exception ex )
		{
			return null;
		}
		finally
		{
			// close the input streams
			try
			{
				if( inURL!=null )
				{
					inURL.close();
				}
			}
			catch( IOException ex )
			{
			}

			try
			{
				if( in!=null )
				{
					in.close();
				}
			}
			catch( IOException ex )
			{
			}
		}

		return doc;
	}


}
