/*
	Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
	и других спецификаций для функционирования компактных приложений на языке
	Java (мидлетов) в среде программного обеспечения Малик Эмулятор.

	Copyright © 2016, 2019 Малик Разработчик

	Это свободная программа: вы можете перераспространять ее и/или изменять
	ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
	в каком она была опубликована Фондом свободного программного обеспечения;
	либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

	Эта программа распространяется в надежде, что она будет полезной,
	но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
	или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
	общественной лицензии GNU.

	Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
	вместе с этой программой. Если это не так, см.
	<https://www.gnu.org/licenses/>.
*/


package javax.microedition.lcdui.game;

import javax.microedition.lcdui.*;

public class Sprite extends Layer
{
	public static final int TRANS_NONE = 0;
	public static final int TRANS_ROT90 = 5;
	public static final int TRANS_ROT180 = 3;
	public static final int TRANS_ROT270 = 6;
	public static final int TRANS_MIRROR = 2;
	public static final int TRANS_MIRROR_ROT90 = 7;
	public static final int TRANS_MIRROR_ROT180 = 1;
	public static final int TRANS_MIRROR_ROT270 = 4;

	private static boolean doPixelCollision(int width, int height,
			Image image1, int left1, int top1, int transform1,
			Image image2, int left2, int top2, int transform2)
	{
		int area;
		int i;
		int j;
		int x1;
		int x2;
		int xinc1;
		int xinc2;
		int yinc1;
		int yinc2;
		int startx1;
		int startx2;
		int start1;
		int start2;
		int[] pixels1 = new int[area = width * height];
		int[] pixels2 = new int[area];
		if((transform1 & 0x04) != 0)
		{
			if((transform1 & 0x01) != 0)
			{
				xinc1 = -height;
				start1 = area - height;
			} else
			{
				xinc1 = height;
				start1 = 0;
			}
			if((transform1 & 0x02) != 0)
			{
				yinc1 = -1;
				start1 += height - 1;
			} else
			{
				yinc1 = 1;
			}
			image1.getRGB(pixels1, 0, height, left1, top1, height, width);
		} else
		{
			if((transform1 & 0x01) != 0)
			{
				yinc1 = -width;
				start1 = area - width;
			} else
			{
				yinc1 = width;
				start1 = 0;
			}
			if((transform1 & 0x02) != 0)
			{
				xinc1 = -1;
				start1 += width - 1;
			} else
			{
				xinc1 = 1;
			}
			image1.getRGB(pixels1, 0, width, left1, top1, width, height);
		}
		if((transform2 & 0x04) != 0)
		{
			if((transform2 & 0x01) != 0)
			{
				xinc2 = -height;
				start2 = area - height;
			} else
			{
				xinc2 = height;
				start2 = 0;
			}
			if((transform2 & 0x02) != 0)
			{
				yinc2 = -1;
				start2 += height - 1;
			} else
			{
				yinc2 = 1;
			}
			image2.getRGB(pixels2, 0, height, left2, top2, height, width);
		} else
		{
			if((transform2 & 0x01) != 0)
			{
				yinc2 = -width;
				start2 = area - width;
			} else
			{
				yinc2 = width;
				start2 = 0;
			}
			if((transform2 & 0x02) != 0)
			{
				xinc2 = -1;
				start2 += width - 1;
			} else
			{
				xinc2 = 1;
			}
			image2.getRGB(pixels2, 0, width, left2, top2, width, height);
		}
		startx1 = start1;
		startx2 = start2;
		for(j = height; j-- > 0; startx1 += yinc1, startx2 += yinc2)
		{
			x1 = startx1;
			x2 = startx2;
			for(i = width; i-- > 0; x1 += xinc1, x2 += xinc2)
			{
				if((pixels1[x1] & 0xff000000) != 0 && (pixels2[x2] & 0xff000000) != 0)
				{
					return true;
				}
			}
		}
		return false;
	}

