
package jp.riken.brain.ni.samuraigraph.figure.java2d;

import java.util.*;
import java.awt.*;
import java.awt.geom.*;
import jp.riken.brain.ni.samuraigraph.base.*;
import jp.riken.brain.ni.samuraigraph.data.*;
import jp.riken.brain.ni.samuraigraph.figure.*;

/**
 *
 */

public class SGDrawingElementString2DExtended extends SGDrawingElementString2D
{

	/**
	 * 
	 */
	protected ArrayList mBaseElementList;


	/**
	 * 
	 */
	protected ArrayList mSubscriptElementList;


	/**
	 * 
	 */
	protected ArrayList mSuperscriptElementList;


	/**
	 * 
	 */
	public SGDrawingElementString2DExtended()
	{
		super();
		this.createStringElements();
	}


	/**
	 * 
	 */
	public SGDrawingElementString2DExtended( final String str )
	{
		super( str );
		this.createStringElements();
	}


	/**
	 * 
	 */
	public SGDrawingElementString2DExtended( final SGDrawingElementString element )
	{
		super( element );
		this.createStringElements();
	}


	/**
	 *
	 */
	public SGDrawingElementString2DExtended(
		final String str,
		final String fontFamilyName,
		final int fontStyle,
		final float fontSize )
	{
		super( str, fontFamilyName, fontStyle, fontSize );
		this.createStringElements();
	}
	

	/**
	 *
	 */
	public SGDrawingElementString2DExtended(
		final String str,
		final String fontFamilyName,
		final int fontStyle,
		final float fontSize,
		final float x,
		final float y )
	{
		super( str, fontFamilyName, fontStyle, fontSize, x, y );
		this.createStringElements();
	}



	/**
	 * 
	 * @return
	 */
	public boolean containsSuperscripts()
	{
		return ( this.mString.indexOf("^")!=-1 );
	}


	/**
	 * 
	 * @return
	 */
	public boolean containsSubscripts()
	{
		return ( this.mString.indexOf("_")!=-1 );
	}


	/**
	 * 
	 * @return
	 */
	public boolean containsSubscriptsOfSuperscripts()
	{
		return ( this.containsSubscripts() || this.containsSuperscripts() );
	}



	/**
	 * 
	 */
	public boolean setMagnification( final float mag )
	{
		super.setMagnification( mag );

		for( int ii=0; ii<this.mBaseElementList.size(); ii++ )
		{
			SGDrawingElementString el
				= (SGDrawingElementString)this.mBaseElementList.get(ii);
			el.setMagnification( mag );
		}
		for( int ii=0; ii<this.mSubscriptElementList.size(); ii++ )
		{
			SGDrawingElementString el
				= (SGDrawingElementString)this.mSubscriptElementList.get(ii);
			if( el!=null )
			{
				el.setMagnification( mag );
			}
		}
		for( int ii=0; ii<this.mSuperscriptElementList.size(); ii++ )
		{
			SGDrawingElementString el
				= (SGDrawingElementString)this.mSuperscriptElementList.get(ii);
			if( el!=null )
			{
				el.setMagnification( mag );
			}
		}

		this.updateDrawingElements();

		return true;
	}



	/**
	 * 
	 */
	public boolean setColorList( final ArrayList colorList )
	{
		super.setColorList( colorList );

		for( int ii=0; ii<this.mBaseElementList.size(); ii++ )
		{
			SGDrawingElementString el
				= (SGDrawingElementString)this.mBaseElementList.get(ii);
			el.setColorList( colorList );
		}
		for( int ii=0; ii<this.mSubscriptElementList.size(); ii++ )
		{
			SGDrawingElementString el
				= (SGDrawingElementString)this.mSubscriptElementList.get(ii);
			if( el!=null )
			{
				el.setColorList( colorList );
			}
		}
		for( int ii=0; ii<this.mSuperscriptElementList.size(); ii++ )
		{
			SGDrawingElementString el
				= (SGDrawingElementString)this.mSuperscriptElementList.get(ii);
			if( el!=null )
			{
				el.setColorList( colorList );
			}
		}
		return true;
	}


