 /***********************************************************************************************
  * File Info: $Id: TextTag.java,v 1.5 2003/03/09 22:42:11 nathaniel_auvil Exp $
  * Copyright (C) 2002
  * Author: John Thomsen
  * Contributor(s): Nathaniel G. Auvil
  *
  * Copyright 2002 (C) Nathaniel G. Auvil. All Rights Reserved.
  *
  * Redistribution and use of this software and associated documentation ("Software"), with or
  * without modification, are permitted provided that the following conditions are met:
  *
  * 1. Redistributions of source code must retain copyright statements and notices.
  * 	Redistributions must also contain a copy of this document.
  *
  * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
  * 	conditions and the following disclaimer in the documentation and/or other materials
  * 	provided with the distribution.
  *
  * 3. The name "jCharts" or "Nathaniel G. Auvil" must not be used to endorse or promote
  * 	products derived from this Software without prior written permission of Nathaniel G.
  * 	Auvil.  For written permission, please contact nathaniel_auvil@users.sourceforge.net
  *
  * 4. Products derived from this Software may not be called "jCharts" nor may "jCharts" appear
  * 	in their names without prior written permission of Nathaniel G. Auvil. jCharts is a
  * 	registered trademark of Nathaniel G. Auvil.
  *
  * 5. Due credit should be given to the jCharts Project (http://jcharts.sourceforge.net/).
  *
  * THIS SOFTWARE IS PROVIDED BY Nathaniel G. Auvil AND CONTRIBUTORS ``AS IS'' AND ANY
  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
  * jCharts OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
  ************************************************************************************************/


package org.jCharts.chartText;


import org.jCharts.test.HTMLGenerator;
import org.jCharts.test.HTMLTestable;
import org.jCharts.chartData.ChartDataException;

import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Hashtable;


public class TextTag implements HTMLTestable, Serializable
{
	//---Strangely, we don't need to store the text itself. (yet)

	private float xPosition = 0;
	private float yPosition = 0;

	private TextLayout textLayout = null;
	private Hashtable attributes = null;

	private boolean isHidden = false;

	//---derived values

	private float width = 0;
	private float height = 0;
	private float fontAscent = 0;
	private float fontDescent = 0;

	private boolean isDerived = false;
	private Font derivedFont= null;

	private String text;   //for toString();
	private Font font;   //for toString();


	/*********************************************************************************************
	 * Default constructor - for untransformed fonts.
	 *
	 **********************************************************************************************/
	public TextTag( String text, Font baseFont, FontRenderContext fontRenderContext )
	{
		this( text, baseFont, null, fontRenderContext );
	}


	/*********************************************************************************************
	 * Constructor when using transformed (derived) fonts
	 *
	 * The need for this arises because the java metrics classes return either 0 or very strange
	 * values for the width and height of a string (TextLayout, LineMetrics, etc..) when
	 * the font is derived
	 *
	 * @param text
	 * @param baseFont is the original (untransformed) font.
	 * @param derivedFont is the transformed font
	 * @param fontRenderContext
	 **********************************************************************************************/
	public TextTag( String text, Font baseFont, Font derivedFont, FontRenderContext fontRenderContext )
	{
		this.textLayout = new TextLayout( text, baseFont, fontRenderContext );

		this.isDerived = (derivedFont != null);
		this.derivedFont= derivedFont;

		//---Dimensions
		this.width = this.textLayout.getAdvance();
		this.height = this.textLayout.getAscent() + this.textLayout.getDescent();

		//---need this to offset font rendering, as rendering is at the baseline not bottom or top,
		this.fontAscent = this.textLayout.getAscent();
		this.fontDescent = this.textLayout.getDescent();

		this.font = (this.isDerived) ? derivedFont : baseFont;
		this.text = text;

//		System.out.println(">"+text+" Bounds:"+textLayout.getBounds() );
//		System.out.println("   >Ascent "+textLayout.getAscent()+" Descent:"+textLayout.getDescent() );
//		System.out.println("   >isVertical "+textLayout.isVertical());
//
//		LineMetrics lm = font.getLineMetrics(text, fontRenderContext);

//		System.out.println("    Metrics:" + lm.getHeight() + " " + lm.getAscent() + lm.getDescent());

	}


	/********************************************************************************************
	 *
	 ********************************************************************************************/
	public float getWidth()
	{
		return this.width;
	}


	/********************************************************************************************
	 *
	 ********************************************************************************************/
	public float getHeight()
	{
		return this.height;
	}


	/********************************************************************************************
	 *
	 ********************************************************************************************/
	public float getFontAscent()
	{
		return this.fontAscent;
	}


	/********************************************************************************************
	 *
	 ********************************************************************************************/
	public float getFontDescent()
	{
		return this.fontDescent;
	}


	/********************************************************************************************
	 *
	 ********************************************************************************************/
	public void setPosition( float x, float y )
	{
		this.xPosition = x;
		this.yPosition = y;

		//System.out.println("TEXT:==>"+text+"< at "+x+","+y);
	}