	private static boolean isIntersection(
			int r1Left, int r1Top, int r1Right, int r1Bottom,
			int r2Left, int r2Top, int r2Right, int r2Bottom)
	{
		return r1Left < r2Right && r2Left < r1Right && r1Top < r2Bottom && r2Top < r1Bottom;
	}


	private int collisionRectLeft;
	private int collisionRectTop;
	private int collisionRectWidth;
	private int collisionRectHeight;
	private int transformedCollisionRectLeft;
	private int transformedCollisionRectTop;
	private int transformedCollisionRectWidth;
	private int transformedCollisionRectHeight;
	private int transformation;
	private int refPointX;
	private int refPointY;
	private int framesPerRow;
	private int framesCount;
	private int frameWidth;
	private int frameHeight;
	private int frameIndex;
	private int[] frameSequence;
	private int[] frameSequenceDefault;
	private Image frameSet;
	private Object lock;

	public Sprite(Sprite src)
	{
		super(src != null && src.isVisible(),
				src != null ? src.getX() : 0, src != null ? src.getY() : 0,
				src != null ? src.getWidth() : 0, src != null ? src.getHeight() : 0);
		if(src == null)
		{
			throw new NullPointerException("Sprite: " +
					"параметр src равен нулевой ссылке.");
		}
		synchronized(src.lock)
		{
			this.collisionRectLeft = src.collisionRectLeft;
			this.collisionRectTop = src.collisionRectTop;
			this.collisionRectWidth = src.collisionRectWidth;
			this.collisionRectHeight = src.collisionRectHeight;
			this.transformedCollisionRectLeft = src.transformedCollisionRectLeft;
			this.transformedCollisionRectTop = src.transformedCollisionRectTop;
			this.transformedCollisionRectWidth = src.transformedCollisionRectWidth;
			this.transformedCollisionRectHeight = src.transformedCollisionRectHeight;
			this.transformation = src.transformation;
			this.refPointX = src.refPointX;
			this.refPointY = src.refPointY;
			this.framesPerRow = src.framesPerRow;
			this.framesCount = src.framesCount;
			this.frameWidth = src.frameWidth;
			this.frameHeight = src.frameHeight;
			this.frameIndex = src.frameIndex;
			this.frameSequence = src.frameSequence;
			this.frameSequenceDefault = src.frameSequenceDefault;
			this.frameSet = src.frameSet;
		}
		this.lock = new Object();
	}

	public Sprite(Image frame)
	{
		this(frame, frame != null ? frame.getWidth() : 0, frame != null ? frame.getHeight() : 0);
	}

	public Sprite(Image frameSet, int frameWidth, int frameHeight)
	{
		super(frameWidth, frameHeight);
		int i;
		int fc;
		int tmp;
		int width;
		int height;
		int[] seq;
		if(frameSet == null)
		{
			throw new NullPointerException("Sprite: " +
					"параметр frameSet равен нулевой ссылке.");
		}
		if(frameWidth < 1 || frameHeight < 1)
		{
			throw new IllegalArgumentException("Sprite: " +
					"размеры кадров анимации могут быть только положительными.");
		}
		if((width = frameSet.getWidth()) % frameWidth != 0 ||
				(height = frameSet.getHeight()) % frameHeight != 0)
		{
			throw new IllegalArgumentException("Sprite: " +
					"размеры набора кадров могут только нацело делиться на размеры самих кадров.");
		}
		this.collisionRectWidth = frameWidth;
		this.collisionRectHeight = frameHeight;
		this.transformedCollisionRectWidth = frameWidth;
		this.transformedCollisionRectHeight = frameHeight;
		this.framesPerRow = tmp = width / frameWidth;
		this.framesCount = fc = tmp * (height / frameHeight);
		this.frameWidth = frameWidth;
		this.frameHeight = frameHeight;
		this.frameSequence = seq = new int[fc];
		this.frameSequenceDefault = seq;
		this.frameSet = frameSet;
		this.lock = new Object();
		for(i = fc; i-- > 0; seq[i] = i);
	}