	/**
	 * 
	 */
	public boolean setColor( final Color color )
	{
		super.setColor( color );

		for( int ii=0; ii<this.mBaseElementList.size(); ii++ )
		{
			SGDrawingElementString el
				= (SGDrawingElementString)this.mBaseElementList.get(ii);
			el.setColor( color );
		}
		for( int ii=0; ii<this.mSubscriptElementList.size(); ii++ )
		{
			SGDrawingElementString el
				= (SGDrawingElementString)this.mSubscriptElementList.get(ii);
			if( el!=null )
			{
				el.setColor( color );
			}
		}
		for( int ii=0; ii<this.mSuperscriptElementList.size(); ii++ )
		{
			SGDrawingElementString el
				= (SGDrawingElementString)this.mSuperscriptElementList.get(ii);
			if( el!=null )
			{
				el.setColor( color );
			}
		}
		return true;
	}


	/**
	 * 
	 * @return
	 */
	public boolean addColor( final Color color )
	{
		super.addColor( color );

		for( int ii=0; ii<this.mBaseElementList.size(); ii++ )
		{
			SGDrawingElementString el
				= (SGDrawingElementString)this.mBaseElementList.get(ii);
			el.addColor( color );
		}
		for( int ii=0; ii<this.mSubscriptElementList.size(); ii++ )
		{
			SGDrawingElementString el
				= (SGDrawingElementString)this.mSubscriptElementList.get(ii);
			if( el!=null )
			{
				el.addColor( color );
			}
		}
		for( int ii=0; ii<this.mSuperscriptElementList.size(); ii++ )
		{
			SGDrawingElementString el
				= (SGDrawingElementString)this.mSuperscriptElementList.get(ii);
			if( el!=null )
			{
				el.addColor( color );
			}
		}
		return true;
	}


	/**
	 *
	 */
	public boolean setLocation( final float x, final float y )
	{
//System.out.println("<< SGDrawingElementString2DExtended::setLocation >>");
//System.out.println(this.getString());
//System.out.println();

/*
		super.setLocation( x, y );
		this.updateDrawingElements();
*/


		final float dx = x - this.getX();
		final float dy = y - this.getY();

		super.setLocation(x,y);

		for( int ii=0; ii<this.mBaseElementList.size(); ii++ )
		{
			SGDrawingElementString el
				= (SGDrawingElementString)this.mBaseElementList.get(ii);
			el.translate( dx, dy );

		}
		for( int ii=0; ii<this.mSubscriptElementList.size(); ii++ )
		{
			SGDrawingElementString el
				= (SGDrawingElementString)this.mSubscriptElementList.get(ii);
			if( el!=null )
			{
				el.translate( dx, dy );
			}
		}
		for( int ii=0; ii<this.mSuperscriptElementList.size(); ii++ )
		{
			SGDrawingElementString el
				= (SGDrawingElementString)this.mSuperscriptElementList.get(ii);
			if( el!=null )
			{
				el.translate( dx, dy );
			}
		}



		return true;
	}



	/**
	 *
	 */
	public boolean setFont( final String name, final int style, final float size )
	{
		super.setFont( name, style, size );

		if( this.mBaseElementList==null )
		{
			this.mBaseElementList = new ArrayList();
			this.mSubscriptElementList = new ArrayList();
			this.mSuperscriptElementList = new ArrayList();
			return true;
		}

		for( int ii=0; ii<this.mBaseElementList.size(); ii++ )
		{
			SGDrawingElementString el
				= (SGDrawingElementString)this.mBaseElementList.get(ii);
			el.setFont( name, style, size );
		}
		for( int ii=0; ii<this.mSubscriptElementList.size(); ii++ )
		{
			SGDrawingElementString el
				= (SGDrawingElementString)this.mSubscriptElementList.get(ii);
			if( el!=null )
			{
				el.setFont( name, style, size/2.0f );
			}
		}
		for( int ii=0; ii<this.mSuperscriptElementList.size(); ii++ )
		{
			SGDrawingElementString el
				= (SGDrawingElementString)this.mSuperscriptElementList.get(ii);
			if( el!=null )
			{
				el.setFont( name, style, size/2.0f );
			}
		}
		this.updateDrawingElements();


		return true;
	}



