/*
 * FSBitmapFill.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 FSBitmapFill class is used to fill a shape with an image.
 * 
 * <p>
 * Two types of bitmap fill are supported:
 * </p>
 * 
 * <table class="datasheet">
 * 
 * <tr>
 * <td>Clipped</td>
 * <td>If the area to be filled is larger than the image then the colour at the
 * edge of the image is used to fill the remainder of the shape.</td>
 * </tr>
 * 
 * <tr>
 * <td>Tiled</td>
 * <td>If the area to be filled is larger than the image then the image is
 * tiled across the area to be filled.</td>
 * </tr>
 * 
 * <tr>
 * <td>Unsmoothed Clipped</td>
 * <td>If the area to be filled is larger than the image then the colour at the
 * edge of the image is used to fill the remainder of the shape.</td>
 * </tr>
 * 
 * <tr>
 * <td>Unsmoothed Tiled</td>
 * <td>If the area to be filled is larger than the image then the image is
 * tiled without smoothing to fill the area.</td>
 * </tr>
 * 
 * 
 * </table>
 * 
 * <p>
 * <!-- Blank paragraph to provide spacing between tables -->
 * </p>
 * 
 * <table class="datasheet">
 * 
 * <tr>
 * <th align="left" colspan="2">Attributes</th>
 * </tr>
 * 
 * <tr>
 * <td>type</td>
 * <td>The type of bitmap fill, either FSFillStyle.Tiled or
 * FSFillStyle.Clipped.</td>
 * </tr>
 * 
 * <tr>
 * <td>identifier</td>
 * <td>The identifier, in the range 1..65535, of the object that contains the
 * image that will be displayed.</td>
 * </tr>
 * 
 * <tr>
 * <td>transform</td>
 * <td>An FSCoordTransform object that defines the coordinate transformation
 * that will be applied to the image, to change its size, location relative to
 * the origin of the shape, orientation, etc., when it is displayed.</td>
 * </tr>
 * 
 * </table>
 * 
 * <p>
 * The type attribute may be used when iterating through an array of fill style
 * objects to identify the type of fill style without using run-time type
 * checking.
 * </p>
 * 
 * <p>
 * When an image is loaded its width and height default to twips rather than
 * pixels. An image 300 x 200 pixels will be displayed as 300 x 200 twips (15 x
 * 10 pixels). Scaling the image by 20 (20 twips = 1 pixel) using the
 * FSCoordTransform object will restore it to its original size.
 * </p>
 * 
 * <p>
 * The image is drawn with the top left corner placed at the origin (0, 0) of
 * the shape being filled. Depending on how the shape is drawn the coordinate
 * transform may also need to specify a translation to place the image at the
 * desired location.
 * </p>
 * 
 * <h1 class="datasheet">When To Use</h1>
 * 
 * <p>
 * In addition to filling shapes with images that represent textures or complex
 * fill patterns the FSBitmapFill class is required to display any image in a
 * Flash file - image can only be displayed in Flash inside a shape definition.
 * The classes that define images only contain the image data, not how it is
 * displayed. To simply display an image, the selected line style of a shape may
 * be set to zero so that the image is displayed without a border.
 * </p>
 * 
 * <h1 class="datasheet">Example</h1>
 * 
 * <p>
 * The following code fragment centres the image in the centre of the shape -
 * assuming the shape is drawn with the origin at the centre. The transform
 * constructor allows the translation and scaling transform to be specified in a
 * single step rather than compositing the transforms.
 * </p>
 * 
 * <pre>
 * FSCoordTransform composite = new FSCoordTransform(-imageWidth / 2,
 * 				-imageHeight / 2, 20.0, 20.0);
 * 
 * fillStyles.add(new FSBitmapFill(FSFillStyle.Clipped, imageId, composite));
 * </pre>
 * 
 * <h1 class="datasheet">History</h1>
 * 
 * <p>
 * The FSBitmapFill class represents the FillStyle structure from the Macromedia
 * Flash (SWF) File Format Specification. It was introduced in Flash 1.
 * </p>
 */
public class FSBitmapFill extends FSFillStyle
{
	private int identifier = 0;
	private FSCoordTransform transform = null;

	/**
	 * Construct an FSBitmapFill object an initialize it with values decoded
	 * from an encoded FSBitmapFill object.
	 * 
	 * @param coder
	 *            an FSCoder object containing an FSBitmapFill encoded as binary
	 *            data.
	 */
	public FSBitmapFill(FSCoder coder)
	{
		decode(coder);
	}

	/**
	 * Constructs an FSBitmapFill object, specifying whether the image is tiled
	 * or clipped within the shape, the identifier of the object containing the
	 * image data and the coordinate transform used to change the appearance of
	 * the image and place it relative to the origin of the shape.
	 * 
	 * @param aType
	 *            the type of bitmap fill, FSFillStyle.Clipped or
	 *            FSFillStyle.Tiled.
	 * 
	 * @param anIdentifier
	 *            the identifier of the object containing the image to be
	 *            displayed.
	 * 
	 * @param aTransform
	 *            an FSCoordTransform object that changes the appearance of the
	 *            image.
	 */
	public FSBitmapFill(int aType, int anIdentifier, FSCoordTransform aTransform)
	{
		super(aType);

		setType(aType);
		setIdentifier(anIdentifier);
		setTransform(aTransform);
	}

	/**
	 * Construct an FSBitmapFill object by copying an existing object.
	 * 
	 * @param obj
	 *            an FSBitmapFill object.
	 */
	public FSBitmapFill(FSBitmapFill obj)
	{
		super(obj.type);
		identifier = obj.identifier;
		transform = new FSCoordTransform(obj.transform);
	}

	/**
	 * Gets the identifier of the object containing the image to be displayed.
	 * 
	 * @return the identifier of the image object to be displayed.
	 */
	public int getIdentifier()
	{
		return identifier;
	}

	/**
	 * Sets the identifier of the object containing the image to be displayed.
	 * 
	 * @param anIdentifier
	 *            the identifier of the object containing the image to be
	 *            displayed.
	 */
	public void setIdentifier(int anIdentifier)
	{
		identifier = anIdentifier;
	}

	/**
	 * Gets the coordinate transform applied to the image.
	 * 
	 * @return the transform that will be applied to the image when it is
	 *         displayed.
	 */
	public FSCoordTransform getTransform()
	{
		return transform;
	}

	/**
	 * Sets the coordinate transform applied to the image to display it inside
	 * the shape.
	 * 
	 * @param aTransform
	 *            an FSCoordTransform object that changes the appearance and
	 *            location of the image inside the shape.
	 */
	public void setTransform(FSCoordTransform aTransform)
	{
		transform = aTransform;
	}

	public Object clone()
	{
		FSBitmapFill anObject = (FSBitmapFill) (super.clone());

		anObject.transform = (transform != null) ? (FSCoordTransform) (transform
						.clone())
						: null;

		return anObject;
	}

	public boolean equals(Object anObject)
	{
		boolean result = false;

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

			result = identifier == typedObject.identifier;

			if (transform != null)
				result = result && transform.equals(typedObject.transform);
			else
				result = result && transform == typedObject.transform;
		}
		return result;
	}

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

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

	public int length(FSCoder coder)
	{
		int length = super.length(coder);

		length += 2;
		length += transform.length(coder);

		return length;
	}

	public void encode(FSCoder coder)
	{
		super.encode(coder);

		coder.writeWord(identifier, 2);
		transform.encode(coder);
	}

	public void decode(FSCoder coder)
	{
		super.decode(coder);

		identifier = coder.readWord(2, false);
		transform = new FSCoordTransform(coder);
	}
}