	public void defineCollisionRectangle(int left, int top, int width, int height)
	{
		if(width < 0 || height < 0)
		{
			throw new IllegalArgumentException("Sprite.defineCollisionRectangle: " +
					"размеры области коллизий не могут быть отрицательными.");
		}
		synchronized(lock)
		{
			this.collisionRectLeft = left;
			this.collisionRectTop = top;
			this.collisionRectWidth = width;
			this.collisionRectHeight = height;
			computeTransformedBounds(transformation);
		}
	}

	public void defineReferencePixel(int x, int y)
	{
		synchronized(lock)
		{
			this.refPointX = x;
			this.refPointY = y;
		}
	}

	public void nextFrame()
	{
		synchronized(lock)
		{
			this.frameIndex = (frameIndex + 1) % frameSequence.length;
		}
	}

	public void prevFrame()
	{
		int len;
		synchronized(lock)
		{
			this.frameIndex = (frameIndex + (len = frameSequence.length) - 1) % len;
		}
	}

	public void setFrame(int frameIndex)
	{
		int error = 0;
		synchronized(lock)
		{
			label0:
			{
				if(frameIndex < 0 || frameIndex >= frameSequence.length)
				{
					error = 1;
					break label0;
				}
				this.frameIndex = frameIndex;
			}
		}
		if(error == 1)
		{
			throw new IndexOutOfBoundsException("Sprite.setFrame: " +
					"параметр frameIndex выходит из диапазона.");
		}
	}

	public void setFrameSequence(int[] sequence)
	{
		int i;
		int len;
		int error;
		int frame;
		int framesCount;
		int[] frameSequence;
		if(sequence == null)
		{
			len = 0;
			frameSequence = null;
		} else
		{
			if((len = sequence.length) < 1)
			{
				throw new IllegalArgumentException("Sprite.setFrameSequence: " +
						"параметр sequence может иметь только положительную длину.");
			}
			Array.copy(sequence, 0, frameSequence = new int[len], 0, len);
		}
		error = 0;
		synchronized(lock)
		{
			label0:
			{
				if(frameSequence == null)
				{
					frameSequence = this.frameSequenceDefault;
				} else
				{
					framesCount = this.framesCount;
					for(i = len; i-- > 0; )
					{
						if((frame = frameSequence[i]) < 0 || frame >= framesCount)
						{
							error = 1;
							break label0;
						}
					}
				}
				this.frameSequence = frameSequence;
			}
		}
		if(error == 1)
		{
			throw new ArrayIndexOutOfBoundsException("Sprite.setFrameSequence: " +
					"параметр sequence содержит элементы, выходящие из диапазона.");
		}
	}

	public void setImage(Image frameSet, int frameWidth, int frameHeight)
	{
		int t;
		int x;
		int y;
		int i;
		int fc;
		int tmp;
		int width;
		int height;
		int[] seq;
		if(frameSet == null)
		{
			throw new NullPointerException("Sprite.setImage: " +
					"параметр frameSet равен нулевой ссылке.");
		}
		if(frameWidth < 1 || frameHeight < 1)
		{
			throw new IllegalArgumentException("Sprite.setImage: " +
					"размеры кадров анимации могут быть только положительными.");
		}
		if((width = frameSet.getWidth()) % frameWidth != 0 ||
				(height = frameSet.getHeight()) % frameHeight != 0)
		{
			throw new IllegalArgumentException("Sprite.setImage: " +
					"размеры набора кадров могут только нацело делиться на размеры самих кадров.");
		}
		synchronized(lock)
		{
			if(frameWidth != this.frameWidth || frameHeight != this.frameHeight)
			{
				t = transformation;
				x = getX() + getTransformedPtX(t);
				y = getY() + getTransformedPtY(t);
				this.collisionRectLeft = 0;
				this.collisionRectTop = 0;
				this.collisionRectWidth = frameWidth;
				this.collisionRectHeight = frameHeight;
				this.transformedCollisionRectLeft = 0;
				this.transformedCollisionRectTop = 0;
				if((t & 0x04) != 0)
				{
					this.transformedCollisionRectWidth = frameHeight;
					this.transformedCollisionRectHeight = frameWidth;
					setSize(frameHeight, frameWidth);
				} else
				{
					this.transformedCollisionRectWidth = frameWidth;
					this.transformedCollisionRectHeight = frameHeight;
					setSize(frameWidth, frameHeight);
				}
				this.frameWidth = frameWidth;
				this.frameHeight = frameHeight;
				super.setPosition(x - getTransformedPtX(t), y - getTransformedPtY(t));
			}
			fc = (tmp = width / frameWidth) * (height / frameHeight);
			this.framesPerRow = tmp;
			if(fc == (tmp = framesCount))
			{
				seq = null;
			} else
			{
				seq = new int[fc];
				for(i = fc; i-- > 0; seq[i] = i);
			}
			this.framesCount = fc;
			if(fc < tmp)
			{
				this.frameIndex = 0;
				this.frameSequence = seq;
				this.frameSequenceDefault = seq;
			}
			else if(fc > tmp)
			{
				if(frameSequence == frameSequenceDefault)
				{
					this.frameSequence = seq;
				}
				this.frameSequenceDefault = seq;
			}
			this.frameSet = frameSet;
		}
	}