	/********************************************************************************************
	 *
	 ********************************************************************************************/
	public void setXPosition( float x )
	{
		this.xPosition = x;
	}


	/********************************************************************************************
	 *
	 ********************************************************************************************/
	public void setYPosition( float y )
	{
		this.yPosition = y;
	}


	/********************************************************************************************
	 *
	 ********************************************************************************************/
	public float getXPosition()
	{
		return this.xPosition;
	}


	/********************************************************************************************
	 *
	 ********************************************************************************************/
	public float getYPosition()
	{
		return this.yPosition;
	}


	/********************************************************************************************
	 *
	 ********************************************************************************************/
	public float getRightSide()
	{
		return this.xPosition + this.width;
	}


	/********************************************************************************************
	 *
	 ********************************************************************************************/
	public float getBottomSide()
	{
		return this.yPosition + this.height;
	}


	/********************************************************************************************
	 *
	 ********************************************************************************************/
	public Rectangle2D.Float getRectangle()
	{
		return new Rectangle2D.Float( this.xPosition, this.yPosition, this.width, this.height );
	}


	/********************************************************************************************
	 *
	 ********************************************************************************************/
	public void setHidden( boolean b )
	{
		this.isHidden = b;
	}


	/********************************************************************************************
	 *
	 ********************************************************************************************/
	public boolean getHidden()
	{
		return this.isHidden;
	}


	public String getText()
	{
		return text;
	}


	/********************************************************************************************
	 *
	 ********************************************************************************************/
	public void addAttribute( String name, Object o )
	{
		if( attributes == null )
		{
			attributes = new Hashtable();
		}

		attributes.put( name, o );
	}


	/********************************************************************************************
	 *
	 ********************************************************************************************/
	public Object getAttribute( String name )
	{
		if( attributes == null )
		{
			return null;
		}

		return attributes.get( name );
	}


	/**********************************************************************************************
	 * Renders the text, at the position - renders from the top (instead of baseline)
	 *
	 * @param g2d
	 * @param fontColor
	 **********************************************************************************************/
	public void render( Graphics2D g2d, Paint fontColor )
	{
		if( fontColor != null )
		{
			g2d.setPaint( fontColor );
		}

		if( this.isHidden == false )
		{
			if( isDerived )
			{
				g2d.setFont( this.derivedFont );
				g2d.drawString( this.text, this.xPosition, this.yPosition );
			}
			else
			{
				textLayout.draw( g2d, this.xPosition, this.yPosition );
			}

			//---Debug comparison code.
			//g2d.setFont( this.font );
			//g2d.drawString(this.text, this.xPosition, this.yPosition);

			/* Interesting...
			System.out.println("Ascent:"+this.fontAscent);
			System.out.println("Descent:"+this.fontDescent);
			System.out.println("Height:"+this.heightNeeded);
			System.out.println("Width:"+this.widthNeeded);
			*/
		}
	}


	/**********************************************************************************************
	 * Renders the text, at the position - renders from the top (instead of baseline)
	 *
	 * @param g2d

	 **********************************************************************************************/
	public void render( Graphics2D g2d, float x, float y )
	{
		textLayout.draw( g2d, x, y );

/*

		if( fontColor != null )
		{
			g2d.setPaint( fontColor );
		}

		if( this.isHidden == false )
		{
			if( isDerived )
			{
				g2d.drawString( this.text, x, y );
			}
			else
			{
            textLayout.draw( g2d, x, y );
			}
		}
*/
	}


	/*********************************************************************************************
	 * Enables the testing routines to display the contents of this Object.
	 *
	 * @param htmlGenerator
	 **********************************************************************************************/
	public void toHTML( HTMLGenerator htmlGenerator )
	{
		htmlGenerator.propertiesTableStart( this.getClass().getName() );

		Field[] fields = this.getClass().getDeclaredFields();
		for( int i = 0; i < fields.length; i++ )
		{
			try
			{
				htmlGenerator.addField( fields[ i ].getName(), fields[ i ].get( this ) );
			}
			catch( IllegalAccessException illegalAccessException )
			{
				illegalAccessException.printStackTrace();
			}
		}

		htmlGenerator.propertiesTableEnd();
	}


	/********************************************************************************************
	 *
	 * @return
	 ********************************************************************************************/
	public String toString()
	{
		String str = "TextTag: '" + this.text + "',x=" + this.xPosition + ",y=" + this.yPosition;

		str += "width=" + this.width + ",height=" + this.height;
		str += ",font=" + this.font.getName() + "," + this.font.getSize();

		if( attributes != null && attributes.size() > 0 )
		{
			java.util.Enumeration enum = attributes.keys();
			str += "\nAttributes:";
			while( enum.hasMoreElements() )
			{
				Object ob = enum.nextElement();
				str += "    [" + ob.toString() + "]=[" + attributes.get( ob ).toString() + "]\n";
			}
		}

		return str;
	}
}