/*
 * FSCharacter.java
 * Transform
 * 
 * Copyright (c) 2001-2008 Flagstone Software Ltd. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *  * 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.
 *  * Neither the name of Flagstone Software Ltd. nor the names of its contributors 
 *    may be used to endorse or promote products derived from this software 
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
 * ANY EXPRESS 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 THE COPYRIGHT OWNER OR 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 com.flagstone.transform;

/**
 * The FSCharacter class is used to identify the glyph that is displayed for a
 * given character in a line of text.
 * 
 * <p>
 * The spacing to the next character is also defined.
 * </p>
 * 
 * <table class="datasheet">
 * 
 * <tr>
 * <th align="left" colspan="2">Attributes</th>
 * </tr>
 * 
 * <tr>
 * <td>glyphIndex</td>
 * <td>An index into the array of FSShape objects that define the glyphs for a
 * given font.</td>
 * </tr>
 * 
 * <tr>
 * <td>advance</td>
 * <td>The distance, in twips, from the origin of the glyph representing the
 * current character to the next glyph to be displayed.</td>
 * </tr>
 * </table>
 * 
 * <p>
 * A single lines of text is displayed using an FSText object which contains an
 * array of FSCharacter objects. Blocks of text can be created by combining one
 * or more FSText objects. The size, colour and relative position of each line
 * within the block is defined by the FSText object. The FSText objects are
 * added to an FSDefineText object or an FSDefineText2 object (which supports
 * transparent colours) which is then used to define the final size and
 * orientation of the text when it is placed on the Display List.
 * </p>
 * 
 * <h1 class="datasheet">Example</h1>
 * 
 * <p>
 * This greatly simplified example illustrates how text strings are created.
 * First the array of glyphs for each character is defined.
 * </p>
 * 
 * <pre>
 *  ArrayList alphabet = new ArrayList();
 * 
 *  FSShape space = new Shape(...);  // Glyph for ' '
 *  FSShape a = new Shape(...);      // Glyph for 'a'
 *  FSShape b = new Shape(...);      // Glyph for 'b'
 *  ...
 *  FSShape z = new Shape(...);      // Glyph for 'z'
 * 
 *  alphabet.add(space);
 *  alphabet.add(a);
 *  alphabet.add(b);
 *  ...
 *  alphabet.add(z);
 * 
 *  // Create the font containing the glyphs for each character
 *  movie.add(new FSDefineFont(movie.newIdentifier(), alphabet));
 * </pre>
 * 
 * <p>
 * Now created the array of FSCharacter objects representing 'a string' Assume
 * the font is a fixed width such as Courier and the spacing between characters
 * is 160 twips - 8 pixels.
 * </p>
 * 
 * <pre>
 * ArrayList characters = new ArrayList();
 * 
 * characters.add(new FSCharacter(1, 120)); // 'a'
 * characters.add(new FSCharacter(0, 120)); // ' '
 * characters.add(new FSCharacter(19, 120)); // 's'
 * characters.add(new FSCharacter(10, 120)); // 't'
 * characters.add(new FSCharacter(18, 120)); // 'r'
 * characters.add(new FSCharacter(9, 120)); // 'i'
 * characters.add(new FSCharacter(14, 120)); // 'n'
 * characters.add(new FSCharacter(6, 120)); // 'g'
 * 
 * FSText string = new FSText(characters);
 * </pre>
 * 
 * <p>
 * It should be immediately clear that creating strings and font definitions
 * from scratch is a huge task requiring knowledge of drawing glyphs and how to
 * layout glyphs to generate aesthetically pleasing text. Transform is a
 * low-level library and such complicated code should be avoided at all costs.
 * Fortunately it is 'relatively' easy to use convert existing font definitions
 * such as those encoded in True Type Font files to into the font and text
 * definition objects that can be used to create Flash files. Another useful
 * approach is to use an existing font definition from a Flash file to obtain
 * the glyph definitions, character codes and advance information.
 * </p>
 * 
 * <p>
 * Creating such font and text definitions is outside the scope of the
 * documentation for this library. However refer to the Transform Utilities
 * framework for Transform available on Flagstone Software's web site for ways
 * to perform these tasks.
 * </p>
 * 
 * <h1 class="datasheet">History</h1>
 * 
 * <p>
 * The FSCharacter class represents the GlyphEntry structure from Macromedia
 * Flash (SWF) File Format Specification. It was introduced in Flash 1.
 * </p>
 */