	public void setRefPixelPosition(int x, int y)
	{
		int transform;
		synchronized(lock)
		{
			transform = this.transformation;
			super.setPosition(x - getTransformedPtX(transform), y - getTransformedPtY(transform));
		}
	}

	public void setTransform(int transform)
	{
		if(transform < 0 || transform > 7)
		{
			throw new IllegalArgumentException("Sprite.setTransform: " +
					"недопустимое значение параметра transform.");
		}
		synchronized(lock)
		{
			setTransformHelper(transform);
		}
	}

	public int getFrameSequenceLength()
	{
		return frameSequence.length;
	}

	public int getRawFrameCount()
	{
		return framesCount;
	}

	public int getRefPixelX()
	{
		int result;
		synchronized(lock)
		{
			result = getX() + getTransformedPtX(transformation);
		}
		return result;
	}

	public int getRefPixelY()
	{
		int result;
		synchronized(lock)
		{
			result = getY() + getTransformedPtY(transformation);
		}
		return result;
	}

	public final void paint(Graphics render)
	{
		int left;
		int top;
		int transformation;
		int framesPerRow;
		int frameWidth;
		int frameHeight;
		int frame;
		Image frameSet;
		if(render == null)
		{
			throw new NullPointerException("Sprite.paint: " +
					"параметр render равен нулевой ссылке.");
		}
		if(!isVisible())
		{
			return;
		}
		synchronized(lock)
		{
			left = getX();
			top = getY();
			transformation = this.transformation;
			framesPerRow = this.framesPerRow;
			frameWidth = this.frameWidth;
			frameHeight = this.frameHeight;
			frame = frameSequence[frameIndex];
			frameSet = this.frameSet;
		}
		render.drawRegion(frameSet,
				(frame % framesPerRow) * frameWidth, (frame / framesPerRow) * frameHeight,
				frameWidth, frameHeight, transformation, left, top, Graphics.LEFT | Graphics.TOP);
	}

