/*******************************************************************************
 * 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.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.events.ShellListener;

import intrinsic.Function;
import intrinsic.mx.containers.TitleWindow;
import intrinsic.mx.containers.VBox;
import intrinsic.mx.core.*;
import intrinsic.mx.events.*;

public class Shell extends Decorations {
	TitleWindow window;
	Region region;
	ToolTip [] toolTips;
	boolean opened;
	Control lastActive;

public Shell () {
	this ((Display) null);
}
public Shell (Display display) {
	this (display, SWT.SHELL_TRIM);
}

public Shell (int style) {
	this ((Display) null, style);
}

public Shell (Display display, int style) {
	this (display, null, style, 0, false);
}

public Shell (Shell parent) {
	this (parent, SWT.DIALOG_TRIM);
}

public Shell (Shell parent, int style) {
	this (parent != null ? parent.display : null, parent, style, 0, false);
}

Shell (Display display, Shell parent, int style, int /*long*/ handle, boolean embedded) {
	super ();
	if (display == null) display = Display.getCurrent ();
	if (display == null) display = Display.getDefault ();
	if (!display.isValidThread ()) {
		error (SWT.ERROR_THREAD_INVALID_ACCESS);
	}
	if (parent != null && parent.isDisposed ()) {
		error (SWT.ERROR_INVALID_ARGUMENT);	
	}
	this.style = checkStyle(style);
	this.parent = parent;
	this.display = display;
//	this.handle = handle;//TODO
	if (handle != 0 && !embedded) {
		state |= FOREIGN_HANDLE;
	}
	createWidget ();
}

public static Shell win32_new (Display display, int handle) {
	return null;
}

public static Shell internal_new (Display display, int handle) {
	return null;
}

void addParent (int index) {
	UIComponent widget = topComponent();
	/*
	*  Set the width and height percentage to 100%.
	*  This causes the shell to be maximized if no 
	*  size is set.
	*/
	widget.percentWidth = 100;
	widget.percentHeight = 100;
	display.root.addChild(widget);
}

public void addShellListener (ShellListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	TypedListener typedListener = new TypedListener (listener);
	addListener (SWT.Close,typedListener);
	addListener (SWT.Iconify,typedListener);
	addListener (SWT.Deiconify,typedListener);
	addListener (SWT.Activate, typedListener);
	addListener (SWT.Deactivate, typedListener);
}

static int checkStyle (int style) {
	style = Decorations.checkStyle (style);
	int mask = SWT.SYSTEM_MODAL | SWT.APPLICATION_MODAL | SWT.PRIMARY_MODAL;
	int bits = style & ~mask;
	if ((style & SWT.SYSTEM_MODAL) != 0) return bits | SWT.SYSTEM_MODAL;
	if ((style & SWT.APPLICATION_MODAL) != 0) return bits | SWT.APPLICATION_MODAL;
	if ((style & SWT.PRIMARY_MODAL) != 0) return bits | SWT.PRIMARY_MODAL;
	return bits;
}

public void close () {
	checkWidget ();
	closeWidget ();
}

void closeHandler(CloseEvent event) {
	sendClose ();
}

native Function closeHandlerFunction ()/*{
	return closeHandler__Lmx_events_CloseEvent_2;
}*/;

void closeWidget () {
	Event event = new Event ();
	sendEvent (SWT.Close, event);
	if (event.doit && !isDisposed ()) dispose ();
}

public Rectangle computeTrim (int x, int y, int width, int height) {
	checkWidget ();
	Rectangle trim = super.computeTrim(x, y, width, height);
	if (window != null) {
		EdgeMetrics view = window.viewMetricsAndPadding;
		trim.x -= view.left;
		trim.y -= view.top;
		trim.width += (view.left + view.right);
		trim.height += (view.top + view.bottom);
	}
	return trim;
}

void createHandle () {
	super.createHandle();
	VBox boxWidget = new VBox();
	boxWidget.percentWidth = boxWidget.percentHeight = 100;
	boxWidget.addChild(object);
	boxComponent = boxWidget;
	if ((style & SWT.NO_TRIM) == 0) {
		window = new TitleWindow();
		window.showCloseButton = (style & SWT.CLOSE) != 0;
		window.layout = "vertical";
		object.percentWidth = object.percentHeight = 100;
		window.addChild(boxWidget);
	}
	UIComponent widget = topComponent();
	widget.visible = false;
	state |= HIDDEN;
}

void deregister () {
	super.deregister ();
	if (window != null) display.removeWidget (window);
}

void destroyWidget () {
//	fixActiveShell ();
	UIComponent widget = topComponent();
	display.root.removeChild(widget);
	releaseHandle();
}

Control findBackgroundControl () {
	return background != null || backgroundImage != null ? this : null;
}

Cursor findCursor () {
	return cursor;
}

