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

import org.eclipse.swt.graphics.*;
import org.eclipse.swt.*;
import org.eclipse.swt.effects.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.accessibility.*;

import intrinsic.Function;
import intrinsic.Array;
import intrinsic.flash.display.DisplayObject;
import intrinsic.flash.events.KeyboardEvent;
import intrinsic.mx.core.*;
import intrinsic.mx.events.MoveEvent;
import intrinsic.mx.events.ResizeEvent;
import intrinsic.mx.managers.IFocusManager;
import intrinsic.mx.managers.IFocusManagerComponent;

public abstract class Control extends Widget implements Drawable {
	int drawCount;
	int x, y, width, height;
	String toolTipText;
	Object layoutData;
	Composite parent;
	Cursor cursor;
	Color foreground;
	Color background;
	Image backgroundImage;
	Font font;
	Menu menu;
	Accessible accessible;
	Region region;
	
Control () {
}
	
public Control (Composite parent, int style) {
	super (parent, style);
	this.parent = parent;
	createWidget ();
}

public void addControlListener (ControlListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	TypedListener typedListener = new TypedListener (listener);
	addListener (SWT.Resize,typedListener);
	addListener (SWT.Move,typedListener);
}

public void addDragDetectListener (DragDetectListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	TypedListener typedListener = new TypedListener (listener);
	addListener (SWT.DragDetect,typedListener);
}

public void addFocusListener (FocusListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	TypedListener typedListener = new TypedListener (listener);
	addListener (SWT.FocusIn,typedListener);
	addListener (SWT.FocusOut,typedListener);
}

public void addHelpListener (HelpListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	TypedListener typedListener = new TypedListener (listener);
	addListener (SWT.Help, typedListener);
}

public void addKeyListener (KeyListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	TypedListener typedListener = new TypedListener (listener);
	addListener (SWT.KeyUp,typedListener);
	addListener (SWT.KeyDown,typedListener);
}

public void addMenuDetectListener (MenuDetectListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	TypedListener typedListener = new TypedListener (listener);
	addListener (SWT.MenuDetect, typedListener);
}

public void addMouseListener (MouseListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	TypedListener typedListener = new TypedListener (listener);
	addListener (SWT.MouseDown,typedListener);
	addListener (SWT.MouseUp,typedListener);
	addListener (SWT.MouseDoubleClick,typedListener);
}

public void addMouseMoveListener (MouseMoveListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	TypedListener typedListener = new TypedListener (listener);
	addListener (SWT.MouseMove,typedListener);
}

public void addMouseTrackListener (MouseTrackListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	TypedListener typedListener = new TypedListener (listener);
	addListener (SWT.MouseEnter,typedListener);
	addListener (SWT.MouseExit,typedListener);
	addListener (SWT.MouseHover,typedListener);
}

public void addMouseWheelListener (MouseWheelListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	TypedListener typedListener = new TypedListener (listener);
	addListener (SWT.MouseWheel, typedListener);
}

public void addPaintListener (PaintListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	TypedListener typedListener = new TypedListener (listener);
	addListener (SWT.Paint,typedListener);
}

void addParent (int index) {
	parent.addControl (this);
	parent.addChild (this, index);
}

public void addTraverseListener (TraverseListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	TypedListener typedListener = new TypedListener (listener);
	addListener (SWT.Traverse,typedListener);
}

UIComponent backgroundControl() {
	return object;
}

native int cast(Object obj)/*{
	return int(obj);
}*/;

public Point computeSize (int wHint, int hHint) {
	return computeSize (wHint, hHint, true);
}

public Point computeSize (int wHint, int hHint, boolean changed) {
	checkWidget ();
	return computeNativeSize (object, wHint, hHint, changed);
}

Point computeNativeSize (UIComponent widget, int wHint, int hHint, boolean changed) {
	double oldWidth = widget.width, oldHeight = widget.height;
	widget.width = Double.NaN;
	widget.height = Double.NaN;
	widget.validateProperties();
	widget.validateSize();
	int width = wHint == SWT.DEFAULT ? (int)widget.measuredWidth : wHint;
	int height = hHint == SWT.DEFAULT ? (int)widget.measuredHeight : hHint;
	widget.width = oldWidth;
	widget.height = oldHeight;
	return new Point (width, height);
}

Control computeTabGroup () {
	if (isTabGroup ()) return this;
	return parent.computeTabGroup ();
}

Control computeTabRoot () {
	Control [] tabList = parent._getTabList ();
	if (tabList != null) {
		int index = 0;
		while (index < tabList.length) {
			if (tabList [index] == this) break;
			index++;
		}
		if (index == tabList.length) {
			if (isTabGroup ()) return this;
		}
	}
	return parent.computeTabRoot ();
}

Control [] computeTabList () {
	if (isTabGroup ()) {
		if (getVisible () && getEnabled ()) {
			return new Control [] {this};
		}
	}
	return new Control [0];
}

void createWidget () {
	super.createWidget ();
	state |= DRAG_DETECT;
//	checkOrientation (parent);
//	checkBackground ();
//	checkBuffered ();
//	setDefaultFont ();
//	checkMirrored ();
//	checkBorder ();
//	if ((state & PARENT_BACKGROUND) != 0) {
//		setBackground ();
//	}
	setInitialBounds ();
	addParent (-1);
}

Color defaultBackground () {
	UIComponent widget = backgroundControl();
	return Color.flex_new (display, cast(widget.getStyle ("backgroundColor")));
}

Font defaultFont () {
	String fontFamily = (String)object.getStyle ("fontFamily");
	String fontStyle = (String)object.getStyle ("fontStyle");
	String fontWeight = (String)object.getStyle ("fontWeight");
	int fontSize = cast(object.getStyle("fontSize"));
	return Font.flex_new (display, fontFamily, fontStyle, fontWeight, fontSize);
}

Color defaultForeground () {
	return Color.flex_new (display, cast(object.getStyle ("color")));
}

void destroyWidget () {
	parent.removeChild (this);
	releaseHandle ();
}

public boolean dragDetect (org.eclipse.swt.widgets.Event event) {
	checkWidget ();
	if (event == null) error (SWT.ERROR_NULL_ARGUMENT);
	return _dragDetect (event.button, event.count, event.stateMask, event.x, event.y);
}

boolean drawGripper (int x, int y, int width, int height, boolean vertical) {
	return false;
}

public boolean dragDetect (org.eclipse.swt.events.MouseEvent event) {
	checkWidget ();
	if (event == null) error (SWT.ERROR_NULL_ARGUMENT);
	return _dragDetect (event.button, event.count, event.stateMask, event.x, event.y);
}

DisplayObject eventComponent () {
	return object;
}

Control findBackgroundControl () {
	if (background != null || backgroundImage != null) return this;
	return (state & PARENT_BACKGROUND) != 0 ? parent.findBackgroundControl () : null;
}

Cursor findCursor () {
	if (cursor != null) return cursor;
	return parent.findCursor ();
}

void fixFocus (Control focusControl) {
	//TODO - fixFocus
//	Shell shell = getShell ();
//	Control control = this;
//	while (control != shell && (control = control.parent) != null) {
//		if (control.setFixedFocus ()) return;
//	}
//	shell.setSavedFocus (focusControl);
//	OS.SetFocus (0);
}

public boolean forceFocus () {
	checkWidget ();
//	if (display.focusEvent == SWT.FocusOut) return false;
//	Decorations shell = menuShell ();
//	shell.setSavedFocus (this);
	if (!isEnabled () || !isVisible ()/* || !isActive ()*/) return false;
	if (isFocusControl ()) return true;
//	shell.setSavedFocus (null);
	Application app = (Application)Application.application;
	IFocusManager focusManager = app.focusManager;
	if (object instanceof IFocusManagerComponent) {
		focusManager.setFocus((IFocusManagerComponent)object);
	}
	if (isDisposed ()) return false;
//	shell.setSavedFocus (this);
	return isFocusControl ();
}

public Accessible getAccessible () {
	checkWidget ();
	if (accessible == null) {
		accessible = Accessible.internal_new_Accessible (this);
	}
	return accessible;
}

public int getAlpha () {
	checkWidget ();
	return (int) (((DisplayObject)object).alpha * 0xFF);
}

public Color getBackground () {
	checkWidget();
	Control control = findBackgroundControl ();
	if (control == null) control = this;
	return control.background != null ? control.background : control.defaultBackground ();
}

public Image getBackgroundImage () {
	checkWidget();
	Control control = findBackgroundControl ();
	if (control == null) control = this;
	return control.backgroundImage;
}

public int getBorderWidth () {
	//TODO-
	return 0;
}

public Rectangle getBounds () {
	checkWidget ();
	UIComponent widget = topComponent();
	return new Rectangle ((int)widget.x, (int)widget.y, (int)widget.width, (int)widget.height);
}

public Cursor getCursor () {
	checkWidget ();
	return cursor;
}

public boolean getDragDetect () {
	checkWidget ();
	return (state & DRAG_DETECT) != 0;
}

public boolean getEnabled () {
	checkWidget ();
	return (state & DISABLED) == 0;
}

public Font getFont () {
	checkWidget ();
	return font != null ? font : defaultFont ();
}

public Color getForeground () {
	checkWidget ();
	return foreground != null ? foreground : defaultForeground ();
}

public Object getLayoutData () {
	checkWidget ();
	return layoutData;
}

public Point getLocation () {
	checkWidget ();
	UIComponent widget = topComponent();
	return new Point ((int)widget.x, (int)widget.y);
}

public Menu getMenu () {
	checkWidget ();
	return menu;
}

public Monitor getMonitor () {
	checkWidget ();
	return _getMonitor ();
}

public Composite getParent () {
	checkWidget ();
	return parent;
}

Control [] getPath () {
	int count = 0;
	Shell shell = getShell ();
	Control control = this;
	while (control != shell) {
		count++;
		control = control.parent;
	}
	control = this;
	Control [] result = new Control [count];
	while (control != shell) {
		result [--count] = control;
		control = control.parent;
	}
	return result;
}

public Shell getShell () {
	checkWidget ();
	return parent.getShell ();
}

public Point getSize () {
	checkWidget ();
	UIComponent widget = topComponent();
	return new Point ((int)widget.width, (int)widget.height);
}

UIComponent getSprite () {
	return null;
}

public String getToolTipText () {
	checkWidget ();
	return toolTipText;
}

public boolean getVisible () {
	checkWidget ();
	return (state & HIDDEN) == 0;
}

void handleMove (MoveEvent event) {
	UIComponent widget = topComponent ();
	int newX = (int)widget.x, newY = (int)widget.y;
	if (x != newX || y != newY) {
		x = newX;
		y = newY;
		moved ();
	}
}

native Function handleMoveFunction ()/*{
	return handleMove__Lmx_events_MoveEvent_2;
}*/;

void handleResize (ResizeEvent event) {
	if (isDisposed()) return;
	UIComponent widget = topComponent ();
	int newWidth = (int)widget.width, newHeight = (int)widget.height;
	if (width != newWidth || height != newHeight) {
		width = newWidth;
		height = newHeight;
		resized ();
	}
}

native Function handleResizeFunction ()/*{
	return handleResize__Lmx_events_ResizeEvent_2;
}*/;

boolean hasFocus () {
	if (object.stage != null) { 
		return object.stage.focus == object;
	}
	return false;
}

void hookEvents () {
	super.hookEvents ();
	topComponent ().addEventListener(MoveEvent.MOVE, handleMoveFunction ());
	resizeComponent ().addEventListener(ResizeEvent.RESIZE, handleResizeFunction ());
}

boolean hooksMouse (int type) {
	return hooks (type) || filters (type);
}

public int internal_new_GC (GCData data) {
	checkWidget ();
	if (data != null) {
		data.sprite = getSprite ();
//		if (data.paintRect == null) {
//			while (data.sprite.numChildren > 0) {
//				data.sprite.removeChildAt(0);
//			}
//		}
		int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
		if ((data.style & mask) == 0) {
			data.style |= style & (mask | SWT.MIRRORED);
		} else {
			if ((data.style & SWT.RIGHT_TO_LEFT) != 0) {
				data.style |= SWT.MIRRORED;
			}
		}
		data.device = display;
		data.background = getBackground();
		data.foreground = getForeground();
		data.font = getFont();
		return 1;
	}
	return 0;
}

public void internal_dispose_GC (int hDC, GCData data) {
	if (data != null) {
		data.sprite = null;
	}
}

public boolean isEnabled () {
	checkWidget ();
	return getEnabled () && parent.isEnabled ();
}

boolean isFocusAncestor (Control control) {
	while (control != null && control != this && !(control instanceof Shell)) {
		control = control.parent;
	}
	return control == this;
}

public boolean isFocusControl () {
	checkWidget();
	return this == display.getFocusControl();
}

public boolean isReparentable () {
	checkWidget();
	return _isReparentable ();
}

boolean isShowing () {
	/*
	* This is not complete.  Need to check if the
	* widget is obscured by a parent or sibling.
	*/
	if (!isVisible ()) return false;
	Control control = this;
	while (control != null) {
		Point size = control.getSize ();
		if (size.x == 0 || size.y == 0) {
			return false;
		}
		control = control.parent;
	}
	return true;
}

boolean isTabGroup () {
	Control [] tabList = parent._getTabList ();
	if (tabList != null) {
		for (int i=0; i<tabList.length; i++) {
			if (tabList [i] == this) return true;
		}
	}
	return _isTabGroup ();
}

boolean isTabItem () {
	Control [] tabList = parent._getTabList ();
	if (tabList != null) {
		for (int i=0; i<tabList.length; i++) {
			if (tabList [i] == this) return false;
		}
	}
	return _isTabItem ();
}


public boolean isVisible () {
	checkWidget ();
	return getVisible () && parent.isVisible ();
}

void markLayout (boolean changed, boolean all) {
	/* Do nothing */
}

Decorations menuShell () {
	return parent.menuShell ();
}

public void moveAbove (Control control) {
	checkWidget ();
	if (control != null) {
		if (control.isDisposed ()) error(SWT.ERROR_INVALID_ARGUMENT);
		if (parent != control.parent) return;
	}
	int index;
	UIComponent parentComponent = parent.parentingComponent();
	if (control != null) {
		index = parentComponent.getChildIndex(control.topComponent());
	} else {
		index = parentComponent.numChildren - 1;
	}
	UIComponent topComponent = topComponent();
	if (parentComponent.getChildIndex(topComponent) < index) {
		parentComponent.setChildIndex(topComponent, index);
	}
}

public void moveBelow (Control control) {
	checkWidget ();
	if (control != null) {
		if (control.isDisposed ()) error(SWT.ERROR_INVALID_ARGUMENT);
		if (parent != control.parent) return;
	}
	int index;
	UIComponent parentComponent = parent.parentingComponent();
	if (control != null) {
		index = Math.max (0, parentComponent.getChildIndex(control.topComponent()) - 1);
	} else {
		index = 0;
	}
	UIComponent topComponent = topComponent();
	if (parentComponent.getChildIndex(topComponent) > index) {
		parentComponent.setChildIndex(topComponent, index);
	}
}

void moved () {
	sendEvent (SWT.Move);
}

public void pack () {
	checkWidget ();
	pack (true);
}

public void pack (boolean changed) {
	checkWidget ();
	setSize (computeSize (SWT.DEFAULT, SWT.DEFAULT, changed));
}

void paintHandler (intrinsic.flash.events.Event e) {
	UIComponent sprite = getSprite();
	if (e.target != sprite) return;
	sprite.graphics.clear();
	while (sprite.numChildren > 0) {
		sprite.removeChildAt(0);
	}
	intrinsic.flash.geom.Rectangle area = new intrinsic.flash.geom.Rectangle(0, 0, object.width, object.height);
	org.eclipse.swt.widgets.Event event = new org.eclipse.swt.widgets.Event ();
	event.x = Math.max(0, (int)area.x);
	event.y = Math.max(0, (int)area.y);
	event.width = (int)area.width;
	event.height = (int)area.height;
	GCData data = new GCData ();
	data.paintRect = area;
	GC gc = event.gc = GC.flex_new (this, data);
	sendEvent (SWT.Paint, event);
	gc.dispose ();
	event.gc = null;
}

native Function paintHandlerFunction ()/*{
	return paintHandler__Lflash_events_Event_2;
}*/;

public void redraw () {
	checkWidget ();
	redrawWidget (0, 0, (int)object.width, (int)object.height, false);
}

public void redraw (int x, int y, int width, int height, boolean all) {
	checkWidget ();
	redrawWidget (x, y, width, height, all);
}

void redrawWidget (int x, int y, int width, int height, boolean all) {
	if (width == 0 || height == 0) return;
	UIComponent sprite = getSprite();
	if (sprite != null) {
		sprite.invalidateDisplayList();
	} else {
		object.invalidateDisplayList();
	}
}

void releaseHandle () {
	super.releaseHandle ();
	object = null;
	parent = null;
}

void releaseParent () {
	parent.removeControl (this);
}

void releaseWidget () {
	super.releaseWidget ();
//	if (toolTipText != null) {
//		setToolTipText (getShell (), null);
//	}
	if (menu != null && !menu.isDisposed ()) {
		menu.dispose ();
	}
	if (display.grabControl == this) {
		display.grabControl = null;
	}
	background = null;
	backgroundImage = null;
	cursor = null;
	font = null;
	foreground = null;
	layoutData = null;
	menu = null;
	toolTipText = null;
//	if (accessible != null) {
//		accessible.internal_dispose_Accessible ();
//	}
//	accessible = null;
}

public void removeControlListener (ControlListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	if (eventTable == null) return;
	eventTable.unhook (SWT.Move, listener);
	eventTable.unhook (SWT.Resize, listener);
}

public void removeDragDetectListener (DragDetectListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	if (eventTable == null) return;
	eventTable.unhook (SWT.DragDetect, listener);
}

public void removeFocusListener (FocusListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	if (eventTable == null) return;
	eventTable.unhook (SWT.FocusIn, listener);
	eventTable.unhook (SWT.FocusOut, listener);
}

public void removeHelpListener (HelpListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	if (eventTable == null) return;
	eventTable.unhook (SWT.Help, listener);
}

public void removeKeyListener (KeyListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	if (eventTable == null) return;
	eventTable.unhook (SWT.KeyUp, listener);
	eventTable.unhook (SWT.KeyDown, listener);
}

public void removeMenuDetectListener (MenuDetectListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	if (eventTable == null) return;
	eventTable.unhook (SWT.MenuDetect, listener);
}

public void removeMouseListener (MouseListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	if (eventTable == null) return;
	eventTable.unhook (SWT.MouseDown, listener);
	eventTable.unhook (SWT.MouseUp, listener);
	eventTable.unhook (SWT.MouseDoubleClick, listener);

}

public void removeMouseMoveListener (MouseMoveListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	if (eventTable == null) return;
	eventTable.unhook (SWT.MouseMove, listener);
}

public void removeMouseTrackListener (MouseTrackListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	if (eventTable == null) return;
	eventTable.unhook (SWT.MouseEnter, listener);
	eventTable.unhook (SWT.MouseExit, listener);
	eventTable.unhook (SWT.MouseHover, listener);
}

public void removeMouseWheelListener (MouseWheelListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	if (eventTable == null) return;
	eventTable.unhook (SWT.MouseWheel, listener);
}

public void removePaintListener (PaintListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	if (eventTable == null) return;
	eventTable.unhook(SWT.Paint, listener);
}

public void removeTraverseListener (TraverseListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	if (eventTable == null) return;
	eventTable.unhook (SWT.Traverse, listener);
}

UIComponent resizeComponent () {
	return object;
}

void resized () {
	sendEvent (SWT.Resize);
}

boolean sendFocusEvent (int type) {
	Shell shell = getShell ();

//	Display display = this.display;
//	display.focusEvent = type;
//	display.focusControl = this;
	sendEvent (type);
	// widget could be disposed at this point
//	display.focusEvent = SWT.None;
//	display.focusControl = null;

	/*
	* It is possible that the shell may be
	* disposed at this point.  If this happens
	* don't send the activate and deactivate
	* events.
	*/	
	if (!shell.isDisposed ()) {
		switch (type) {
			case SWT.FocusIn:
				shell.setActiveControl (this);
				break;
			case SWT.FocusOut:
				if (shell != display.getActiveShell ()) {
					shell.setActiveControl (null);
				}
				break;
		}
	}
	return true;
}

boolean sendKeyEvent (int type, intrinsic.flash.events.KeyboardEvent keyEvent) {
	Event event = new Event ();
	if (!setKeyState (event, type, keyEvent)) return true;
	return sendKeyEvent(type, event);
}

boolean sendKeyEvent (int type, Event keyEvent) {
	sendEvent (type, keyEvent);
	if (isDisposed ()) return false;
	return keyEvent.doit;
}

boolean sendMouseEvent (int type, intrinsic.flash.events.MouseEvent mouseEvent, boolean send) {
	if (!hooksMouse (type)) return true;
	org.eclipse.swt.widgets.Event event = new org.eclipse.swt.widgets.Event ();
	switch (type) {
		case SWT.MouseDown:
		case SWT.MouseUp:
			event.button = 1;
	}
	DisplayObject eventComponent = eventComponent (); 
	if (mouseEvent.target == eventComponent) {
		event.x = (int)mouseEvent.localX;
		event.y = (int)mouseEvent.localY;
	} else {
		intrinsic.flash.geom.Point pt = new intrinsic.flash.geom.Point(mouseEvent.stageX, mouseEvent.stageY);
		pt = eventComponent.globalToLocal(pt);
		event.x = (int)pt.x;
		event.y = (int)pt.y;
	}
	event.time = (int)System.currentTimeMillis();
	event.count = display.getClickCount (type, this, event.x, event.y, event.time);
//	event.detail = detail;
	setInputState (event, type, mouseEvent.altKey, mouseEvent.ctrlKey, mouseEvent.shiftKey, mouseEvent.buttonDown);
	return sendMouseEvent(type, event, send);
}
	
boolean sendMouseEvent (int type, Event mouseEvent, boolean send) {
	if (send) {
		sendEvent (type, mouseEvent);
		if (isDisposed ()) return false;
	} else {
		postEvent (type, mouseEvent);
	}
	return mouseEvent.doit;
}

boolean setInputState (org.eclipse.swt.widgets.Event event, int type, boolean altKey, boolean controlKey, boolean shiftKey, boolean buttonDown) {
	if (altKey) event.stateMask |= SWT.ALT;
	if (shiftKey) event.stateMask |= SWT.SHIFT;
	if (controlKey) event.stateMask |= SWT.CONTROL;
	if (buttonDown) event.stateMask |= SWT.BUTTON1;
//	if (OS.GetKeyState (OS.VK_MBUTTON) < 0) event.stateMask |= SWT.BUTTON2;
//	if (OS.GetKeyState (OS.VK_RBUTTON) < 0) event.stateMask |= SWT.BUTTON3;
//	if (OS.GetKeyState (OS.VK_XBUTTON1) < 0) event.stateMask |= SWT.BUTTON4;
//	if (OS.GetKeyState (OS.VK_XBUTTON2) < 0) event.stateMask |= SWT.BUTTON5;
	switch (type) {
		case SWT.MouseDown:
		case SWT.MouseDoubleClick:
			if (event.button == 1) event.stateMask &= ~SWT.BUTTON1;
			if (event.button == 2) event.stateMask &= ~SWT.BUTTON2;
			if (event.button == 3) event.stateMask &= ~SWT.BUTTON3;
			if (event.button == 4) event.stateMask &= ~SWT.BUTTON4;
			if (event.button == 5) event.stateMask &= ~SWT.BUTTON5;
			break;
		case SWT.MouseUp:
			if (event.button == 1) event.stateMask |= SWT.BUTTON1;
			if (event.button == 2) event.stateMask |= SWT.BUTTON2;
			if (event.button == 3) event.stateMask |= SWT.BUTTON3;
			if (event.button == 4) event.stateMask |= SWT.BUTTON4;
			if (event.button == 5) event.stateMask |= SWT.BUTTON5;
			break;
		case SWT.KeyDown:
		case SWT.Traverse:
			if (event.keyCode == SWT.ALT) event.stateMask &= ~SWT.ALT;
			if (event.keyCode == SWT.SHIFT) event.stateMask &= ~SWT.SHIFT;
			if (event.keyCode == SWT.CONTROL) event.stateMask &= ~SWT.CONTROL;
			break;
		case SWT.KeyUp:
			if (event.keyCode == SWT.ALT) event.stateMask |= SWT.ALT;
			if (event.keyCode == SWT.SHIFT) event.stateMask |= SWT.SHIFT;
			if (event.keyCode == SWT.CONTROL) event.stateMask |= SWT.CONTROL;
			break;
	}		
	return true;
}

void setInitialBounds() {
	UIComponent topComponent = topComponent();
	topComponent.x = topComponent.y = 0;
	topComponent.width = topComponent.height = 0;
}

public void setAlpha (int alpha) {
	checkWidget ();
	((DisplayObject)object).alpha = (alpha&0xFF) / (double)0xFF;
}
public void setBackground (Color color) {
	checkWidget ();
	if (color != null && color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
	Color oldColor = this.background;
	if (oldColor == color) return;
	this.background = color;
	if (oldColor != null && oldColor.equals (color)) {
		return;
	}
	UIComponent widget = backgroundControl();  
	if (color != null) {
		widget.setStyle("backgroundColor", color.handle);
	} else {
		widget.clearStyle("backgroundColor");
	}
}

public void setBackgroundImage (Image image) {
	checkWidget ();
	if (image != null && image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
	Image oldImage = this.backgroundImage;
	if (oldImage == image) return;
	this.backgroundImage = image;
	if (oldImage != null && oldImage.equals (font)) {
		return;
	}
	_setBackgroundImage (image);
}

public void setBounds (int x, int y, int width, int height) {
	checkWidget();
	setBounds (x, y, Math.max (0, width), Math.max (0, height), MOVED | RESIZED);
}

int setBounds (int x, int y, int width, int height, int flags) {
	boolean sameOrigin = true, sameExtent = true;
	UIComponent widget = topComponent();
	int oldX = (int)widget.x, oldY = (int)widget.y;
	if ((flags & MOVED) != 0) {
		sameOrigin = x == oldX && y == oldY;
	} else {
		x = oldX;
		y = oldY;
	}
	int oldWidth = (int)widget.width, oldHeight = (int)widget.height;
	if ((flags & RESIZED) != 0) {
		sameExtent = width == oldWidth && height == oldHeight;
	} else {
		width = oldWidth;
		height = oldHeight;
	}
	if (!sameOrigin) {
		this.x = x;
		this.y = y;
		widget.x = x;
		widget.y = y;
	}
	if (!sameExtent) {
		this.width = width;
		this.height = height;
		widget.width = width;
		widget.height = height;
	}
	int result = 0;
	if (!sameOrigin) {
		sendEvent (SWT.Move);
		result |= MOVED;
	}
	if (!sameExtent) {
		sendEvent (SWT.Resize);
		result |= RESIZED;
	}
	return result;
}

public void setBounds (Rectangle rect) {
	checkWidget ();
	if (rect == null) error (SWT.ERROR_NULL_ARGUMENT);
	setBounds (rect.x, rect.y, rect.width, rect.height);
}

public void setCapture (boolean capture) {
	checkWidget();
	_setCapture (capture);
}

public void setCursor (Cursor cursor) {
	checkWidget ();
	if (cursor != null && cursor.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
	this.cursor = cursor;
}

public void setDragDetect (boolean dragDetect) {
	checkWidget ();
	state = dragDetect ? state & ~DRAG_DETECT : state | DRAG_DETECT;
}

public void setEffect(Effect effect) {
	checkWidget();
	if (effect != null && effect.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
	Array array = new Array();
	if (effect != null) {
		if (effect instanceof CompositeEffect) {
			Effect[] effects = (Effect[])effect.object;
			for (int i = 0; i<effects.length; i++) {
				array.push(effects[i].object);
			}
		} else {
			array.push(effect.object);
		}
	}
	UIComponent widget = topComponent();
	widget.filters = array;
}

public void setEnabled (boolean enabled) {
	checkWidget();
	if (((state & DISABLED) == 0) == enabled) return;
	Control control = null;
	boolean fixFocus = false;
	if (!enabled) {
//		if (display.focusEvent != SWT.FocusOut) {
			control = display.getFocusControl ();
			fixFocus = isFocusAncestor (control);
//		}
	}
	state = enabled ? state & ~DISABLED : state | DISABLED;
	UIComponent widget = topComponent();
	widget.enabled = enabled;
	widget.mouseChildren = enabled;
	if (isDisposed ()) return;	
	if (fixFocus) fixFocus (control);
}

public boolean setFocus () {
	checkWidget();
	if ((style & SWT.NO_FOCUS) != 0) return false;
	return forceFocus ();
}

public void setFont (Font font) {
	checkWidget ();
	if (font != null && font.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
	Font oldFont = this.font;
	if (oldFont == font) return;
	this.font = font;
	if (oldFont != null && oldFont.equals (font)) {
		return;
	}
	if (font != null) {
		object.setStyle("fontFamily", font.fontFamily);
		object.setStyle("fontStyle", font.fontStyle);
		object.setStyle("fontWeight", font.fontWeight);
		object.setStyle("fontSize", font.fontSize);
	} else {
		object.clearStyle("fontFamily");
		object.clearStyle("fontStyle");
		object.clearStyle("fontWeight");
		object.clearStyle("fontSize");		
	}
}

public void setForeground (Color color) {
	checkWidget ();
	if (color != null && color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
	Color oldColor = this.foreground;
	if (oldColor == color) return;
	this.foreground = color;
	if (oldColor != null && oldColor.equals (color)) {
		return;
	}
	if (color != null) {
		object.setStyle("color", color.handle);
	} else {
		object.clearStyle("backgroundColor");
	}
}

boolean setKeyState (Event event, int type, KeyboardEvent keyEvent) {
	event.keyCode = Display.translateKey(keyEvent.keyCode);
	if (event.keyCode == 0) {
		int key = event.keyCode = keyEvent.keyCode;
		if ('A'  <= key && key <= 'Z') event.keyCode += 'a' - 'A';
	}
	boolean isNull = false;
	int key = event.character;
	if (keyEvent.ctrlKey && (0 <= key && key <= 0x7F)) {
		if ('a'  <= key && key <= 'z') key -= 'a' - 'A';
		if (64 <= key && key <= 95) key -= 64;
		event.character = (char) key;
		isNull = keyEvent.keyCode == '@' && key == 0;
	} else {
		event.character = (char)keyEvent.charCode;
	}
	if (event.keyCode == 0 && event.character == 0) {
		if (!isNull) return false;
	}
	return setInputState (event, type, keyEvent.altKey, keyEvent.ctrlKey, keyEvent.shiftKey, false);
}

public void setLayoutData (Object layoutData) {
	checkWidget ();
	this.layoutData = layoutData;
}

public void setLocation (int x, int y) {
	checkWidget();
	setBounds (x, y, 0, 0, MOVED);
}

public void setLocation (Point location) {
	checkWidget ();
	if (location == null) error (SWT.ERROR_NULL_ARGUMENT);
	setLocation (location.x, location.y);
}

public void setMenu (Menu menu) {
	checkWidget ();
	if (menu != null) {
		if (menu.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
		if ((menu.style & SWT.POP_UP) == 0) {
			error (SWT.ERROR_MENU_NOT_POP_UP);
		}
		if (menu.parent != menuShell ()) {
			error (SWT.ERROR_INVALID_PARENT);
		}
	}
	this.menu = menu;
}

public boolean setParent (Composite parent) {
	checkWidget ();
	if (parent == null) error (SWT.ERROR_NULL_ARGUMENT);
	if (parent.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
	if (this.parent == parent) return true;
	if (!isReparentable ()) return false;
	return _setParent (parent);
}

boolean setRadioSelection (boolean value) {
	return false;
}

public void setRedraw (boolean redraw) {
	checkWidget();
	if (redraw) {
		if (--drawCount == 0) {
			_setRedraw (redraw);
		}
	} else {
		if (drawCount++ == 0) {
			_setRedraw (redraw);
		}
	}
}

public void setRegion (Region region) {
	checkWidget();
	if (region != null && region.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
	this.region = region;
//	topComponent().mask = region.object;
	//TODO
}

public void setSize (int width, int height) {
	checkWidget();
	setBounds (0, 0, Math.max (0, width), Math.max (0, height), RESIZED);
}

public void setSize (Point size) {
	checkWidget ();
	if (size == null) error (SWT.ERROR_NULL_ARGUMENT);
	setSize (size.x, size.y);
}

boolean setTabGroupFocus () {
	return setTabItemFocus ();
}

boolean setTabItemFocus () {
	if (!isShowing ()) return false;
	return forceFocus ();
}

public void setToolTipText (String string) {
	checkWidget ();
	toolTipText = string;
	object.toolTip = string;
}

public void setTransform (Transform transform) {
	checkWidget ();
	//TODO copy? topHandle?
	UIComponent widget = topComponent();
	widget.transform.matrix = transform.object;
}

public void setVisible (boolean visible) {
	checkWidget ();
	if (((state & HIDDEN) == 0) == visible) return;
	if (visible) {
		sendEvent (SWT.Show);
		if (isDisposed ()) return;
	}
	Control control = null;
	boolean fixFocus = false;
	if (!visible) {
//		if (display.focusEvent != SWT.FocusOut) {
			control = display.getFocusControl ();
			fixFocus = isFocusAncestor (control);
//		}
	}
	state = visible ? state & ~HIDDEN : state | HIDDEN;
	UIComponent widget = topComponent();
	widget.visible = visible;
	if (!visible) {
		sendEvent (SWT.Hide);
		if (isDisposed ()) return;
	}
	if (fixFocus) fixFocus (control);
}

void sort (int [] items) {
	/* Shell Sort from K&R, pg 108 */
	int length = items.length;
	for (int gap=length/2; gap>0; gap/=2) {
		for (int i=gap; i<length; i++) {
			for (int j=i-gap; j>=0; j-=gap) {
		   		if (items [j] <= items [j + gap]) {
					int swap = items [j];
					items [j] = items [j + gap];
					items [j + gap] = swap;
		   		}
	    	}
	    }
	}
}

public Point toControl (int x, int y) {
	checkWidget ();
	return display.map (null, this, x, y);
}

public Point toControl (Point point) {
	checkWidget ();
	if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
	return toControl (point.x, point.y);
}

public Point toDisplay (int x, int y) {
	checkWidget ();
	return display.map(this, null, x, y);
}

public Point toDisplay (Point point) {
	checkWidget ();
	if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
	return toDisplay (point.x, point.y);
}

public boolean traverse (int traversal) {
	checkWidget ();
	org.eclipse.swt.widgets.Event event = new org.eclipse.swt.widgets.Event ();
	event.doit = true;
	event.detail = traversal;
	return traverse (event);
}

boolean traverseEscape () {
	return false;
}

boolean traverseGroup (boolean next) {
	Control root = computeTabRoot ();
	Control group = computeTabGroup ();
	Control [] list = root.computeTabList ();
	int length = list.length;
	int index = 0;
	while (index < length) {
		if (list [index] == group) break;
		index++;
	}
	/*
	* It is possible (but unlikely), that application
	* code could have disposed the widget in focus in
	* or out events.  Ensure that a disposed widget is
	* not accessed.
	*/
	if (index == length) return false;
	int start = index, offset = (next) ? 1 : -1;
	while ((index = ((index + offset + length) % length)) != start) {
		Control control = list [index];
		if (!control.isDisposed () && control.setTabGroupFocus ()) {
			return true;
		}
	}
	if (group.isDisposed ()) return false;
	return group.setTabGroupFocus ();
}

boolean traverseItem (boolean next) {
	Control [] children = parent._getChildren ();
	int length = children.length;
	int index = 0;
	while (index < length) {
		if (children [index] == this) break;
		index++;
	}
	/*
	* It is possible (but unlikely), that application
	* code could have disposed the widget in focus in
	* or out events.  Ensure that a disposed widget is
	* not accessed.
	*/
	if (index == length) return false;
	int start = index, offset = (next) ? 1 : -1;
	while ((index = (index + offset + length) % length) != start) {
		Control child = children [index];
		if (!child.isDisposed () && child.isTabItem ()) {
			if (child.setTabItemFocus ()) return true;
		}
	}
	return false;
}

boolean traverseMnemonic (char key) {
//	if (mnemonicHit (key)) {
//		OS.SendMessage (handle, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0);
//		return true;
//	}
	return false;
}

boolean traversePage (boolean next) {
	return false;
}

boolean traverseReturn () {
	return false;
}

boolean traverse (org.eclipse.swt.widgets.Event event) {
	/*
	* It is possible (but unlikely), that application
	* code could have disposed the widget in the traverse
	* event.  If this happens, return true to stop further
	* event processing.
	*/	
	sendEvent (SWT.Traverse, event);
	if (isDisposed ()) return true;
	if (!event.doit) return false;
	switch (event.detail) {
		case SWT.TRAVERSE_NONE: return true;
		case SWT.TRAVERSE_ESCAPE: return traverseEscape ();
		case SWT.TRAVERSE_RETURN: return traverseReturn ();
		case SWT.TRAVERSE_TAB_NEXT: return traverseGroup (true);
		case SWT.TRAVERSE_TAB_PREVIOUS: return traverseGroup (false);
		case SWT.TRAVERSE_ARROW_NEXT: return traverseItem (true);
		case SWT.TRAVERSE_ARROW_PREVIOUS: return traverseItem (false);
		case SWT.TRAVERSE_MNEMONIC: return traverseMnemonic (event.character);	
		case SWT.TRAVERSE_PAGE_NEXT: return traversePage (true);
		case SWT.TRAVERSE_PAGE_PREVIOUS: return traversePage (false);
	}
	return false;
}

public void update () {
	checkWidget ();
	object.validateDisplayList();
}

void updateLayout (boolean resize, boolean all) {
	/* Do nothing */
}

/*--------------------- COMMON INTERFACE ------------------*/

boolean _dragDetect (int button, int count, int stateMask, int x, int y) {
	return false;
}

Monitor _getMonitor () {
	return null;
}

boolean _isReparentable () {
	return false;
}

boolean _isTabGroup () {
	return false;
}

boolean _isTabItem () {
	return false;
}

void _setBackgroundImage (Image image) {
}

void _setCapture (boolean capture) {
}

boolean _setParent (Composite parent) {
	return false;
}

void _setRedraw (boolean redraw) {
}

}