	public final boolean collidesWith(Sprite src, boolean pixelLevel)
	{
		boolean result;
		int sprite1Left;
		int sprite1Top;
		int sprite1Right;
		int sprite1Bottom;
		int thisLeft;
		int thisTop;
		int thisRight;
		int thisBottom;
		int sprite2Left;
		int sprite2Top;
		int sprite2Right;
		int sprite2Bottom;
		int srcLeft;
		int srcTop;
		int srcRight;
		int srcBottom;
		int resultLeft;
		int resultTop;
		int resultRight;
		int resultBottom;
		int resultWidth;
		int resultHeight;
		if(src == null)
		{
			throw new NullPointerException("Sprite.collidesWith: " +
					"параметр src равен нулевой ссылке.");
		}
		if((!this.isVisible()) || (!src.isVisible()))
		{
			return false;
		}
		synchronized(this.lock)
		{
			synchronized(src.lock)
			{
				label0:
				{
					sprite1Left = this.getX();
					sprite1Top = this.getY();
					sprite1Right = sprite1Left + this.getWidth();
					sprite1Bottom = sprite1Top + this.getHeight();
					thisLeft = sprite1Left + this.transformedCollisionRectLeft;
					thisTop = sprite1Top + this.transformedCollisionRectTop;
					thisRight = thisLeft + this.transformedCollisionRectWidth;
					thisBottom = thisTop + this.transformedCollisionRectHeight;
					sprite2Left = src.getX();
					sprite2Top = src.getY();
					sprite2Right = sprite2Left + src.getWidth();
					sprite2Bottom = sprite2Top + src.getHeight();
					srcLeft = sprite2Left + src.transformedCollisionRectLeft;
					srcTop = sprite2Top + src.transformedCollisionRectTop;
					srcRight = srcLeft + src.transformedCollisionRectWidth;
					srcBottom = srcTop + src.transformedCollisionRectHeight;
					if(!isIntersection(thisLeft, thisTop, thisRight, thisBottom,
							srcLeft, srcTop, srcRight, srcBottom))
					{
						result = false;
						break label0;
					}
					if(!pixelLevel)
					{
						result = true;
						break label0;
					}
					resultLeft = Math.max(
							Math.max(sprite1Left, thisLeft),
							Math.max(sprite2Left, srcLeft));
					resultTop = Math.max(
							Math.max(sprite1Top, thisTop),
							Math.max(sprite2Top, srcTop));
					resultRight = Math.min(
							Math.min(sprite1Right, thisRight),
							Math.min(sprite2Right, srcRight));
					resultBottom = Math.min(
							Math.min(sprite1Bottom, thisBottom),
							Math.min(sprite2Bottom, srcBottom));
					result = (resultWidth = resultRight - resultLeft) > 0 &&
							(resultHeight = resultBottom - resultTop) > 0 &&
							doPixelCollision(resultWidth, resultHeight, this.frameSet,
							this.getFrameSetLeft(resultLeft, resultTop, resultRight, resultBottom),
							this.getFrameSetTop(resultLeft, resultTop, resultRight, resultBottom),
							this.transformation, src.frameSet,
							src.getFrameSetLeft(resultLeft, resultTop, resultRight, resultBottom),
							src.getFrameSetTop(resultLeft, resultTop, resultRight, resultBottom),
							src.transformation);
				}
			}
		}
		return result;
	}

