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

import intrinsic.flash.display.*;
import intrinsic.mx.controls.RadioButtonGroup;
import intrinsic.mx.core.*;

public class Composite extends Scrollable {
	Layout layout;
	Control [] tabList, children;
	int layoutCount, backgroundMode;
	SWTCanvas sprite;
	RadioButtonGroup group;

Composite () {
}

public Composite (Composite parent, int style) {
	super (parent, style);
}

UIComponent parentingComponent() {
	if ((state & CANVAS) != 0) {
		return ((SWTScrollControlBase)object).getContent();
	}
	return object;
}

void addChild(Widget child, int index) {
	UIComponent widget = child.topComponent();
	if (index == -1) {
		parentingComponent().addChildAt(widget, 0);
	} else {
		parentingComponent().addChildAt(widget, index);
	}
}

void addControl (Control control) {
	if (children == null) children = new Control [4];
	int length = children.length;
	for (int i=0; i<length; i++) {
		if (children [i] == control) return;
	}
	int index = 0;
	while (index < length) {
		if (children [index] == null) break;
		index++;
	}
	if (index == length) {
		Control [] temp = new Control [length + 4];
		System.arraycopy (children, 0, temp, 0, length);
		children = temp;
	}
	children [index] = control;
}

Control[] _getChildren () {
	if (children == null) return new Control[0];
	int count = 0;
	int length = children.length;
	while (count < length) {
		if (children [count] == null) break;
		count++;
	}
	Control [] result = new Control [count];
	System.arraycopy (children, 0, result, 0, count);
	return result;
}

Control [] _getTabList () {
	if (tabList == null) return tabList;
	int count = 0;
	for (int i=0; i<tabList.length; i++) {
		if (!tabList [i].isDisposed ()) count++;
	}
	if (count == tabList.length) return tabList;
	Control [] newList = new Control [count];
	int index = 0;
	for (int i=0; i<tabList.length; i++) {
		if (!tabList [i].isDisposed ()) {
			newList [index++] = tabList [i];
		}
	}
	tabList = newList;
	return tabList;
}

UIComponent backgroundControl() {
	if ((state & CANVAS) != 0) return ((SWTScrollControlBase)object).getContent();
	return super.backgroundControl();
}

public void changed (Control[] changed) {
	checkWidget ();
	if (changed == null) error (SWT.ERROR_INVALID_ARGUMENT);
	for (int i=0; i<changed.length; i++) {
		Control control = changed [i];
		if (control == null) error (SWT.ERROR_INVALID_ARGUMENT);
		if (control.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
		boolean ancestor = false;
		Composite composite = control.parent;
		while (composite != null) {
			ancestor = composite == this;
			if (ancestor) break;
			composite = composite.parent;
		}
		if (!ancestor) error (SWT.ERROR_INVALID_PARENT);
	}
	for (int i=0; i<changed.length; i++) {
		Control child = changed [i];
		Composite composite = child.parent;
		while (child != this) {
			if (composite.layout == null || !composite.layout.flushCache (child)) {
				composite.state |= LAYOUT_CHANGED;
			}
			child = composite;
			composite = child.parent;
		}
	}
}

protected void checkSubclass () {
	/* Do nothing - Subclassing is allowed */
}

public Point computeSize (int wHint, int hHint, boolean changed) {
	checkWidget ();
	Point size;
	if (layout != null) {
		if (wHint == SWT.DEFAULT || hHint == SWT.DEFAULT) {
			changed |= (state & LAYOUT_CHANGED) != 0;
			state &= ~LAYOUT_CHANGED;
			size = layout.computeSize (this, wHint, hHint, changed);
		} else {
			size = new Point (wHint, hHint);
		}
	} else {
		size = minimumSize (wHint, hHint, changed);
	}
	if (size.x == 0) size.x = DEFAULT_WIDTH;
	if (size.y == 0) size.y = DEFAULT_HEIGHT;
	if (wHint != SWT.DEFAULT) size.x = wHint;
	if (hHint != SWT.DEFAULT) size.y = hHint;
	Rectangle trim = computeTrim (0, 0, size.x, size.y);
	return new Point (trim.width, trim.height);
}

Control [] computeTabList () {
	Control result [] = super.computeTabList ();
	if (result.length == 0) return result;
	Control [] list = tabList != null ? _getTabList () : _getChildren ();
	for (int i=0; i<list.length; i++) {
		Control child = list [i];
		Control [] childList = child.computeTabList ();
		if (childList.length != 0) {
			Control [] newResult = new Control [result.length + childList.length];
			System.arraycopy (result, 0, newResult, 0, result.length);
			System.arraycopy (childList, 0, newResult, result.length, childList.length);
			result = newResult;
		}
	}
	return result;
}

void createHandle () {
	state |= CANVAS;
	
	sprite = new SWTCanvas();
	sprite.mouseEnabled = false;
	intrinsic.mx.containers.Canvas content = new intrinsic.mx.containers.Canvas();
	content.setStyle("backgroundColor", 0xFFFFFF);
	content.horizontalScrollPolicy = ScrollPolicy.OFF;
	content.verticalScrollPolicy = ScrollPolicy.OFF;
	SWTScrollControlBase widget = new SWTScrollControlBase(content);
	widget.setStyle("borderStyle", hasBorder() ? "inset" : "none");
	widget.horizontalScrollPolicy = (style & SWT.H_SCROLL) != 0 ? ScrollPolicy.ON : ScrollPolicy.OFF;
	widget.verticalScrollPolicy = (style & SWT.V_SCROLL) != 0 ? ScrollPolicy.ON : ScrollPolicy.OFF;
	dummy(widget.viewMetrics);	
	widget.addChild(content);
	content.addChild(sprite);
	
	object = widget;
}

void deregister () {
	super.deregister ();
	if ((state & CANVAS) != 0) {
		display.removeWidget (parentingComponent());
	}
}

void dummy(EdgeMetrics vm) {
}

DisplayObject eventComponent () {
	if ((state & CANVAS) != 0) return parentingComponent();
	return object;
}

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

void fixTabList (Control control) {
	if (tabList == null) return;
	int count = 0;
	for (int i=0; i<tabList.length; i++) {
		if (tabList [i] == control) count++;
	}
	if (count == 0) return;
	Control [] newList = null;
	int length = tabList.length - count;
	if (length != 0) {
		newList = new Control [length];
		int index = 0;
		for (int i=0; i<tabList.length; i++) {
			if (tabList [i] != control) {
				newList [index++] = tabList [i];
			}
		}
	}
	tabList = newList;
}

public int getBackgroundMode () {
	checkWidget ();
	return backgroundMode;
}

public Control[] getChildren () {
	checkWidget ();
	return _getChildren ();
}

public Layout getLayout () {
	checkWidget ();
	return layout;
}

UIComponent getSprite () {
	return sprite;
}

public Control[] getTabList () {
	checkWidget ();
	Control [] tabList = _getTabList ();
	if (tabList == null) {
		int count = 0;
		Control [] list =_getChildren ();
		for (int i=0; i<list.length; i++) {
			if (list [i].isTabGroup ()) count++;
		}
		tabList = new Control [count];
		int index = 0;
		for (int i=0; i<list.length; i++) {
			if (list [i].isTabGroup ()) {
				tabList [index++] = list [i];
			}
		}
	}
	return tabList;
}

public boolean getLayoutDeferred () {
	checkWidget ();
	return layoutCount > 0 ;
}

boolean hooksKeys () {
	return hooks (SWT.KeyDown) || hooks (SWT.KeyUp);
}

void hookEvents () {
	super.hookEvents ();
	if (sprite != null) {
		sprite.addEventListener(SWTCanvas.PAINT, paintHandlerFunction ());
	}
}

public boolean isLayoutDeferred () {
	checkWidget ();
	return findDeferredControl () != null;
}

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

public void layout (boolean changed) {
	checkWidget ();
	if (layout == null) return;
	layout (changed, false);
}

public void layout (boolean changed, boolean all) {
	checkWidget ();
	if (layout == null && !all) return;
	markLayout (changed, all);
	updateLayout (true, all);
}

public void layout (Control[] changed) {
	checkWidget ();
	if (changed == null) error (SWT.ERROR_INVALID_ARGUMENT);
	for (int i=0; i<changed.length; i++) {
		Control control = changed [i];
		if (control == null) error (SWT.ERROR_INVALID_ARGUMENT);
		if (control.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
		boolean ancestor = false;
		Composite composite = control.parent;
		while (composite != null) {
			ancestor = composite == this;
			if (ancestor) break;
			composite = composite.parent;
		}
		if (!ancestor) error (SWT.ERROR_INVALID_PARENT);
	}
	int updateCount = 0;
	Composite [] update = new Composite [16];
	for (int i=0; i<changed.length; i++) {
		Control child = changed [i];
		Composite composite = child.parent;
		while (child != this) {
			if (composite.layout != null) {
				composite.state |= LAYOUT_NEEDED;
				if (!composite.layout.flushCache (child)) {
					composite.state |= LAYOUT_CHANGED;
				}
			}
			if (updateCount == update.length) {
				Composite [] newUpdate = new Composite [update.length + 16];
				System.arraycopy (update, 0, newUpdate, 0, update.length);
				update = newUpdate;
			}
			child = update [updateCount++] = composite;
			composite = child.parent;
		}
	}
	for (int i=updateCount-1; i>=0; i--) {
		update [i].updateLayout (true, false);
	}
}

void markLayout (boolean changed, boolean all) {
	if (layout != null) {
		state |= LAYOUT_NEEDED;
		if (changed) state |= LAYOUT_CHANGED;
	}
	if (all) {
		Control [] children = _getChildren ();
		for (int i=0; i<children.length; i++) {
			children [i].markLayout (changed, all);
		}
	}
}

Point minimumSize (int wHint, int hHint, boolean changed) {
	Control [] children = _getChildren ();
	int width = 0, height = 0;
	for (int i=0; i<children.length; i++) {
		Rectangle rect = children [i].getBounds ();
		width = Math.max (width, rect.x + rect.width);
		height = Math.max (height, rect.y + rect.height);
	}
	return new Point (width, height);
}

void register () {
	super.register ();
	if ((state & CANVAS) != 0) {
		display.addWidget (parentingComponent(), this);
	}
}

void releaseChildren (boolean destroy) {
	Control [] children = _getChildren ();
	for (int i=0; i<children.length; i++) {
		Control child = children [i];
		if (child != null && !child.isDisposed ()) {
			child.release (false);
		}
	}
	super.releaseChildren (destroy);
}

void releaseWidget () {
	super.releaseWidget ();
	layout = null;
	tabList = null;
}

void removeControl (Control control) {
	fixTabList (control);
	int index = 0;
	while (index < children.length) {
		if (children [index] == control) break;
		index++;
	}
	System.arraycopy (children, index + 1, children, index, children.length - index - 1);
	children [children.length - 1] = null;
}

UIComponent resizeComponent () {
	if ((state & CANVAS) != 0) {
		return ((SWTScrollControlBase)object).getContent();
	}
	return super.resizeComponent ();
}

void resized() {
	super.resized();
	if (layout != null) {
		markLayout (false, false);
		updateLayout (false, false);
	}
}

void removeChild(Widget child) {
	UIComponent widget = child.topComponent();
	parentingComponent().removeChild (widget);
}

void handleResize (intrinsic.mx.events.ResizeEvent event) {
	super.handleResize(event);
	if (isDisposed ()) return;
	if (sprite != null) {
		redrawWidget (0, 0, (int)object.width, (int)object.height, false);
	}
}

public void setBackgroundMode (int mode) {
}

int setBounds (int x, int y, int width, int height, int flags) {
	int result = super.setBounds (x, y, width, height, flags);
	if ((result & RESIZED) != 0 && layout != null) {
		markLayout (false, false);
		updateLayout ((result & RESIZED) != 0, false);
	}
	return result;
}

public boolean setFocus () {
	checkWidget ();
	Control [] children = _getChildren ();
	for (int i= 0; i < children.length; i++) {
		if (children [i].setFocus ()) return true;
	}
	return super.setFocus ();
}

public void setLayout (Layout layout) {
	checkWidget ();
	this.layout = layout;
}

public void setLayoutDeferred (boolean defer) {
	if (!defer) {
		if (--layoutCount == 0) {
			if ((state & LAYOUT_CHILD) != 0 || (state & LAYOUT_NEEDED) != 0) {
				updateLayout (true, true);
			}
		}
	} else {
		layoutCount++;
	}
}

boolean setTabGroupFocus () {
	if (isTabItem ()) return setTabItemFocus ();
	boolean takeFocus = (style & SWT.NO_FOCUS) == 0;
	if ((state & CANVAS) != 0) {
		takeFocus = hooksKeys ();
		if ((style & SWT.EMBEDDED) != 0) takeFocus = true;
	}
	if (takeFocus && setTabItemFocus ()) return true;
	Control [] children = _getChildren ();
//	for (int i=0; i<children.length; i++) {
//		Control child = children [i];
//		if (child.isTabItem () && child.setRadioFocus ()) return true;
//	}
	for (int i=0; i<children.length; i++) {
		Control child = children [i];
		if (child.isTabItem () && child.setTabItemFocus ()) return true;
	}
	return false;
}

public void setTabList (Control[] tabList) {
	checkWidget ();
	if (tabList != null) {
		for (int i=0; i<tabList.length; i++) {
			Control control = tabList [i];
			if (control == null) error (SWT.ERROR_INVALID_ARGUMENT);
			if (control.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
			if (control.parent != this) error (SWT.ERROR_INVALID_PARENT);
		}
		Control [] newList = new Control [tabList.length];
		System.arraycopy (tabList, 0, newList, 0, tabList.length);
		tabList = newList;
	} 
	this.tabList = tabList;
}

void updateLayout (boolean resize, boolean all) {
	Composite parent = findDeferredControl ();
	if (parent != null) {
		parent.state |= LAYOUT_CHILD;
		return;
	}
	if ((state & LAYOUT_NEEDED) != 0) {
		boolean changed = (state & LAYOUT_CHANGED) != 0;
		state &= ~(LAYOUT_NEEDED | LAYOUT_CHANGED);
		//TODO-
//		if (resize) setResizeChildren (false);
		layout.layout (this, changed);
//		if (resize) setResizeChildren (true);
	}
	if (all) {
		state &= ~LAYOUT_CHILD;
		Control [] children = _getChildren ();
		for (int i=0; i<children.length; i++) {
			children [i].updateLayout (resize, all);
		}
	}
}

}
