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

public class TabFolder extends Composite {
	TabItem [] items;
	boolean initDojoLayout = false;
	int selection = -1;

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

public void addSelectionListener (SelectionListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	TypedListener typedListener = new TypedListener(listener);
	addListener(SWT.Selection,typedListener);
	addListener(SWT.DefaultSelection,typedListener);
}

static int checkStyle (int style) {
	style = checkBits (style, SWT.TOP, SWT.BOTTOM, 0, 0, 0, 0);
	
	/*
	* Even though it is legal to create this widget
	* with scroll bars, they serve no useful purpose
	* because they do not automatically scroll the
	* widget's client area.  The fix is to clear
	* the SWT style.
	*/
	return style & ~(SWT.H_SCROLL | SWT.V_SCROLL);
}

protected void checkSubclass () {
	if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
}

void createItem (TabItem item, int index) {
	if (items == null) items = new TabItem [4];
	int length = items.length;
	for (int i=0; i<length; i++) {
		if (items [i] == item) return;
	}
	while (index < length) {
		if (items [index] == null) break;
		index++;
	}
	if (index == length) {
		TabItem [] temp = new TabItem [length + 4];
		System.arraycopy (items, 0, temp, 0, length);
		items = temp;
	}
	items [index] = item;
	item._createItem(this, style, index);
//TODO uncomment if necessary	
//	if (index == 0) {
//		Event event = new Event ();
//		event.item = items [0];
//		sendEvent (SWT.Selection, event);
//		// the widget could be destroyed at this point
//	}
}

void createWidget(Display display, Widget parent, int style, int index) {
	super.createWidget(display, parent, style, index);
	items = new TabItem [4];
}

public TabItem getItem (int index) {
	checkWidget ();
	int count = getItemCount ();
	if (!(0 <= index && index < count)) error (SWT.ERROR_INVALID_RANGE);
	return items [index];
}

public int getItemCount () {
	checkWidget ();
	int count = 0;
	while (count < items.length && items[count] != null) count++;
	return count;
}

public TabItem[] getItems () {
	checkWidget ();
	int count = getItemCount ();
	TabItem [] result = new TabItem [count];
	System.arraycopy (items, 0, result, 0, count);
	return result;
}

public TabItem[] getSelection () {
	checkWidget ();
	int index = getSelectionIndex ();
	if (index == -1) return new TabItem [0];
	return new TabItem [] {items [index]};
}

public int getSelectionIndex () {
	checkWidget ();	
	return selection;
}

void hookEvents () {
	super.hookEvents();
	_hookSelectChild("onSelectChild");
}

public int indexOf (TabItem item) {
	checkWidget ();
	if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
	for (int i=0; i<items.length; i++) {
		if (items [i] == item) return i;
	}
	return -1;
}

Point minimumSize (int wHint, int hHint, boolean flushCache) {
	Control [] children = _getChildren ();
	int width = 0, height = 0;
	for (int i=0; i<children.length; i++) {
		Control child = children [i];
		int index = 0;	
		int count = getItemCount();
		while (index < count) {
			if (items [index].control == child) break;
			index++;
		}
		if (index == count) {
			Rectangle rect = child.getBounds ();
			width = Math.max (width, rect.x + rect.width);
			height = Math.max (height, rect.y + rect.height);
		} else {
			Point size = child.computeSize (wHint, hHint, flushCache);
			width = Math.max (width, size.x);
			height = Math.max (height, size.y);
		}
		Point tabListSize = new Point (0, 0);
		_getTabListSize(tabListSize);
		width = Math.max(tabListSize.x, width);
		height += tabListSize.y;
	}
	return new Point (width, height);
}

void releaseChildren (boolean destroy) {
	if (items != null) {
		int count = getItemCount ();
		for (int i=0; i<count; i++) {
			TabItem item = items [i];
			if (item != null && !item.isDisposed ()) {
				item.release (false);
			}
		}
		items = null;
	}
	super.releaseChildren (destroy);
}

void removeControl (Control control) {
	super.removeControl (control);
	for (int i=0; i<items.length; i++) {
		TabItem item = items [i];
		if (item != null && item.control == control) {
			item.setControl (null);
		}
	}
}
void removeItem (TabItem item) {
	int index = 0;
	while (index < items.length) {
		if (items [index] == item) break;
		index++;
	}
	System.arraycopy (items, index + 1, items, index, items.length - index);
	items [items.length - 1] = null;
}

public void removeSelectionListener (SelectionListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	if (eventTable == null) return;
	eventTable.unhook (SWT.Selection, listener);
	eventTable.unhook (SWT.DefaultSelection,listener);	
}

void sendSelection (int selection) {
	setSelection (selection, true);
}

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) {
		int index = getSelectionIndex ();
		if (index != -1) {
			TabItem item = items [index];
			Control control = item.control;
			if (control != null && !control.isDisposed ()) {
				control.setBounds (getClientArea ());
			}				
		} else {
//TODO find better place for initialization and selection of tabFolder item			
			if (!initDojoLayout) {
				_initDojoLayout(0, 0, width, height);
				initDojoLayout = true;
			}
			TabItem item = items [0];
			Control control = item.control;
			if (control != null && !control.isDisposed ()) {
				_setSelection(0);
				control.setBounds (getClientArea ());
			}
		}
	}
	return result;
}