	public final boolean collidesWith(TiledLayer src, boolean pixelLevel)
	{
		boolean result;
		int spriteLeft;
		int spriteTop;
		int spriteRight;
		int spriteBottom;
		int thisLeft;
		int thisTop;
		int thisRight;
		int thisBottom;
		int srcLeft;
		int srcTop;
		int srcRight;
		int srcBottom;
		int resultLeft;
		int resultTop;
		int resultRight;
		int resultBottom;
		int cellsWidth;
		int cellsHeight;
		int cellLeft;
		int cellTop;
		int cellRight;
		int cellBottom;
		int cellsPerRow;
		int transform;
		int col;
		int row;
		int cell;
		int spriteX;
		int spriteY;
		int tileX;
		int tileY;
		int width;
		int height;
		int delta;
		Image frameSet;
		Image tileSet;
		if(src == null)
		{
			throw new NullPointerException("Sprite.collidesWith: " +
					"параметр src равен нулевой ссылке.");
		}
		if((!this.isVisible()) || (!src.isVisible()))
		{
			return false;
		}
		synchronized(lock)
		{
			synchronized(src.getMonitor())
			{
				label0:
				{
					spriteLeft = getX();
					spriteTop = getY();
					spriteRight = spriteLeft + getWidth();
					spriteBottom = spriteTop + getHeight();
					thisLeft = spriteLeft + transformedCollisionRectLeft;
					thisTop = spriteTop + transformedCollisionRectTop;
					thisRight = thisLeft + transformedCollisionRectWidth;
					thisBottom = thisTop + transformedCollisionRectHeight;
					srcLeft = src.getX();
					srcTop = src.getY();
					srcRight = srcLeft + src.getWidth();
					srcBottom = srcTop + src.getHeight();
					if(!isIntersection(thisLeft, thisTop, thisRight, thisBottom,
							srcLeft, srcTop, srcRight, srcBottom))
					{
						result = false;
						break label0;
					}
					resultLeft = Math.max(Math.max(spriteLeft, thisLeft), srcLeft);
					resultTop = Math.max(Math.max(spriteTop, thisTop), srcTop);
					resultRight = Math.min(Math.min(spriteRight, thisRight), srcRight);
					resultBottom = Math.min(Math.min(spriteBottom, thisBottom), srcBottom);
					if(resultRight - resultLeft <= 0 || resultBottom - resultTop <= 0)
					{
						result = false;
						break label0;
					}
					cellsWidth = src.getCellWidth();
					cellsHeight = src.getCellHeight();
					cellLeft = (resultLeft - srcLeft) / cellsWidth;
					cellTop = (resultTop - srcTop) / cellsHeight;
					cellRight = (resultRight - srcLeft - 1) / cellsWidth;
					cellBottom = (resultBottom - srcTop - 1) / cellsHeight;
					if(!pixelLevel)
					{
						for(row = cellTop; row <= cellBottom; row++)
						{
							for(col = cellLeft; col <= cellRight; col++)
							{
								if(src.getTileIndex(col, row) != 0)
								{
									result = true;
									break label0;
								}
							}
						}
						result = false;
						break label0;
					}
					cellsPerRow = src.getTilesPerRow();
					transform = this.transformation;
					frameSet = this.frameSet;
					tileSet = src.getTileSet();
					for(row = cellTop; row <= cellBottom; row++)
					{
						for(col = cellLeft; col <= cellRight; col++)
						{
							if((cell = src.getTileIndex(col, row)) == 0)
							{
								continue;
							}
							cell--;
							spriteX = srcLeft + col * cellsWidth;
							spriteY = srcTop + row * cellsHeight;
							tileX = (cell % cellsPerRow) * cellsWidth;
							tileY = (cell / cellsPerRow) * cellsHeight;
							width = cellsWidth;
							height = cellsHeight;
							if((delta = resultLeft - spriteX) > 0)
							{
								spriteX += delta;
								tileX += delta;
								width -= delta;
							}
							if((delta = spriteX + width - resultRight) > 0)
							{
								width -= delta;
							}
							if((delta = resultTop - spriteY) > 0)
							{
								spriteY += delta;
								tileY += delta;
								height -= delta;
							}
							if((delta = spriteY + height - resultBottom) > 0)
							{
								height -= delta;
							}
							if(doPixelCollision(width, height, frameSet,
									getFrameSetLeft(spriteX, spriteY,
											width + spriteX, spriteY + height),
									getFrameSetTop(spriteX, spriteY,
											width + spriteX, spriteY + height),
									transform, tileSet, tileX, tileY, TRANS_NONE))
							{
								result = true;
								break label0;
							}
						}
					}
					result = false;
				}
			}
		}
		return result;
	}

