package junkutil.gui;

import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.nio.charset.UnsupportedCharsetException;
import java.util.HashMap;
import java.util.Map;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JSeparator;
import javax.swing.KeyStroke;

import junkutil.common.StringUtil;


/**
 * シンプルなメニュー作成方法を提供する
 * @author Hiroyuki Shiota
 */
public class LzMenu {

	private JMenuBar menuBar = new JMenuBar();
	private Map menuMap = new HashMap();
	
	/**
	 * コンストラクタ
	 */
	public LzMenu() {
	}
	
	/**
	 * スタブを登録する
	 * ex. addMenu("Foo/Bar/Hoge");
	 * @param menuPath
	 */
	public void addMenu(String menuPath) {
		addMenu(menuPath, new AbstractAction() {
			public void actionPerformed(ActionEvent e) {
				JMenuItem menuItem = (JMenuItem)e.getSource();
			}
		});
	}
	
	/**
	 * コールバックつきのメニューを登録する
	 * ex. addMenu("Foo/Bar/Hoge", new LzCallback(obj, "doHoge"));
	 * @param menuPath
	 * @param callback
	 */
	public void addMenu(String menuPath, LzCallback callback) {
		addMenu(menuPath, callback.getCallbackAction());
	}
	
	/**
	 * アクションを設定する
	 * ex. addMenu("Foo/Bar/Hoge,Ctrl+A", new AbstractAction(){...});
	 * @param menuPath
	 * @param action
	 */
	public void addMenu(String menuPath, Action action) {
		String [] menus = StringUtil.split(menuPath, "/");
		StringBuffer sb = new StringBuffer();
		String parentPath = "";
		String path = "";
		String item = menus[menus.length - 1];
		action.putValue(Action.NAME, item);
		// Menu 
		for (int i = 0; i < menus.length - 1; i++) {
			JMenu menu = new JMenu(menus[i]);
			parentPath = new String(sb);
			if (i == 0) {
			} else {
				sb.append("/");
			}
			sb.append(menus[i]);
			path = new String(sb);
			if (!menuMap.containsKey(path)) {
				menuMap.put(path, menu);
				setupMenuItem(path, menu);
				if (parentPath.length() == 0) {
					menuBar.add(menu);
				} else {
					getMenu(parentPath).add(menu);
				}
			}
		}
		// MenuItem
		if (item.startsWith("-")) {
			if (path.length() != 0) {
				getMenu(path).add(new JSeparator());
			}
		} else {
			JMenuItem menuItem = new JMenuItem(action);
			if (!menuMap.containsKey(menuPath)) {
				menuMap.put(menuPath, menuItem);
				setupMenuItem(menuPath, menuItem);
				if (path.length() == 0) {
					menuBar.add(menuItem);
				} else {
					getMenu(path).add(menuItem);
				}
			}
		}
	}
	
	/**
	 * セットアップメニューアイテム
	 * @param menuPath
	 * @param menuItem
	 */
	private void setupMenuItem(String menuPath, JMenuItem menuItem) {
		String value = menuItem.getText();
		int idx; String text, accelStr;
		char mnemonic = ' ';
		if ((idx = value.indexOf(',')) != -1) {
			text = value.substring(0, idx).trim();
			accelStr = value.substring(idx+1).trim();
		} else {
			text = value.trim();
			accelStr = null;
		}
		int aIdx = text.indexOf('(')+1;
		if (aIdx == -1) return;
		if (aIdx < text.length()) {
			mnemonic = text.charAt(aIdx);
		}
		menuItem.setText(text);
		if (mnemonic != ' ') menuItem.setMnemonic(mnemonic); //ニモニック
		if ((accelStr != null) && (accelStr.indexOf('+') != -1)) {
			String [] accelList = StringUtil.split(accelStr, "+");
			int mask = 0;
			for (int i = 0; i < accelList.length; i++) {
				String accel = accelList[i].toLowerCase();
				if (accel.equals("ctrl")) mask += InputEvent.CTRL_DOWN_MASK;
				if (accel.equals("shift")) mask += InputEvent.SHIFT_DOWN_MASK;
				if (accel.equals("alt")) mask += InputEvent.ALT_DOWN_MASK;
			}
			char keyChar = accelList[accelList.length - 1].toUpperCase().charAt(0);
			//System.out.println(keyChar);
			int keyCode = 0;
			if ('0' <= keyChar && keyChar <= '9') {
				keyCode = KeyEvent.VK_0 + (keyChar - '0');
			} else if ('A' <= keyChar && keyChar <= 'Z') {
				keyCode = KeyEvent.VK_A + (keyChar - 'A');
			} else {
				throw new UnsupportedCharsetException(accelStr);
			}
			menuItem.setAccelerator(KeyStroke.getKeyStroke(keyCode, mask));
		}
	}
	
	/**
	 * メニューバーを取得する
	 * @return
	 */
	public JMenuBar getMenuBar() {
		return menuBar;
	}
	
	/**
	 * メニューを取得する
	 * @param path
	 * @return
	 */
	public JMenu getMenu(String path) {
		return (JMenu)menuMap.get(path);
	}
	
	/**
	 * メニューアイテムを取得する
	 * @param path
	 * @return
	 */
	public JMenuItem getMenuItem(String path) {
		return (JMenuItem)menuMap.get(path);
	}
}