	/**
	 *
	 */
	public boolean setString( final String str )
	{
		super.setString( str );
		this.createStringElements();
		this.updateDrawingElements();
		return true;
	}



	/**
	 * 
	 */
	public boolean setAngle( final float angle )
	{
		super.setAngle( angle );

		for( int ii=0; ii<this.mBaseElementList.size(); ii++ )
		{
			SGDrawingElementString el
				= (SGDrawingElementString)this.mBaseElementList.get(ii);
			el.setAngle( angle );
		}
		for( int ii=0; ii<this.mSubscriptElementList.size(); ii++ )
		{
			SGDrawingElementString el
				= (SGDrawingElementString)this.mSubscriptElementList.get(ii);
			if( el!=null )
			{
				el.setAngle( angle );
			}
		}
		for( int ii=0; ii<this.mSuperscriptElementList.size(); ii++ )
		{
			SGDrawingElementString el
				= (SGDrawingElementString)this.mSuperscriptElementList.get(ii);
			if( el!=null )
			{
				el.setAngle( angle );
			}
		}
		this.updateDrawingElements();
		return true;
	}



	/**
	 * 
	 * @return
	 */
	private boolean createStringElementsDirectly()
	{
		SGDrawingElementString2D el
			= new SGDrawingElementString2D( this.mString );
		this.mBaseElementList.add(el);
		this.mSubscriptElementList.add(null);
		this.mSuperscriptElementList.add(null);
		this.setPropertiesToAllStringElements();

		return true;
	}



	/**
	 * 
	 * @return
	 */
	private boolean createStringElements()
	{

		if( this.mBaseElementList==null )
		{
			this.mBaseElementList = new ArrayList();
			this.mSubscriptElementList = new ArrayList();
			this.mSuperscriptElementList = new ArrayList();
		}
		else
		{
			this.mBaseElementList.clear();
			this.mSubscriptElementList.clear();
			this.mSuperscriptElementList.clear();
		}

		// if the string does not contain subscripts nor superscripts,
		// set the string to the base element
		if( this.containsSubscriptsOfSuperscripts() == false )
		{
			return this.createStringElementsDirectly();
		}


		// get information of the input line
		String line = this.getString();
		ArrayList charList = new ArrayList();
		ArrayList superList = new ArrayList();
		ArrayList subList = new ArrayList();
		if( SGUtilityText.getSubscriptAndSuperscriptInfo(line,charList,superList,subList) == false )
		{
			return this.createStringElementsDirectly();
		}
		if( charList.size()!=superList.size() || superList.size()!=subList.size() )
		{
			return this.createStringElementsDirectly();
		}


		//
		for( int ii=0; ii<charList.size(); ii++ )
		{
			// characters
			{
				// create a string
				Character c = (Character)charList.get(ii);
				char[] array = new char[1];
				array[0] = c.charValue();
				String str = new String(array);

				SGDrawingElementString2D el	= new SGDrawingElementString2D(str);
				this.mBaseElementList.add(el);
			}
		

			// subscript characters
			Object sb = subList.get(ii);
			if( sb!=null )
			{
				String str = (String)sb;
				SGDrawingElementString2DExtended el
					= new SGDrawingElementString2DExtended(str);
				this.mSubscriptElementList.add(el);
			}
			else
			{
				this.mSubscriptElementList.add( null );
			}


			// superscript characters
			Object sp = superList.get(ii);
			if( sp!=null )
			{
				String str = (String)sp;
				SGDrawingElementString2DExtended el
					= new SGDrawingElementString2DExtended(str);
				this.mSuperscriptElementList.add( el );
			}
			else
			{
				this.mSuperscriptElementList.add( null );
			}
		
		}


		this.setPropertiesToAllStringElements();

		return true;
	}



