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

import java.awt.Color;
import java.awt.Font;
import java.util.List;

import jp.riken.brain.ni.samuraigraph.base.SGDrawingElement;
import jp.riken.brain.ni.samuraigraph.base.SGIConstants;
import jp.riken.brain.ni.samuraigraph.base.SGIDrawingElementConstants;
import jp.riken.brain.ni.samuraigraph.base.SGProperties;
import jp.riken.brain.ni.samuraigraph.base.SGTuple2f;
import jp.riken.brain.ni.samuraigraph.base.SGUtilityText;

import org.w3c.dom.Element;


/**
 * Drawing element of the text string.
 * 
 */
public abstract class SGDrawingElementString extends SGDrawingElement
	implements SGIStringConstants, SGIDrawingElementConstants
{
	/**
	 * Text for this string element.
	 */
	private String mString = null;

	/**
	 * Font used to draw string actually.
	 * This object is updated with the primary information source:
	 * font size, font style, font name and the magnification.
	 */
	private Font mFont = null;

	/**
	 * Font name.
	 */
	private String mFontName = DEFAULT_STRING_FONT_NAME;

	/**
	 * Font style.
	 */
	private int mFontStyle = DEFAULT_STRING_FONT_STYLE;

	/**
	 * Font size in the default zoom.
	 */
	private float mFontSize = DEFAULT_STRING_FONT_SIZE;

	/**
	 * Angled of this string.
	 */
	private float mAngle = DEFAULT_STRING_ANGLE;

	/**
	 * X-coordinate of the string.
	 */
	private float mX = 0.0f;

	/**
	 * Y-coordinate of the string.
	 */
	private float mY = 0.0f;


	/**
	 * Default constructor.
	 */
	public SGDrawingElementString()
	{
		super();
		this.mString = new String("");
		super.setColor( DEFAULT_STRING_FONT_COLOR );
		this.updateFont();
	}

	/**
	 * Construct a string element with given text.
	 */
	public SGDrawingElementString( final String str )
	{
		super();
		this.mString = new String( str );
		super.setColor( DEFAULT_STRING_FONT_COLOR );
		this.updateFont();
	}

	/**
	 * Construct a string element with given string element.
	 */
	public SGDrawingElementString(
		final SGDrawingElementString element )
	{
		super();
		this.mString = new String( element.mString );
		this.mX = element.mX;
		this.mY = element.mY;
		this.mFontName = element.getFontName();
		this.mFontStyle = element.getFontStyle();
		this.mFontSize = element.getFontSize();
		this.mAngle = element.mAngle;
		super.setColorList( element.getColorList() );
		super.setMagnification( element.getMagnification() );
		this.updateFont();
	}

	/**
	 * Construct a string element with given text and font information.
	 */
	public SGDrawingElementString(
		final String str,
		final String fontName,
		final int fontStyle,
		final float fontSize,
		final Color color,
		final float mag,
		final float angle)
	{
		super();
		this.mString = new String( str );
		this.mFontName = fontName;
		this.mFontStyle = fontStyle;
		this.mFontSize = fontSize;
		this.mAngle = angle;
		super.setColor( color );
		super.setMagnification( mag );
		this.updateFont();
	}
	
	/**
	 * 
	 */
	public void dispose()
	{
		super.dispose();
		this.mString = null;
		this.mFont = null;
		this.mFontName = null;
	}

	/**
	 * Returns the text of this string element.
	 */
	public final String toString()
	{
		return this.getString();
	}

	/**
	 * Set the text.
	 * @param str - text
	 */
	public boolean setString( final String str )
	{
		this.mString = new String( str );
		return true;
	}

	/**
	 * Set the magnification.
	 * @param mag - magnification
	 */
	public boolean setMagnification( final float mag )
	{
		super.setMagnification( mag );

		// update the attribute
		this.updateFont();

		return true;
	}

	/**
	 * Set the font name.
	 * @param name - font name
	 */
	public final boolean setFontName( final String name )
	{
		return this.setFont( name, this.mFontStyle, this.mFontSize );
	}

	/**
	 * Set the font style.
	 * @param style - font style
	 */
	public final boolean setFontStyle( final int style )
	{
		return this.setFont( this.mFontName, style, this.mFontSize );
	}

	/**
	 * Set the font size in the default zoom
	 * @param size - font size
	 */
	public final boolean setFontSize( final float size )
	{
		return this.setFont( this.mFontName, this.mFontStyle, size );
	}

	/**
	 * Set the font size with unit in the default zoom
	 */
	public final boolean setFontSize( final float size, final String unit )
	{
		final double conv = SGUtilityText.convert( size, unit, FONT_SIZE_UNIT );
		if( conv < FONT_SIZE_MIN_VALUE ) return false;
		if( conv > FONT_SIZE_MAX_VALUE ) return false;
		return this.setFontSize( (float)SGUtilityText.convertToPoint( size, unit ) );
	}

	/**
	 * Set the font information.
	 * @param name - font name
	 * @param style - font style
	 * @param size - font size in the default zoom
	 * @return
	 */
	public boolean setFont( final String name, final int style, final float size )
	{
		this.mFontName = name;
		this.mFontStyle = style;
		this.mFontSize = size;

		// update the attribute
		this.updateFont();

		return true;
	}

	/**
	 * Update the font object in attributes.
	 */
	private boolean updateFont()
	{
		this.mFont = new Font(
			this.mFontName,
			this.mFontStyle,
			(int)(this.getMagnification()*this.mFontSize)
		);
		return true;
	}

	/**
	 * Set the location of this string.
	 * @param pos - location
	 * @return
	 */
	public final boolean setLocation( final SGTuple2f pos )
	{
		if( pos==null )
		{
			throw new IllegalArgumentException("pos==null");
		}
		this.setLocation( pos.x, pos.y );
		return true;
	}

	/**
	 * Set the location of this string.
	 * @param x - X-coordinate
	 * @param y - Y-coordinate
	 * @return
	 */
	public final boolean setLocation( final float x, final float y )
	{
		this.setX( x );
		this.setY( y );
		return true;
	}

	/**
	 * Translate this string element.
	 * @param dx - Displacement to the X-axis direction
	 * @param dy - Displacement to the Y-axis direction
	 */
	public final void translate( final float dx, final float dy )
	{
		this.setLocation( this.getX() + dx, this.getY() + dy );
	}

	/**
	 * Set the x-coordinate of this string.
	 * @param x - X-coordinate
	 * @return
	 */
	public boolean setX( final float x )
	{
		this.mX = x;
		return true;
	}


	/**
	 * Set the y-coordinate of this string.
	 * @param y - Y-coordinate
	 * @return
	 */
	public boolean setY( final float y )
	{
		this.mY = y;
		return true;
	}

	/**
	 * Set the angle of this string.
	 * @param angle - angle to be set
	 * @return
	 */
	public boolean setAngle( final float angle )
	{
		this.mAngle = angle;
		return true;
	}

	/**
	 * Returns a string object.
	 * @return sring object
	 */
	public final String getString()
	{
		return new String( this.mString );
	}

	/**
	 * Returns the X-coordinate.
	 * @return X-coordinate
	 */
	public float getX()
	{
		return this.mX;
	}

	/**
	 * Returns the Y-coordinate.
	 * @return Y-coordinate
	 */
	public float getY()
	{
		return this.mY;
	}

	/**
	 * Returns the location.
	 * @return location
	 */
	public final SGTuple2f getLocation()
	{
		return new SGTuple2f( this.getX(), this.getY() );
	}

	/**
	 * Returns the font.
	 * @return font
	 */
	public final Font getFont()
	{
		return this.mFont;
	}

	/**
	 * Returns the font name.
	 * @return font name
	 */
	public final String getFontName()
	{
		return this.mFontName;
	}

	/**
	 * Returns the font size in the default zoom.
	 * @return font size in the default zoom
	 */
	public final float getFontSize()
	{
		return this.mFontSize;
	}

	/**
	 * Returns the font style.
	 * @return font style
	 */
	public final int getFontStyle()
	{
		return this.mFontStyle;
	}

	/**
	 * Returns the angle of this string.
	 * @return angle of this string
	 */
	public final float getAngle()
	{
		return this.mAngle;
	}

	/**
	 * 
	 */
	public SGProperties getProperties()
	{
		StringProperties p = new StringProperties();
		this.getProperties(p);
		return p;
	}

	/**
	 * 
	 */
	public boolean getProperties( SGProperties p )
	{
		if( p==null ) return false;
		if( ( p instanceof StringProperties ) == false ) return false;

		super.getProperties(p);

		StringProperties sp = (StringProperties)p;
		sp.setFontName( this.mFontName );
		sp.setFontSize( this.mFontSize );
		sp.setFontStyle( this.mFontStyle );
		sp.setAngle( this.mAngle );

		return true;
	}

	/**
	 * 
	 */
	public boolean setProperties( SGProperties p )
	{
		if( ( p instanceof StringProperties ) == false ) return false;

		if( super.setProperties(p) == false ) return false;

		StringProperties ep = (StringProperties)p;

		this.setFont( ep.getFontName(), ep.getFontStyle().intValue(), ep.getFontSize().floatValue() );
		this.setAngle( ep.getAngle().floatValue() );

		return true;

	}

	/**
	 * 
	 * @param el
	 * @return
	 */
	public boolean writeProperty( final Element el )
	{
		el.setAttribute( KEY_TEXT, this.getString() );
		el.setAttribute( KEY_FONT_NAME, this.getFontName() );
		el.setAttribute( KEY_FONT_SIZE, Float.toString( this.getFontSize() ) + SGIConstants.pt );
		el.setAttribute( KEY_FONT_STYLE, SGUtilityText.getFontStyleName( this.getFontStyle() ) );
		el.setAttribute( KEY_STRING_COLORS, SGUtilityText.getColorListString( this.getColorList() ) );
		el.setAttribute( KEY_ANGLE, Float.toString( this.getAngle()/RADIAN_DEGREE_RATIO ) + SGIConstants.degree );
		return true;
	}
		
		

	/**
	 * 
	 */
	public boolean readProperty( final Element el )
	{
		String str = null;
		Number num = null;
		Color cl = null;
		Boolean b = null;
		List list = null;


		// set the text
		str = el.getAttribute( KEY_TEXT );
		if( str.length()!=0 )
		{
			final String text = str;
			if( this.setString( text ) == false )
			{
				return false;
			}
		}
		
		
		// set font name
		str = el.getAttribute( KEY_FONT_NAME );
		if( str.length()!=0 )
		{
			final String fontName = str;
			if( this.setFontName( fontName ) == false )
			{
				return false;
			}
		}
		
		
		// set font size
		str = el.getAttribute( KEY_FONT_SIZE );
		if( str.length()!=0 )
		{
			StringBuffer uFontSize = new StringBuffer();
			num = SGUtilityText.getNumber( str, uFontSize );
			if( num==null )
			{
				return false;
			}
			final float fontSize = num.floatValue();
			if( this.setFontSize( fontSize, uFontSize.toString() ) == false )
			{
				return false;
			}
		}
		
		
		// set font style
		str = el.getAttribute( KEY_FONT_STYLE );
		if( str.length()!=0 )
		{
			final int fontStyle = SGUtilityText.getFontStyle(str);
			if( fontStyle==-1 )
			{
				return false;
			}
			if( this.setFontStyle( fontStyle ) == false )
			{
				return false;
			}
		}
		
		
		// set color
		str = el.getAttribute( KEY_STRING_COLORS );
		if( str.length()!=0 )
		{
			list = SGUtilityText.getColorList(str);
			if( list==null )
			{
				return false;
			}
			if( list.size()<1 )
			{
				return false;
			}
			final Color color = (Color)list.get(0);
			if( this.setColor( color ) == false )
			{
				return false;
			}
		}
		
		
		// set angle
		str = el.getAttribute( KEY_ANGLE );
		if( str.length()!=0 )
		{
			num = SGUtilityText.getFloat(str,SGIConstants.degree);
			if( num==null )
			{
				return false;
			}
			final float angle = num.floatValue()*RADIAN_DEGREE_RATIO;
			if( this.setAngle( angle ) == false )
			{
				return false;
			}
		}

		return true;
	}


	/**
	 * 
	 */
	public static class StringProperties extends DrawingElementProperties
	{

		private float mFontSize = 0.0f;
		private int mFontStyle = -1;
		private String mFontName = null;
		private float mAngle = 0.0f;


		/**
		 * 
		 *
		 */
		public StringProperties()
		{
			super();
		}


		/**
		 * 
		 */
		public boolean equals( final Object obj )
		{
			if( ( obj instanceof StringProperties ) == false )
			{
				return false;
			}

			if( super.equals(obj) == false ) return false;

			StringProperties p = (StringProperties)obj;

			if( this.mFontSize!=p.mFontSize ) return false;
			if( this.mFontStyle!=p.mFontStyle ) return false;
			if( this.mFontName.equals(p.mFontName) == false ) return false;
			if( this.mAngle!=p.mAngle ) return false;

			return true;
		}


		public String getFontName()
		{
			return this.mFontName;
		}
		
		public Float getFontSize()
		{
			return new Float( this.mFontSize );
		}

		public Integer getFontStyle()
		{
			return new Integer( this.mFontStyle );
		}

		public Float getAngle()
		{
			return new Float( this.mAngle );
		}


		public boolean setFontName( final String name )
		{
			this.mFontName = name;
			return true;
		}

		public boolean setFontSize( final float size )
		{
			this.mFontSize = size;
			return true;
		}

		public boolean setFontStyle( final int style )
		{
			this.mFontStyle = style;
			return true;
		}

		public boolean setAngle( final float angle )
		{
			this.mAngle = angle;
			return true;
		}

	
	}


}

