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

public class Menu extends Widget {
	Decorations parent;
	int x, y, itemCount;
	MenuItem cascade;
	MenuItem[] items;
	boolean hasLocation;

public Menu (Control parent) {
	this (checkNull (parent).menuShell (), SWT.POP_UP);
}

public Menu (Decorations parent, int style) {
	super (parent, checkStyle (style));
}

public Menu (Menu parentMenu) {
	this (checkNull (parentMenu).parent, SWT.DROP_DOWN);
}

public Menu (MenuItem parentItem) {
	this (checkNull (parentItem).parent);
}

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 addMenuListener (MenuListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	TypedListener typedListener = new TypedListener (listener);
	addListener (SWT.Hide,typedListener);
	addListener (SWT.Show,typedListener);
}

static Control checkNull (Control control) {
	if (control == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
	return control;
}

static Menu checkNull (Menu menu) {
	if (menu == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
	return menu;
}

static MenuItem checkNull (MenuItem item) {
	if (item == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
	return item;
}

static int checkStyle (int style) {
	return checkBits (style, SWT.POP_UP, SWT.BAR, SWT.DROP_DOWN, 0, 0, 0);
}

public void createItem(Widget parent, MenuItem menuItem, int style, int index) {
	if (!(0 <= index && index <= itemCount)) error (SWT.ERROR_INVALID_RANGE);
	menuItem._createItem(parent, style, index);
	if (itemCount == items.length) {
		MenuItem [] newItems = new MenuItem [items.length + 4];
		System.arraycopy (items, 0, newItems, 0, items.length);
		items = newItems;
	}
	System.arraycopy (items, index, items, index + 1, itemCount++ - index);
	items [index] = menuItem;
}

void createWidget (Display display, Widget parent, int style, int index) {
	this.parent = (Decorations) parent;
	items = new MenuItem [4];
	super.createWidget(display, parent, style, index);
	this._createHandle(parent, style, index);
	hookEvents ();
	register ();
}

public MenuItem getDefaultItem () {
	return null;
}

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

public MenuItem getItem (int index) {
	return null;
}

public int getItemCount () {
	checkWidget();
	return itemCount;
}

public MenuItem[] getItems () {
	checkWidget ();
	MenuItem [] result = new MenuItem [itemCount];
	int index = 0;
	if (items != null) {
		for (int i = 0; i < itemCount; i++) {
			MenuItem item = items [i];
			if (item != null && !item.isDisposed ()) {
				result [index++] = item;
			}
		}
	}
	if (index != result.length) {
		MenuItem [] newItems = new MenuItem[index];
		System.arraycopy(result, 0, newItems, 0, index);
		result = newItems;
	}
	return result;
}

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

public MenuItem getParentItem () {
	checkWidget ();
	return cascade;
}

public Menu getParentMenu () {
	checkWidget ();
	if (cascade != null) return cascade.parent;
	return null;
}

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

public boolean getVisible () {
	return false;
}

void hookEvents () {
//TODO implement with all events
	_hookClose("_onClose");
}

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

public boolean isEnabled () {
	checkWidget ();
	Menu parentMenu = getParentMenu ();
	if (parentMenu == null) {
		return getEnabled () && parent.isEnabled ();
	}
	return getEnabled () && parentMenu.isEnabled ();
}

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

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 removeMenuListener (MenuListener listener) {
	checkWidget ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	if (eventTable == null) return;
	eventTable.unhook (SWT.Hide, listener);
	eventTable.unhook (SWT.Show, listener);
}

public void setDefaultItem (MenuItem item) {
}

public void setEnabled (boolean enabled) {
	checkWidget ();
	state &= ~DISABLED;
	if (!enabled) state |= DISABLED;
}

public void setLocation (int x, int y) {
	checkWidget ();
	if ((style & (SWT.BAR | SWT.DROP_DOWN)) != 0) return;
	this.x = x;
	this.y = y;
	hasLocation = true;
}

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

public void setVisible (boolean visible) {
	checkWidget ();
//	if (((state & HIDDEN) == 0) == visible) return;
	if (visible && !isDisposed ()) {
		this._setVisible (visible, x, y);
		sendEvent (SWT.Show);
	} else if (!visible && !isDisposed ()) {
		this._setVisible (visible, x, y);
		sendEvent (SWT.Hide);
	}
}

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

protected native void _createHandle (Widget parent, int style, int index) /*-{
	if((style & (@org.eclipse.swt.SWT::BAR)) != 0) {
		if(!$wnd.dojo._hasResource["org.eclipse.swt.BarMenu"]){
			$wnd.dojo._hasResource["org.eclipse.swt.BarMenu"] = true;
			$wnd.dojo.provide("org.eclipse.swt.BarMenu");
			
			$wnd.dojo.require("dijit.Menu");
			$wnd.dojo.require("dijit.Toolbar");
		
			$wnd.dojo.declare("org.eclipse.swt.BarMenu", $wnd.dijit.Toolbar, {
				templateString:
					'<div class="dijit dijitToolbar" waiRole="toolbar" tabIndex="${tabIndex}">' +
						'<table class="dijit dijitMenu dijitReset dijitMenuTable" waiRole="menu">' +
							'<tbody class="dijitReset" dojoAttachPoint="containerNode"></tbody>'+
						'</table>' +
					'</div>',
				onItemClick: function(item){
					if(item.popup)
						if(!this.isOpen){
							item.popup.open({
								around: item.domNode,
								orient: {'BL': 'TL'}
							});
						} else {
							this.close();
						}
				},
				onItemHover: function(item){
					this.focusChild(item);
				},
				onItemUnhover: function(){}
			});
		}
	}
	if((style & (@org.eclipse.swt.SWT::POP_UP | @org.eclipse.swt.SWT::DROP_DOWN)) != 0) {
		if(!$wnd.dojo._hasResource["org.eclipse.swt.PopupMenu"]){
			$wnd.dojo._hasResource["org.eclipse.swt.PopupMenu"] = true;
			$wnd.dojo.provide("org.eclipse.swt.PopupMenu");
			
			$wnd.dojo.require("dijit.Menu");
		
			$wnd.dojo.declare("org.eclipse.swt.PopupMenu", $wnd.dijit.Menu, {
				parent: "",
				isOpen: false,
				_contextKey: function(e){},
				_contextMouse: function(e){},
				_onClose: function(e){
					this._onBlur = function(e){};
				},
				_openMyself: function(e){},
				close: function(){
					$wnd.dijit.popup.close(this);
					this.isOpen = false;
				},
				open: function(config){
					var self = this;
					popupConfig = {
						popup: this,
						onExecute: function (e){self._onClose(e)},
						onCancel: function (e){self._onClose(e)},
						orient: this.isLeftToRight() ? 'L' : 'R'
					}
					$wnd.dijit.popup.open($wnd.dojo.mixin(popupConfig, config));
					this.isOpen = true;
					this.focus();
					this._onBlur = function(e){self._onClose(e);};
				}
			});
		}
	}
	
	var jsParent = parent.@org.eclipse.swt.widgets.Widget::jsObject;
	var params = {};
	if((style & (@org.eclipse.swt.SWT::BAR)) != 0) {
		var self = new $wnd.org.eclipse.swt.BarMenu(params);
		jsParent.addChild(self);
	}
	if((style & (@org.eclipse.swt.SWT::POP_UP)) != 0) {
		var self = new $wnd.org.eclipse.swt.PopupMenu(params);
	}
	if((style & (@org.eclipse.swt.SWT::DROP_DOWN)) != 0) {
		var self = new $wnd.org.eclipse.swt.PopupMenu(params);
	}
	try {
		this.@org.eclipse.swt.widgets.Widget::jsObject = self;
	} catch (e) {
//TODO Have to throw real exception for Java side also	
		$wnd.console.log(e);
	}	
}-*/;

native void _hookClose (String eventType) /*-{
	var self = this;
	$wnd.dojo.connect(
		self.@org.eclipse.swt.widgets.Widget::jsObject,
		eventType, 
		function(e){
 			self.@org.eclipse.swt.widgets.Menu::setVisible(Z)(false);
		}
	);
}-*/;

public native void _setVisible (boolean visible, int x, int y) /*-{
	if (visible) {
		this.@org.eclipse.swt.widgets.Widget::jsObject.open({x: x, y: y});
	} else {
		this.@org.eclipse.swt.widgets.Widget::jsObject.close();
	}
}-*/;

}