	/**
	 * 
	 * @return
	 */
	public boolean setPropertiesToAllStringElements()
	{
		final float mag = this.getMagnification();
		final ArrayList colorList = this.getColorList();
		final float size = this.getFontSize();
		final String name = this.getFontFamilyName();
		final int style = this.getFontStyle();
		final float angle = this.getAngle();

		//
		for( int ii=0; ii<this.mBaseElementList.size(); ii++ )
		{
			// characters
			{
				SGDrawingElementString2D el
					= (SGDrawingElementString2D)this.mBaseElementList.get(ii);
				el.setMagnification( mag );
				el.setColorList( colorList );
				el.setFont( name, style, size );
				el.setAngle( angle );
			}

			// subscript characters
			Object sp = this.mSubscriptElementList.get(ii);
			if( sp!=null )
			{
				SGDrawingElementString2D el	= (SGDrawingElementString2D)sp;
				el.setMagnification( mag );
				el.setColorList( colorList );
				el.setFont( name, style, size/2.0f );
				el.setAngle( angle );

				if( el instanceof SGDrawingElementString2DExtended )
				{
					SGDrawingElementString2DExtended el_
						= (SGDrawingElementString2DExtended)el;
					el_.setPropertiesToAllStringElements();
				}
			}

			// superscript characters
			Object sb = this.mSuperscriptElementList.get(ii);
			if( sb!=null )
			{
				SGDrawingElementString2D el	= (SGDrawingElementString2D)sb;
				el.setMagnification( mag );
				el.setColorList( colorList );
				el.setFont( name, style, size/2.0f );
				el.setAngle( angle );

				if( el instanceof SGDrawingElementString2DExtended )
				{
					SGDrawingElementString2DExtended el_
						= (SGDrawingElementString2DExtended)el;
					el_.setPropertiesToAllStringElements();
				}
			}
		}

		return true;
	}




	/**
	 * 
	 */
	public Rectangle2D getStringRect()
	{
//System.out.println("<< SGDrawingElementString2D::getStringRect >>");

		//
		float width = 0.0f;
		float height = 0.0f;
		for( int ii=0; ii<this.mBaseElementList.size(); ii++ )
		{
			// characters
			{
				SGDrawingElementString2D el
					= (SGDrawingElementString2D)this.mBaseElementList.get(ii);

				// get a bounding box
				Rectangle2D stringRect = el.getStringRect();
				width += (float)stringRect.getWidth();
				height = (float)stringRect.getHeight();
			}


			// subscript characters
			Object sb = this.mSubscriptElementList.get(ii);
			float widthSub = 0.0f;
			if( sb!=null )
			{
				SGDrawingElementString2D el
					= (SGDrawingElementString2D)this.mSubscriptElementList.get(ii);

				// get a bounding box
				Rectangle2D stringRect = el.getStringRect();

				widthSub += (float)stringRect.getWidth();
			}


			// superscript characters
			Object sp = this.mSuperscriptElementList.get(ii);
			float widthSuper = 0.0f;
			if( sp!=null )
			{
				SGDrawingElementString2D el
					= (SGDrawingElementString2D)this.mSuperscriptElementList.get(ii);

				// get a bounding box
				Rectangle2D stringRect = el.getStringRect();

				widthSuper += (float)stringRect.getWidth();
			}


			if( sp!=null || sb!=null )
			{
				width += Math.max(widthSuper,widthSub);
			}

		}

		// create a rectangle
		Rectangle2D rect = new Rectangle2D.Float(
			0.0f, 0.0f,
			width, height );


		return rect;

	}



	/**
	 * 
	 */
	public Rectangle2D getElementBounds()
	{
//System.out.println("<< SGDrawingElementString2D::getElementBounds >>");

		//
		ArrayList rectList = new ArrayList();
		for( int ii=0; ii<this.mBaseElementList.size(); ii++ )
		{
			// characters
			{
				SGDrawingElementString2D el
					= (SGDrawingElementString2D)this.mBaseElementList.get(ii);
				rectList.add( el.getElementBounds() );
			}

			// subscript characters
			Object sb = this.mSubscriptElementList.get(ii);
			if( sb!=null )
			{
				SGDrawingElementString2D el
					= (SGDrawingElementString2D)this.mSubscriptElementList.get(ii);
				rectList.add( el.getElementBounds() );
			}

			// superscript characters
			Object sp = this.mSuperscriptElementList.get(ii);
			if( sp!=null )
			{
				SGDrawingElementString2D el
					= (SGDrawingElementString2D)this.mSuperscriptElementList.get(ii);
				rectList.add( el.getElementBounds() );
			}
		}

//System.out.println(this.mBaseElementList);
//System.out.println(this.mSubscriptElementList);
//System.out.println(this.mSuperscriptElementList);
//System.out.println(rectList);

		// create a rectangle
		Rectangle2D rect = SGUtility.createUnion( rectList );

//System.out.println(rect);
//System.out.println();

		return rect;
	}