	public final boolean collidesWith(Image src, int left, int top, boolean pixelLevel)
	{
		boolean result;
		int spriteLeft;
		int spriteTop;
		int spriteRight;
		int spriteBottom;
		int thisLeft;
		int thisTop;
		int thisRight;
		int thisBottom;
		int srcLeft;
		int srcTop;
		int srcRight;
		int srcBottom;
		int resultLeft;
		int resultTop;
		int resultRight;
		int resultBottom;
		int resultWidth;
		int resultHeight;
		if(src == null)
		{
			throw new NullPointerException("Sprite.collidesWith: " +
					"параметр src равен нулевой ссылке.");
		}
		if(!isVisible())
		{
			return false;
		}
		synchronized(lock)
		{
			label0:
			{
				spriteLeft = getX();
				spriteTop = getY();
				spriteRight = spriteLeft + getWidth();
				spriteBottom = spriteTop + getHeight();
				thisLeft = spriteLeft + transformedCollisionRectLeft;
				thisTop = spriteTop + transformedCollisionRectTop;
				thisRight = thisLeft + transformedCollisionRectWidth;
				thisBottom = thisTop + transformedCollisionRectHeight;
				srcLeft = left;
				srcTop = top;
				srcRight = srcLeft + src.getWidth();
				srcBottom = srcTop + src.getHeight();
				if(!isIntersection(thisLeft, thisTop, thisRight, thisBottom,
						srcLeft, srcTop, srcRight, srcBottom))
				{
					result = false;
					break label0;
				}
				if(!pixelLevel)
				{
					result = true;
					break label0;
				}
				resultLeft = Math.max(Math.max(spriteLeft, thisLeft), srcLeft);
				resultTop = Math.max(Math.max(spriteTop, thisTop), srcTop);
				resultRight = Math.min(Math.min(spriteRight, thisRight), srcRight);
				resultBottom = Math.min(Math.min(spriteBottom, thisBottom), srcBottom);
				result = (resultWidth = resultRight - resultLeft) > 0 &&
						(resultHeight = resultBottom - resultTop) > 0 &&
						doPixelCollision(resultWidth, resultHeight, frameSet,
						getFrameSetLeft(resultLeft, resultTop, resultRight, resultBottom),
						getFrameSetTop(resultLeft, resultTop, resultRight, resultBottom),
						transformation, src, resultLeft - srcLeft, resultTop - srcTop, TRANS_NONE);
			}
		}
		return result;
	}

	public final int getFrame()
	{
		return frameIndex;
	}

	private void setTransformHelper(int newTransform)
	{
		int oldTransform = this.transformation;
		super.move(
				getTransformedPtX(oldTransform) - getTransformedPtX(newTransform),
				getTransformedPtY(oldTransform) - getTransformedPtY(newTransform));
		computeTransformedBounds(newTransform);
		this.transformation = newTransform;
	}

	private void computeTransformedBounds(int transform)
	{
		int fw;
		int fh;
		int crw;
		int crh;
		switch(transform)
		{
		default:
			return;
		case TRANS_NONE:
			transformedCollisionRectLeft = collisionRectLeft;
			transformedCollisionRectTop = collisionRectTop;
			transformedCollisionRectWidth = collisionRectWidth;
			transformedCollisionRectHeight = collisionRectHeight;
			setSize(frameWidth, frameHeight);
			return;
		case TRANS_ROT90:
			transformedCollisionRectLeft = (fh = frameHeight) - (crh = collisionRectHeight) -
					collisionRectTop;
			transformedCollisionRectTop = collisionRectLeft;
			transformedCollisionRectWidth = crh;
			transformedCollisionRectHeight = collisionRectWidth;
			setSize(fh, frameWidth);
			return;
		case TRANS_ROT180:
			transformedCollisionRectLeft = (fw = frameWidth) - (crw = collisionRectWidth) -
					collisionRectLeft;
			transformedCollisionRectTop = (fh = frameHeight) - (crh = collisionRectHeight) -
					collisionRectTop;
			transformedCollisionRectWidth = crw;
			transformedCollisionRectHeight = crh;
			setSize(fw, fh);
			return;
		case TRANS_ROT270:
			transformedCollisionRectLeft = collisionRectTop;
			transformedCollisionRectTop = (fw = frameWidth) - (crw = collisionRectWidth) -
					collisionRectLeft;
			transformedCollisionRectWidth = collisionRectHeight;
			transformedCollisionRectHeight = crw;
			setSize(frameHeight, fw);
			return;
		case TRANS_MIRROR:
			transformedCollisionRectLeft = (fw = frameWidth) - (crw = collisionRectWidth) -
					collisionRectLeft;
			transformedCollisionRectTop = collisionRectTop;
			transformedCollisionRectWidth = crw;
			transformedCollisionRectHeight = collisionRectHeight;
			setSize(fw, frameHeight);
			return;
		case TRANS_MIRROR_ROT90:
			transformedCollisionRectLeft = (fh = frameHeight) - (crh = collisionRectHeight) -
					collisionRectTop;
			transformedCollisionRectTop = (fw = frameWidth) - (crw = collisionRectWidth) -
					collisionRectLeft;
			transformedCollisionRectWidth = crh;
			transformedCollisionRectHeight = crw;
			setSize(fh, fw);
			return;
		case TRANS_MIRROR_ROT180:
			transformedCollisionRectLeft = collisionRectLeft;
			transformedCollisionRectTop = (fh = frameHeight) - (crh = collisionRectHeight) -
					collisionRectTop;
			transformedCollisionRectWidth = collisionRectWidth;
			transformedCollisionRectHeight = crh;
			setSize(frameWidth, fh);
			return;
		case TRANS_MIRROR_ROT270:
			transformedCollisionRectLeft = collisionRectTop;
			transformedCollisionRectTop = collisionRectLeft;
			transformedCollisionRectWidth = collisionRectHeight;
			transformedCollisionRectHeight = collisionRectWidth;
			setSize(frameHeight, frameWidth);
			return;
		}
	}