Composite findDeferredControl () {
	return layoutCount > 0 ? this : null;
}

public void forceActive () {
}

public Rectangle getClientArea () {
	checkWidget ();
	Rectangle rect = super.getClientArea();
	if (window != null) {
		EdgeMetrics windowView = window.viewMetricsAndPadding;
		rect.width -= (windowView.left + windowView.right);
		rect.height -= (windowView.top + windowView.bottom);
	}
	return rect;
}

public int getImeInputMode () {
	return 0;
}

public Point getMinimumSize () {
	return null;
}

public Region getRegion () {
	checkWidget ();
	return region;
}

public Shell getShell () {
	checkWidget ();
	return this;
}

public Shell[] getShells () {
	checkWidget ();
	int count = 0;
	Shell [] shells = display.getShells ();
	for (int i=0; i<shells.length; i++) {
		Control shell = shells [i];
		do {
			shell = shell.parent;
		} while (shell != null && shell != this);
		if (shell == this) count++;
	}
	int index = 0;
	Shell [] result = new Shell [count];
	for (int i=0; i<shells.length; i++) {
		Control shell = shells [i];
		do {
			shell = shell.parent;
		} while (shell != null && shell != this);
		if (shell == this) {
			result [index++] = shells [i];
		}
	}
	return result;
}

boolean hasBorder () {
	return false;
}

void hookEvents () {
	super.hookEvents ();
	if (window != null) {
		window.addEventListener (CloseEvent.CLOSE, closeHandlerFunction ());
	}
}

public boolean isEnabled () {
	checkWidget ();
	return getEnabled ();
}

public boolean isVisible () {
	checkWidget ();
	return getVisible ();
}

public void open () {
	checkWidget ();
	setVisible (true);
}

void register () {
	super.register ();
	if (window != null) display.addWidget (window, this);
}

void releaseChildren (boolean destroy) {
	Shell [] shells = getShells ();
	for (int i=0; i<shells.length; i++) {
		Shell shell = shells [i];
		if (shell != null && !shell.isDisposed ()) {
			shell.release (false);
		}
	}
	if (toolTips != null) {
		for (int i=0; i<toolTips.length; i++) {
			ToolTip toolTip = toolTips [i];
			if (toolTip != null && !toolTip.isDisposed ()) {
				toolTip.release (false);
			}
		}
	}
	toolTips = null;
	super.releaseChildren (destroy);
}

void releaseParent () {
	/* Do nothing */
}

void releaseWidget () {
	super.releaseWidget ();
	region = null;
	lastActive = null;
}

public void removeShellListener (ShellListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	if (eventTable == null) return;
	eventTable.unhook (SWT.Close, listener);
	eventTable.unhook (SWT.Iconify,listener);
	eventTable.unhook (SWT.Deiconify,listener);
	eventTable.unhook (SWT.Activate, listener);
	eventTable.unhook (SWT.Deactivate, listener);
}

void sendClose () {
	closeWidget ();
}

public void setActive () {
}

void setActiveControl (Control control) {
	if (control != null && control.isDisposed ()) control = null;
	if (lastActive != null && lastActive.isDisposed ()) lastActive = null;
	if (lastActive == control) return;
	
	/*
	* Compute the list of controls to be activated and
	* deactivated by finding the first common parent
	* control.
	*/
	Control [] activate = (control == null) ? new Control[0] : control.getPath ();
	Control [] deactivate = (lastActive == null) ? new Control[0] : lastActive.getPath ();
	lastActive = control;
	int index = 0, length = Math.min (activate.length, deactivate.length);
	while (index < length) {
		if (activate [index] != deactivate [index]) break;
		index++;
	}
	
	/*
	* It is possible (but unlikely), that application
	* code could have destroyed some of the widgets. If
	* this happens, keep processing those widgets that
	* are not disposed.
	*/
	for (int i=deactivate.length-1; i>=index; --i) {
		if (!deactivate [i].isDisposed ()) {
			deactivate [i].sendEvent (SWT.Deactivate);
		}
	}
	for (int i=activate.length-1; i>=index; --i) {
		if (!activate [i].isDisposed ()) {
			activate [i].sendEvent (SWT.Activate);
		}
	}
}

public void setImeInputMode (int mode) {
}

void setInitialBounds () {
}

public void setMinimumSize (int width, int height) {
	checkWidget ();
}

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

public void setRegion (Region region) {
	checkWidget ();
	if ((style & SWT.NO_TRIM) == 0) return;
	if (region != null && region.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
	this.region = region;
}

public void setText (String string) {
	checkWidget ();
	super.setText(string);
	if (window != null) {
		window.title = string;
	}
}

public void setVisible(boolean visible) {
	super.setVisible(visible);
	if (visible) opened = true;
}

UIComponent topComponent() {
	return window != null ? window : super.topComponent();
}

}
