/*******************************************************************************
 * Copyright (c) 2000, 2008 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.swt.graphics;

import org.eclipse.swt.SWT;

import intrinsic.Class;
import intrinsic.flash.display.BitmapData;
import intrinsic.flash.utils.ByteArray;

public final class Cursor extends Resource {
	public Class object;
	public BitmapData bitmap;
	public int hotspotX, hotspotY;
	public boolean wait;
	
	/**
	 * data used to create a HAND cursor.
	 */
	static final int HAND_X = 5, HAND_Y = 0, HAND_WIDTH = 32, HAND_HEIGHT = 16; 
	static final byte[] HAND_SOURCE = {
		(byte)0xf9,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xf0,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xf0,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xf0,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xf0,(byte)0x3f,(byte)0xff,(byte)0xff,
		(byte)0xf0,(byte)0x07,(byte)0xff,(byte)0xff,
		(byte)0xf0,(byte)0x03,(byte)0xff,(byte)0xff,
		(byte)0xf0,(byte)0x00,(byte)0xff,(byte)0xff,

		(byte)0x10,(byte)0x00,(byte)0x7f,(byte)0xff,
		(byte)0x00,(byte)0x00,(byte)0x7f,(byte)0xff,
		(byte)0x80,(byte)0x00,(byte)0x7f,(byte)0xff,
		(byte)0xc0,(byte)0x00,(byte)0x7f,(byte)0xff,
		(byte)0xe0,(byte)0x00,(byte)0x7f,(byte)0xff,
		(byte)0xf0,(byte)0x00,(byte)0x7f,(byte)0xff,
		(byte)0xf8,(byte)0x00,(byte)0xff,(byte)0xff,
		(byte)0xfc,(byte)0x01,(byte)0xff,(byte)0xff,
	};
	static final byte[] HAND_MASK = {
		(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
		(byte)0x06,(byte)0x00,(byte)0x00,(byte)0x00,
		(byte)0x06,(byte)0x00,(byte)0x00,(byte)0x00,
		(byte)0x06,(byte)0x00,(byte)0x00,(byte)0x00,
		(byte)0x06,(byte)0x00,(byte)0x00,(byte)0x00,
		(byte)0x06,(byte)0xc0,(byte)0x00,(byte)0x00,
		(byte)0x06,(byte)0xd8,(byte)0x00,(byte)0x00,
		(byte)0x06,(byte)0xd8,(byte)0x00,(byte)0x00,

		(byte)0x07,(byte)0xdb,(byte)0x00,(byte)0x00,
		(byte)0x67,(byte)0xfb,(byte)0x00,(byte)0x00,
		(byte)0x3f,(byte)0xff,(byte)0x00,(byte)0x00,
		(byte)0x1f,(byte)0xff,(byte)0x00,(byte)0x00,
		(byte)0x0f,(byte)0xff,(byte)0x00,(byte)0x00,
		(byte)0x07,(byte)0xff,(byte)0x00,(byte)0x00,
		(byte)0x03,(byte)0xfe,(byte)0x00,(byte)0x00,
		(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
	};
	
	/**
	 * data used to create a IBEAM cursor.
	 */
	static final int IBEAM_X = 3, IBEAM_Y = 8, IBEAM_WIDTH = 32, IBEAM_HEIGHT = 16; 
	static final byte[] IBEAM_SOURCE = {
		(byte)0x11,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xef,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xef,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xef,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xef,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xef,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xef,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xef,(byte)0xff,(byte)0xff,(byte)0xff,

		(byte)0xef,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xef,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xef,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xef,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xef,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xef,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xef,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0x11,(byte)0xff,(byte)0xff,(byte)0xff,
	};
	
	/**
	 * data used to create a SIZEE and SIZEW cursor.
	 */
	static final int SIZEE_X = 10, SIZEE_Y = 10, SIZEE_WIDTH = 32, SIZEE_HEIGHT = 20; 
	static final byte[] SIZEE_SOURCE = {
		(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xef,(byte)0xfe,(byte)0xff,(byte)0xff,		
		(byte)0xcf,(byte)0xfe,(byte)0x7f,(byte)0xff,
		
		(byte)0x8f,(byte)0xfe,(byte)0x3f,(byte)0xff,
		(byte)0x00,(byte)0x00,(byte)0x1f,(byte)0xff,
		(byte)0x8f,(byte)0xfe,(byte)0x3f,(byte)0xff,
		(byte)0xcf,(byte)0xfe,(byte)0x7f,(byte)0xff,
		(byte)0xef,(byte)0xfe,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,

		(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
	};
	
	/**
	 * data used to create a SIZES and SIZEN cursor.
	 */
	static final int SIZES_X = 10, SIZES_Y = 10, SIZES_WIDTH = 32, SIZES_HEIGHT = 20; 
	static final byte[] SIZES_SOURCE = {
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0x1f,(byte)0xff,(byte)0xff,
		(byte)0xfe,(byte)0x0f,(byte)0xff,(byte)0xff,
		(byte)0xfc,(byte)0x07,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,		
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xfc,(byte)0x07,(byte)0xff,(byte)0xff,

		(byte)0xfe,(byte)0x0f,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0x1f,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
	};
	
	/**
	 * data used to create a SIZEALL cursor.
	 */
	static final int SIZEALL_X = 10, SIZEALL_Y = 10, SIZEALL_WIDTH = 32, SIZEALL_HEIGHT = 20; 
	static final byte[] SIZEALL_SOURCE = {
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0x1f,(byte)0xff,(byte)0xff,
		(byte)0xfe,(byte)0x0f,(byte)0xff,(byte)0xff,
		(byte)0xfc,(byte)0x07,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xef,(byte)0xbe,(byte)0xff,(byte)0xff,		
		(byte)0xcf,(byte)0xbe,(byte)0x7f,(byte)0xff,
		
		(byte)0x8f,(byte)0xbe,(byte)0x3f,(byte)0xff,
		(byte)0x00,(byte)0x00,(byte)0x1f,(byte)0xff,
		(byte)0x8f,(byte)0xbe,(byte)0x3f,(byte)0xff,
		(byte)0xcf,(byte)0xbe,(byte)0x7f,(byte)0xff,
		(byte)0xef,(byte)0xbe,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xfc,(byte)0x07,(byte)0xff,(byte)0xff,

		(byte)0xfe,(byte)0x0f,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0x1f,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
	};
	
	/**
	 * data used to create a SIZENW cursor.
	 */
	static final int SIZENW_X = 7, SIZENW_Y = 7, SIZENW_WIDTH = 32, SIZENW_HEIGHT = 16; 
	static final byte[] SIZENW_SOURCE = {
		(byte)0x07,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0x0f,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0x1f,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0x2f,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0x77,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xfb,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xfd,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xfe,(byte)0xff,(byte)0xff,(byte)0xff,

		(byte)0xff,(byte)0x77,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xa7,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xc7,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0x87,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0x07,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
	};	
	
	/**
	 * data used to create a SIZENW cursor.
	 */
	static final int SIZENE_X = 7, SIZENE_Y = 7, SIZENE_WIDTH = 32, SIZENE_HEIGHT = 16; 
	static final byte[] SIZENE_SOURCE = {
		(byte)0xff,(byte)0x07,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0x87,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xc7,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xa7,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0x77,(byte)0xff,(byte)0xff,
		(byte)0xfe,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xfd,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xfb,(byte)0xff,(byte)0xff,(byte)0xff,

		(byte)0x77,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0x2f,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0x1f,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0x0f,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0x07,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
	};
	
	/**
	 * data used to create a CROSS cursor.
	 */
	static final int CROSS_X = 10, CROSS_Y = 10, CROSS_WIDTH = 32, CROSS_HEIGHT = 20; 
	static final byte[] CROSS_SOURCE = {
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,

		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0x00,(byte)0x00,(byte)0x1f,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,
		(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
	};

public Cursor (Device device, int style) {
	super(device);
	int width = 0, height = 0;
	int hotspotX = 0, hotspotY = 0;
	byte[] source = null, mask = null;
	switch (style) {
		case SWT.CURSOR_HAND:
			source = HAND_SOURCE;
			mask = HAND_MASK;
			hotspotX = HAND_X;
			hotspotY = HAND_Y;
			width = HAND_WIDTH;
			height = HAND_HEIGHT;
			break;
		case SWT.CURSOR_ARROW:
			break;
		case SWT.CURSOR_WAIT:
			wait = true;
			break;
		case SWT.CURSOR_CROSS:
			source = CROSS_SOURCE;
			hotspotX = CROSS_X;
			hotspotY = CROSS_Y;
			width = CROSS_WIDTH;
			height = CROSS_HEIGHT;
			break;
		case SWT.CURSOR_APPSTARTING:
			break;
		case SWT.CURSOR_HELP:
			break;
		case SWT.CURSOR_SIZEALL:
		case SWT.CURSOR_SIZENESW:
		case SWT.CURSOR_SIZENWSE:
			source = SIZEALL_SOURCE;
			hotspotX = SIZEALL_X;
			hotspotY = SIZEALL_Y;
			width = SIZEALL_WIDTH;
			height = SIZEALL_HEIGHT;
			break;
		case SWT.CURSOR_SIZENS:
		case SWT.CURSOR_SIZEN:
		case SWT.CURSOR_SIZES:
			source = SIZES_SOURCE;
			hotspotX = SIZES_X;
			hotspotY = SIZES_Y;
			width = SIZES_WIDTH;
			height = SIZES_HEIGHT;
			break;
		case SWT.CURSOR_SIZEWE:
		case SWT.CURSOR_SIZEE:
		case SWT.CURSOR_SIZEW:
			source = SIZEE_SOURCE;
			hotspotX = SIZEE_X;
			hotspotY = SIZEE_Y;
			width = SIZEE_WIDTH;
			height = SIZEE_HEIGHT;
			break;
		case SWT.CURSOR_SIZENE:
		case SWT.CURSOR_SIZESE:
			source = SIZENE_SOURCE;
			hotspotX = SIZENE_X;
			hotspotY = SIZENE_Y;
			width = SIZENE_WIDTH;
			height = SIZENE_HEIGHT;
			break;
		case SWT.CURSOR_SIZESW:
		case SWT.CURSOR_SIZENW:
			source = SIZENW_SOURCE;
			hotspotX = SIZENW_X;
			hotspotY = SIZENW_Y;
			width = SIZENW_WIDTH;
			height = SIZENW_HEIGHT;
			break;
		case SWT.CURSOR_UPARROW:
			break;
		case SWT.CURSOR_IBEAM:
			source = IBEAM_SOURCE;
			hotspotX = IBEAM_X;
			hotspotY = IBEAM_Y;
			width = IBEAM_WIDTH;
			height = IBEAM_HEIGHT;
			break;
		case SWT.CURSOR_NO:
			break;
		default:
			SWT.error(SWT.ERROR_INVALID_ARGUMENT);
	}
	if (source != null) {
		byte[] data = new byte[width * height * 4];
		for (int y = 0; y < height; y++) {
			int offset = y * width * 4;
			for (int x = 0; x < width; x++) {
				int index = (y * 4) + (x >> 3), masking = 1 << (7 - (x & 0x7));
				int pixel = ((source[index] & 0xFF) & masking) == 0 ? 0 : 1;
				int maskPixel = mask == null || ((mask[index] & 0xFF) & masking) == 0 ? 0 : 1;
				if (pixel == 0 && maskPixel == 0) {
					// BLACK
					data[offset] = (byte)0xFF;
				} else if (pixel == 0 && maskPixel == 1) {
					// WHITE - cursor color
					data[offset] = data[offset + 1] = data[offset + 2] = data[offset + 3] = (byte)0xFF;
				} else if (pixel == 1 && maskPixel == 0) {
					// SCREEN
				} else {
					// REVERSE SCREEN -> SCREEN
				}
				offset += 4;
			}
		}
		this.hotspotX = hotspotX;
		this.hotspotY = hotspotY;
		createBitmap(data, width, height);
	}
	init();
}

public Cursor (Device device, ImageData source, ImageData mask, int hotspotX, int hotspotY) {
	super(device);
	if (source == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
	if (mask == null) {
		if (source.getTransparencyType() != SWT.TRANSPARENCY_MASK) {
			SWT.error(SWT.ERROR_NULL_ARGUMENT);
		}
		mask = source.getTransparencyMask();
	}
	/* Check the bounds. Mask must be the same size as source */
	if (mask.width != source.width || mask.height != source.height) {
		SWT.error(SWT.ERROR_INVALID_ARGUMENT);
	}
	/* Check the hotspots */
	if (hotspotX >= source.width || hotspotX < 0 ||
		hotspotY >= source.height || hotspotY < 0) {
		SWT.error(SWT.ERROR_INVALID_ARGUMENT);
	}
	byte[] data = new byte[source.width * source.height * 4];
	for (int y = 0; y < source.height; y++) {
		int offset = y * source.width * 4;
		for (int x = 0; x < source.width; x++) {
			int pixel = source.getPixel(x, y);
			int maskPixel = mask.getPixel(x, y);
			if (pixel == 0 && maskPixel == 0) {
				// BLACK
				data[offset] = (byte)0xFF;
			} else if (pixel == 0 && maskPixel == 1) {
				// WHITE - cursor color
				data[offset] = data[offset + 1] = data[offset + 2] = data[offset + 3] = (byte)0xFF;
			} else if (pixel == 1 && maskPixel == 0) {
				// SCREEN
			} else {
				// REVERSE SCREEN -> SCREEN
			}
			offset += 4;
		}
	}
	this.hotspotX = hotspotX;
	this.hotspotY = hotspotY;
	createBitmap(data, source.width, source.height);
	init();
}

public Cursor (Device device, ImageData source, int hotspotX, int hotspotY) {
	super(device);
	if (source == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
	if (hotspotX >= source.width || hotspotX < 0 ||
		hotspotY >= source.height || hotspotY < 0) {
		SWT.error(SWT.ERROR_INVALID_ARGUMENT);
	}
	if (source == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
	this.hotspotX = hotspotX;
	this.hotspotY = hotspotY;
	PaletteData palette = source.palette;
	if (!(((source.depth == 1 || source.depth == 2 || source.depth == 4 || source.depth == 8) && !palette.isDirect) ||
		((source.depth == 8) || (source.depth == 16 || source.depth == 24 || source.depth == 32) && palette.isDirect)))
			SWT.error (SWT.ERROR_UNSUPPORTED_DEPTH);
	int width = source.width;
	int height = source.height;
	
	byte[] buffer = new byte[width * 4 * height];
	if (palette.isDirect) {
		ImageData.blit(ImageData.BLIT_SRC,
			source.data, source.depth, source.bytesPerLine, source.getByteOrder(), 0, 0, width, height, palette.redMask, palette.greenMask, palette.blueMask,
			ImageData.ALPHA_OPAQUE, null, 0, 0, 0, 
			buffer, 32, width * 4, ImageData.MSB_FIRST, 0, 0, width, height, 0xFF0000, 0xFF00, 0xFF,
			false, false);
	} else {
		RGB[] rgbs = palette.getRGBs();
		int length = rgbs.length;
		byte[] srcReds = new byte[length];
		byte[] srcGreens = new byte[length];
		byte[] srcBlues = new byte[length];
		for (int i = 0; i < rgbs.length; i++) {
			RGB rgb = rgbs[i];
			if (rgb == null) continue;
			srcReds[i] = (byte)rgb.red;
			srcGreens[i] = (byte)rgb.green;
			srcBlues[i] = (byte)rgb.blue;
		}
		ImageData.blit(ImageData.BLIT_SRC,
			source.data, source.depth, source.bytesPerLine, source.getByteOrder(), 0, 0, width, height, srcReds, srcGreens, srcBlues,
			ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
			buffer, 32, width * 4, ImageData.MSB_FIRST, 0, 0, width, height, 0xFF0000, 0xFF00, 0xFF,
			false, false);
	}
	
	/* Initialize transparency */
	int transparency = source.getTransparencyType(); 
	if (transparency == SWT.TRANSPARENCY_MASK || source.transparentPixel != -1) {
		ImageData maskImage = source.getTransparencyMask();
		byte[] maskData = maskImage.data;
		int maskBpl = maskImage.bytesPerLine;
		int offset = 0, maskOffset = 0;
		for (int y = 0; y<height; y++) {
			for (int x = 0; x<width; x++) {
				buffer[offset] = ((maskData[maskOffset + (x >> 3)]) & (1 << (7 - (x & 0x7)))) != 0 ? (byte)0xff : 0;
				offset += 4;
			}
			maskOffset += maskBpl;
		}
	} else {
		if (source.alpha != -1) {
			byte a = (byte)source.alpha;
			for (int dataIndex=0; dataIndex<buffer.length; dataIndex+=4) {
				buffer[dataIndex] = a;				
			}
		} else if (source.alphaData != null) {
			int offset = 0, alphaOffset = 0;
			for (int y = 0; y<height; y++) {
				for (int x = 0; x<width; x++) {
					buffer[offset] = source.alphaData[alphaOffset];
					offset += 4;
					alphaOffset += 1;
				}
			}
		} else {
			for (int dataIndex=0; dataIndex<buffer.length; dataIndex+=4) {
				buffer[dataIndex] = (byte)0xff;				
			}
		}		
	}

	createBitmap(buffer, width, height);
	init();
}

void createBitmap(byte[] buffer, int width, int height) {
	BitmapData object = new BitmapData(width, height, true, 0xFFFFFFFF);
	if (object == null) SWT.error(SWT.ERROR_NO_HANDLES);
	bitmap = object;
	intrinsic.flash.geom.Rectangle rect = new intrinsic.flash.geom.Rectangle(0, 0, width, height);
	object.setPixels(rect, getArray(buffer));
}

void destroy () {
	object = null;
	bitmap = null;
}

public boolean equals (Object object) {
	if (object == this) return true;
	if (!(object instanceof Cursor)) return false;
	Cursor cursor = (Cursor) object;
	return device == cursor.device && object == cursor.object;
}

native ByteArray getArray(byte[] array)/*{
	return ByteArray(array.array);
}*/;

public int hashCode () {
	return super.hashCode();
}

public boolean isDisposed () {
	return device == null;
}

public String toString () {
	if (isDisposed()) return "Cursor {*DISPOSED*}";
	return "Cursor {" + 1 + "}";
}

}