public class FSCharacter extends FSTransformObject
{
	private int glyphIndex = 0;
	private int advance = 0;

	/**
	 * Construct an FSCharacter object, initalizing it with values decoded from
	 * an encoded object.
	 * 
	 * @param coder
	 *            an FSCoder containing the binary data.
	 */
	public FSCharacter(FSCoder coder)
	{
		decode(coder);
	}

	/**
	 * Constructs an FSCharacter specifying the index of the glyph to be
	 * displayed and the spacing to the next glyph.
	 * 
	 * @param anIndex
	 *            the index into the array of FSShapes in a font definition
	 *            object that defines the glyph that represents the character to
	 *            be displayed.
	 * 
	 * @param anAdvance
	 *            the relative position in twips, from the origin of the glyph
	 *            representing this character to the next glyph to be displayed.
	 */
	public FSCharacter(int anIndex, int anAdvance)
	{
		setGlyphIndex(anIndex);
		setAdvance(anAdvance);
	}

	/**
	 * Constructs an FSCharacter object by copying values from an existing
	 * object.
	 * 
	 * @param obj
	 *            an FSCharacter object.
	 */
	public FSCharacter(FSCharacter obj)
	{
		glyphIndex = obj.glyphIndex;
		advance = obj.advance;
	}

	/**
	 * Gets the index of the glyph, in a font definition object, that will
	 * displayed to represent this character.
	 * 
	 * @return the index of the glyph that represents the character to be
	 *         displayed.
	 */
	public int getGlyphIndex()
	{
		return glyphIndex;
	}

	/**
	 * Gets the spacing in twips between the glyph representing this character
	 * and the next.
	 * 
	 * @return the distance in twips to the next glyph.
	 */
	public int getAdvance()
	{
		return advance;
	}

	/**
	 * Sets the index of the glyph, contained in the array of FSShape object
	 * contained in a font definition object, that represents the character to
	 * be displayed.
	 * 
	 * @param anIndex
	 *            the index of the glyph that represents the character to be
	 *            displayed.
	 */
	public void setGlyphIndex(int anIndex)
	{
		glyphIndex = anIndex;
	}

	/**
	 * Sets the spacing in twips between the glyph representing this character
	 * and the next glyph to be displayed.
	 * 
	 * @param aNumber
	 *            the relative position in twips from the origin of the glyph
	 *            representing this character to the next glyph.
	 */
	public void setAdvance(int aNumber)
	{
		advance = aNumber;
	}

	/**
	 * Returns true if anObject is equal to this one. Objects are considered
	 * equal if they would generate identical binary data when they are encoded
	 * to a Flash file.
	 * 
	 * @return true if this object would be identical to anObject when encoded.
	 */
	public boolean equals(Object anObject)
	{
		boolean result = false;

		if (super.equals(anObject))
		{
			FSCharacter typedObject = (FSCharacter) anObject;

			result = glyphIndex == typedObject.glyphIndex;
			result = result && advance == typedObject.advance;
		}
		return result;
	}

	public void appendDescription(StringBuffer buffer, int depth)
	{
		buffer.append(name());

		if (depth > 0)
		{
			buffer.append(": { ");
			Transform.append(buffer, "glyphIndex", glyphIndex);
			Transform.append(buffer, "advance", advance);
			buffer.append("}");
		}
	}

	public int length(FSCoder coder)
	{
		int numberOfGlyphBits = coder.context[FSCoder.NumberOfGlyphBits];
		int numberOfAdvanceBits = coder.context[FSCoder.NumberOfAdvanceBits];

		return numberOfGlyphBits + numberOfAdvanceBits;
	}

	public void encode(FSCoder coder)
	{
		coder.writeBits(glyphIndex, coder.context[FSCoder.NumberOfGlyphBits]);
		coder.writeBits(advance, coder.context[FSCoder.NumberOfAdvanceBits]);
	}

	public void decode(FSCoder coder)
	{
		int numberOfGlyphBits = coder.context[FSCoder.NumberOfGlyphBits];
		int numberOfAdvanceBits = coder.context[FSCoder.NumberOfAdvanceBits];

		glyphIndex = coder.readBits(numberOfGlyphBits, false);
		advance = coder.readBits(numberOfAdvanceBits, true);
	}
}