	/**
	 * 
	 * @return
	 */
	public boolean updateDrawingElements()
	{

		// angle
		final float angle = this.getAngle();
		final float cv = (float)Math.cos(angle);
		final float sv = (float)Math.sin(angle);


//System.out.println("angle:"+angle/(Math.PI/180.0));

		// location
		final float x = this.getX();
		final float y = this.getY();

//System.out.println(x+"  "+y);

		float d = 0.0f;
		for( int ii=0; ii<this.mBaseElementList.size(); ii++ )
		{
//System.out.println("ii="+ii);

			// characters
			{
				SGDrawingElementString2D el
					= (SGDrawingElementString2D)this.mBaseElementList.get(ii);
				Rectangle2D stringRect = el.getStringRect();

				el.setLocation( x + d*cv, y - d*sv );

				// update the location
				d += (float)stringRect.getWidth();
			}


			// superscript characters
			Object sp = this.mSuperscriptElementList.get(ii);
			float widthSuper = 0.0f;
			if( sp!=null )
			{
				SGDrawingElementString2D el = (SGDrawingElementString2D)sp;
				Rectangle2D stringRect = el.getStringRect();

				// update the location
				el.setLocation( x + d*cv, y - d*sv );

				// update the location of subscript and superscript
				if( el instanceof SGDrawingElementString2DExtended )
				{
					SGDrawingElementString2DExtended el_
						= (SGDrawingElementString2DExtended)el;
					el_.updateDrawingElements();
				}

				widthSuper += (float)stringRect.getWidth();
			}


			// subscript characters
			Object sb = this.mSubscriptElementList.get(ii);
			float widthSub = 0.0f;
			if( sb!=null )
			{
				SGDrawingElementString2D el = (SGDrawingElementString2D)sb;
				Rectangle2D stringRect = el.getStringRect();

				final float h = (float)stringRect.getHeight();

				// update the location
				el.setLocation( x + d*cv + h*sv, y - d*sv + h*cv );

				// update the location of subscript and superscript
				if( el instanceof SGDrawingElementString2DExtended )
				{
					SGDrawingElementString2DExtended el_
						= (SGDrawingElementString2DExtended)el;
					el_.updateDrawingElements();
				}

				widthSub += (float)stringRect.getWidth();
			}


			if( sp!=null || sb!=null )
			{
				d += Math.max(widthSuper,widthSub);
			}

		}


		return true;
	}






	/**
	 * 
	 */
	public boolean drawString( final Graphics2D g2d )
	{
//System.out.println("<< drawString >>");

		if( g2d==null )
		{
			return false;
		}

		if( this.isVisible() == false )
		{
			return true;
		}


		// draw strings
		for( int ii=0; ii<this.mBaseElementList.size(); ii++ )
		{
			// characters
			{
				SGDrawingElementString2D el
					= (SGDrawingElementString2D)this.mBaseElementList.get(ii);
				el.drawString(g2d);
			}

			// subscript characters
			Object sp = this.mSubscriptElementList.get(ii);
			if( sp!=null )
			{
				SGDrawingElementString2D el	= (SGDrawingElementString2D)sp;
				el.drawString(g2d);
			}

			// superscript characters
			Object sb = this.mSuperscriptElementList.get(ii);
			if( sb!=null )
			{
				SGDrawingElementString2D el	= (SGDrawingElementString2D)sb;
				el.drawString(g2d);
			}
		}

		return true;

	}




}