public void setSelection (int index) {
	checkWidget ();
	int count = getItemCount ();
	if (!(0 <= index && index < count)) return;
	setSelection (index, false);
}

void setSelection (int index, boolean notify) {
	int oldIndex = selection;
	if (oldIndex == index) return;
	if (oldIndex != -1) {
		TabItem item = items [oldIndex];
		Control control = item.control;
		if (control != null && !control.isDisposed ()) {
			control.setVisible (false);
		}
	}
	int newIndex = selection = index;
	if (newIndex != -1) {
		if (initDojoLayout) _setSelection (index);
		TabItem item = items [newIndex];
		Control control = item.control;
		if (control != null && !control.isDisposed ()) {
			control.setBounds (getClientArea ());
			control.setVisible (true);
		}
		if (notify) {
			Event event = new Event ();
			event.item = item;
			sendEvent (SWT.Selection, event);
		}
	}
}

public void setSelection (TabItem[] items) {
	checkWidget ();
	if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
	if (items.length == 0) {
		setSelection (-1, false);
	} else {
		for (int i=items.length-1; i>=0; --i) {
			int index = indexOf (items [i]);
			if (index != -1) setSelection (index, false);
		}
	}
}

public void setSelection (TabItem item) {
	checkWidget ();
	if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
	setSelection (new TabItem [] {item});
}

/*--------------------- NATIVE INTERFACE ------------------*/

protected native void _createHandle (Widget parent, int style, int index) /*-{
	if(!$wnd.dojo._hasResource["org.eclipse.swt.TabFolder"]){
		$wnd.dojo._hasResource["org.eclipse.swt.TabFolder"] = true;
		$wnd.dojo.provide("org.eclipse.swt.TabFolder");
		
		$wnd.dojo.require("dijit.layout.TabContainer");
		
		$wnd.dojo.declare(
			"org.eclipse.swt.TabFolder", $wnd.dijit.layout.TabContainer,{
				border: "",
				addChild: function(child, insertIndex){
					if (child.declaredClass == "org.eclipse.swt.TabItem") {
						this.inherited("addChild",arguments);
					}
				},
				getTabListSize: function(){
					this.startup();
					var tlSize = $wnd.swt.getNativeSize(this.tablist.domNode);
//TODO IE needs 4px more in width, find where to get them - margins, pads, borders?					
					return {w: tlSize.w + 4, h: tlSize.h};
				},
				postCreate: function(){
					this.inherited("postCreate",arguments); 
					$wnd.swt.setCssStyle(this.domNode, {border: this.border});
				},
				setWidgetBounds: function(dim){
					var dnContentBox = $wnd.swt.setBounds(this.domNode, dim);
					this._contentBox = {w: dnContentBox.w, h: dnContentBox.h, l: 0, t: 0};
					this.layout();
				}
			}
		);
	}
	
	var jsParent = parent.@org.eclipse.swt.widgets.Widget::jsObject;
	var params = {};
	if((style & (@org.eclipse.swt.SWT::BORDER)) != 0){
		params.border = "1px solid black";
	}
	if((style & (@org.eclipse.swt.SWT::BOTTOM)) != 0){
		params.tabPosition = "bottom";
	} else {
		params.tabPosition = "top";
	}
	var self = new $wnd.org.eclipse.swt.TabFolder(params);
	try {
		this.@org.eclipse.swt.widgets.Widget::jsObject = self;
		jsParent.addChild(self);
	} catch (e) {
//TODO Have to throw real exception for Java side also	
		$wnd.console.log(e);
	}
}-*/;

native void _getTabListSize(Point size) /*-{
	var dim = this.@org.eclipse.swt.widgets.Widget::jsObject.getTabListSize();
	size.@org.eclipse.swt.graphics.Point::x = dim.w;
	size.@org.eclipse.swt.graphics.Point::y = dim.h;
}-*/;

native void _hookSelectChild (String eventType) /*-{
	var self = this;
	$wnd.dojo.connect(
		self.@org.eclipse.swt.widgets.Widget::jsObject.tablist,
		eventType,
		function(arg){
			if (arg.index!=self.@org.eclipse.swt.widgets.TabFolder::selection) {
				self.@org.eclipse.swt.widgets.TabFolder::sendSelection(I)(arg.index);
			}
		}
	);
}-*/;

public native int _setSelection (int index) /*-{
	var self = this.@org.eclipse.swt.widgets.Widget::jsObject;
	self.selectChild(self.getChildren()[index]);
	return index;
}-*/;

native void _initDojoLayout(int x, int y, int width, int height) /*-{
	var self = this.@org.eclipse.swt.widgets.Widget::jsObject;
	self.startup();
	self._contentBox = {w: width, h: height, l: x, t: y};
	self.layout();	
}-*/;

}
