/*******************************************************************************
 * 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.*;

import intrinsic.Array;
import intrinsic.flash.system.Capabilities;

public abstract class Device implements Drawable {
	
	/* Debugging */
	public static boolean DEBUG;
	boolean debug = DEBUG;
	boolean tracking = DEBUG;
	Error [] errors;
	Object [] objects;
	Object trackingLock;
	
	boolean disposed;
	Font systemFont;
	
	/*
	* TEMPORARY CODE. When a graphics object is
	* created and the device parameter is null,
	* the current Display is used. This presents
	* a problem because SWT graphics does not
	* reference classes in SWT widgets. The correct
	* fix is to remove this feature. Unfortunately,
	* too many application programs rely on this
	* feature.
	*
	* This code will be removed in the future.
	*/
	protected static Device CurrentDevice;
	protected static Runnable DeviceFinder;
	static {
		try {
			Class.forName ("org.eclipse.swt.widgets.Display"); //$NON-NLS-1$
		} catch (Throwable e) {}
	}
	
/*
* TEMPORARY CODE.
*/
static synchronized Device getDevice () {
	if (DeviceFinder != null) DeviceFinder.run();
	Device device = CurrentDevice;	
	CurrentDevice = null;
	return device;
}

public Device () {
	this(null);
}

public Device (DeviceData data) {
	synchronized (Device.class) {
		if (data != null) {
			debug = data.debug;
			tracking = data.tracking;
		}
		create (data);
		init ();
		if (tracking) {
			errors = new Error [128];
			objects = new Object [128];
			trackingLock = new Object ();
		}
		
		/* Initialize the system font slot */
		systemFont = Font.flex_new(this, "_sans", "normal", "normal", 12 * 96 / 72);
	}
}

native Object arrayGet(Array array, int index)/*{
	return array[index];
}*/;

protected void checkDevice () {
	if (disposed) SWT.error(SWT.ERROR_DEVICE_DISPOSED);
}

protected void create (DeviceData data) {
}

protected void destroy () {
}

public void dispose () {
	synchronized (Device.class) {
		if (isDisposed()) return;
		checkDevice ();
		release ();
		destroy ();
		disposed = true;
		if (tracking) {
			synchronized (trackingLock) {
				objects = null;
				errors = null;
				trackingLock = null;
			}
		}
	}
}

void dispose_Object (Object object) {
	synchronized (trackingLock) {
		for (int i=0; i<objects.length; i++) {
			if (objects [i] == object) {
				objects [i] = null;
				errors [i] = null;
				return;
			}
		}
	}
}

public Rectangle getBounds () {
	checkDevice();
	return new Rectangle(0, 0, (int)Capabilities.screenResolutionX, (int)Capabilities.screenResolutionY);
}

public DeviceData getDeviceData () {
	checkDevice();
	DeviceData data = new DeviceData ();
	data.debug = debug;
	data.tracking = tracking;
	if (tracking) {
		synchronized (trackingLock) {
			int count = 0, length = objects.length;
			for (int i=0; i<length; i++) {
				if (objects [i] != null) count++;
			}
			int index = 0;
			data.objects = new Object [count];
			data.errors = new Error [count];
			for (int i=0; i<length; i++) {
				if (objects [i] != null) {
					data.objects [index] = objects [i];
					data.errors [index] = errors [i];
					index++;
				}
			}
		}
	} else {
		data.objects = new Object [0];
		data.errors = new Error [0];
	}
	return data;
}

public Rectangle getClientArea () {
	return getBounds ();
}

public int getDepth () {
	checkDevice ();
	return 0;
}

public Point getDPI () {
	checkDevice ();
	return new Point((int)Capabilities.screenDPI, (int)Capabilities.screenDPI);
}

public FontData[] getFontList (String faceName, boolean scalable) {
	checkDevice ();
	intrinsic.Array fonts = intrinsic.flash.text.Font.enumerateFonts(true);
	FontData[] fontData = new FontData[fonts.length];
	for (int i = 0; i < fontData.length; i++) {
		fontData[i] = new FontData(((intrinsic.flash.text.Font)arrayGet(fonts,i)).fontName, 10, SWT.NORMAL);
	}
	return fontData;
}

public Color getSystemColor (int id) {
	checkDevice ();
	int rgb = 0x000000;
	switch (id) {
		case SWT.COLOR_WHITE:				rgb = 0xFFFFFF;  break;
		case SWT.COLOR_BLACK:				rgb = 0x000000;  break;
		case SWT.COLOR_RED:					rgb = 0xFF0000;  break;
		case SWT.COLOR_DARK_RED:			rgb = 0x800000;  break;
		case SWT.COLOR_GREEN:				rgb = 0x00FF00;  break;
		case SWT.COLOR_DARK_GREEN:			rgb = 0x008000;  break;
		case SWT.COLOR_YELLOW:				rgb = 0xFFFF00;  break;
		case SWT.COLOR_DARK_YELLOW:			rgb = 0x808000;  break;
		case SWT.COLOR_BLUE:				rgb = 0x0000FF;  break;
		case SWT.COLOR_DARK_BLUE:			rgb = 0x000080;  break;
		case SWT.COLOR_MAGENTA:				rgb = 0xFF00FF;  break;
		case SWT.COLOR_DARK_MAGENTA:		rgb = 0x800080;  break;
		case SWT.COLOR_CYAN:				rgb = 0xFF00FF;  break;
		case SWT.COLOR_DARK_CYAN:			rgb = 0x800080;  break;
		case SWT.COLOR_GRAY:				rgb = 0xC0C0C0;  break;
		case SWT.COLOR_DARK_GRAY:			rgb = 0x808080;  break;
	}
	return Color.flex_new (this, rgb);
}

public Font getSystemFont () {
	checkDevice ();
	return systemFont;
}

public boolean getWarnings () {
	checkDevice ();
	return false;
}

protected void init () {
}

public abstract int internal_new_GC (GCData data);

public abstract void internal_dispose_GC (int hDC, GCData data);

public boolean isDisposed () {
	synchronized (Device.class) {
		return disposed;
	}
}

public boolean loadFont (String path) {
	checkDevice ();
	return false;
}

void new_Object (Object object) {
	synchronized (trackingLock) {
		for (int i=0; i<objects.length; i++) {
			if (objects [i] == null) {
				objects [i] = object;
				errors [i] = new Error ();
				return;
			}
		}
		Object [] newObjects = new Object [objects.length + 128];
		java.lang.System.arraycopy (objects, 0, newObjects, 0, objects.length);
		newObjects [objects.length] = object;
		objects = newObjects;
		Error [] newErrors = new Error [errors.length + 128];
		java.lang.System.arraycopy (errors, 0, newErrors, 0, errors.length);
		newErrors [errors.length] = new Error ();
		errors = newErrors;
	}
}

protected void release () {
}

public void setWarnings (boolean warnings) {
	checkDevice ();
}

}