	private int getTransformedPtX(int transform)
	{
		switch(transform)
		{
		default:
			return 0;
		case TRANS_NONE:
		case TRANS_MIRROR_ROT180:
			return refPointX;
		case TRANS_ROT90:
		case TRANS_MIRROR_ROT90:
			return frameHeight - refPointY - 1;
		case TRANS_ROT180:
		case TRANS_MIRROR:
			return frameWidth - refPointX - 1;
		case TRANS_ROT270:
		case TRANS_MIRROR_ROT270:
			return refPointY;
		}
	}

	private int getTransformedPtY(int transform)
	{
		switch(transform)
		{
		default:
			return 0;
		case TRANS_NONE:
		case TRANS_MIRROR:
			return refPointY;
		case TRANS_ROT90:
		case TRANS_MIRROR_ROT270:
			return refPointX;
		case TRANS_ROT180:
		case TRANS_MIRROR_ROT180:
			return frameHeight - refPointY - 1;
		case TRANS_ROT270:
		case TRANS_MIRROR_ROT90:
			return frameWidth - refPointX - 1;
		}
	}

	private int getFrameSetLeft(int left, int top, int right, int bottom)
	{
		int result;
		switch(transformation)
		{
		default:
			return 0;
		case TRANS_NONE:
		case TRANS_MIRROR_ROT180:
			result = left - getX();
			break;
		case TRANS_ROT90:
		case TRANS_MIRROR_ROT270:
			result = top - getY();
			break;
		case TRANS_ROT180:
		case TRANS_MIRROR:
			result = getX() + getWidth() - right;
			break;
		case TRANS_ROT270:
		case TRANS_MIRROR_ROT90:
			result = getY() + getHeight() - bottom;
			break;
		}
		return result + (frameSequence[frameIndex] % framesPerRow) * frameWidth;
	}

	private int getFrameSetTop(int left, int top, int right, int bottom)
	{
		int result;
		switch(transformation)
		{
		default:
			return 0;
		case TRANS_NONE:
		case TRANS_MIRROR:
			result = top - getY();
			break;
		case TRANS_ROT90:
		case TRANS_MIRROR_ROT90:
			result = getX() + getWidth() - right;
			break;
		case TRANS_ROT180:
		case TRANS_MIRROR_ROT180:
			result = getY() + getHeight() - bottom;
			break;
		case TRANS_ROT270:
		case TRANS_MIRROR_ROT270:
			result = left - getX();
			break;
		}
		return result + (frameSequence[frameIndex] / framesPerRow) * frameHeight;
	}
}
