/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.gfui; import gplx.*;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JSeparator;
import javax.swing.border.EmptyBorder;
public class GfuiMenuBar implements GfoInvkAble {
	public Object Under() {return winMenu;}
	public boolean Visible() {return visible;} private boolean visible;
	public void Visible_set(boolean v) {
		this.visible = v;
		MenuBar_visible_set(v);
		boolean menuBandExists = win.Lyt().Bands_has(menuBand.Key());
		if		( visible && !menuBandExists)
			win.Lyt().Bands_add(menuBand);
		else if (!visible &&  menuBandExists)
			win.Lyt().Bands_del(menuBand.Key());
		GftGrid.LytExecRecur(win);
	}	GftBand menuBand = GftBand.fillWidth_().Key_("GfuiMenuBar");
	public void Load_cfg(String cfgKey) {
		try {
			root.ForeColor_(ColorAdp_.Black).BackColor_(ColorAdp_.White);
			root.ExecProps();
			curOwnerItm = root;
			GfsCore._.AddObj(this, "GfuiMenuBar_");
			GfsCore._.ExecRegy("gplx.gfui.GfuiMenuBar.ini");
		}
		catch (Exception e) {GfuiEnv_.ShowMsg(Err_.Message_gplx(e));}
	}
	String separatorText, mnemonicPrefix; int separatorIdx = 0;
	public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
		if		(ctx.Match(k, Invk_visible_toggle))		this.Visible_set(!visible);
		else if (ctx.Match(k, Invk_SeparatorText_))		separatorText = GfoMsgUtl.SetStr(ctx, m, separatorText);
		else if (ctx.Match(k, Invk_MnemonicPrefix_))	mnemonicPrefix = GfoMsgUtl.SetStr(ctx, m, mnemonicPrefix);
		else if	(ctx.Match(k, Invk_Visible_))	{
			boolean v = m.ReadBoolOr("v", true);
			if (ctx.Deny()) return this;
			Visible_set(v);
		}
		else if (ctx.Match(k, Invk_RegTop)) {
			String s = m.ReadStrOr("v", null);
			if (ctx.Deny()) return this;
			GfuiMenuBarItm itm = GfuiMenuBarItm.sub_(root);
			itm.Type_(GfuiMenuBarItmType.Top);
			itm.Text_(s);
			itm.Ipt_(Read_prop_ipt(IptKey_.None, itm));
			itms.Add(s, itm);
			itm.ExecProps();
			curOwnerItm = itm;
		}
		else if (ctx.Match(k, Invk_RegSpr)) {
			String text = m.ReadStr("text");
			if (ctx.Deny()) return this;
			GfuiMenuBarItm itm = GfuiMenuBarItm.sub_(curOwnerItm);
			itm.Type_(GfuiMenuBarItmType.Spr);
			itm.Text_(text);
			itm.Key_(curOwnerItm.Key() + "." + text + Int_.Xto_str(separatorIdx++));
			itm.ExecProps();
		}
		else if (ctx.Match(k, Invk_RegCmd)) {
			String text = m.ReadStr("text");
			String cmd = m.ReadStrOr("cmd", null);
			String tipText = m.ReadStrOr("tipText", null);
			if (ctx.Deny()) return this;
			GfuiMenuBarItm itm = GfuiMenuBarItm.sub_(curOwnerItm);
			itm.Type_(GfuiMenuBarItmType.Cmd);
			itm.Text_(text);
			itm.Cmd_(cmd);
			itm.TipText_(tipText);
			itm.Ipt_(Read_prop_ipt(IptKey_.None, itm));
			itm.Key_(curOwnerItm.Key() + "." + text);
			itm.ExecProps();
		}
		else	return GfoInvkAble_.Rv_unhandled;
		return this;
	}	public static final String Invk_visible_toggle = "MenuBar_toggle"
			, Invk_Visible_ = "Visible_", Invk_SeparatorText_ = "SeparatorText_", Invk_MnemonicPrefix_ = "MnemonicPrefix_"
			, Invk_RegTop = "RegTop", Invk_RegCmd = "RegCmd", Invk_RegSpr = "RegSpr"
			;
	GfuiMenuBarItm curOwnerItm = null;
	IptKey Read_prop_ipt(IptKey ipt, GfuiMenuBarItm itm) {
		if (mnemonicPrefix == null) return ipt;
		String text = itm.Text();
		int pos = String_.FindFwd(text, mnemonicPrefix);
		if (pos == String_.Find_none || pos == String_.Len(text) - 1) return ipt;	// mnemonic not found
		String keyChar = String_.MidByLen(text, pos + 1, 1);
		if (!Char_.IsLetterEnglish(String_.CharAt(keyChar, 0))) return ipt;	// keyChar is not a character; EX: 'A & B' (keyChar = space)
		String keyCharRaw = "key." + String_.Lower(keyChar);
		ipt = IptKey_.parse_(keyCharRaw);
		text = String_.MidByLen(text, 0, pos) + String_.Mid(text, pos + 1);	// remove mnemPrefix; ex: &File -> File && key.f
		itm.Text_(text);
		return ipt;
	}
		void MenuBar_visible_set(boolean v) {winMenu.setVisible(v);}
	void InitMenuBar(GxwWin win) {
		ownerForm = (JFrame)win;
		ownerForm.setJMenuBar(winMenu);
		winMenu.setBorder(GxwBorderFactory.Empty);
	}
	JMenuBar winMenu = new JMenuBar();
	JFrame ownerForm;
		GfuiMenuBarItm root;
	void Init(GfuiWin win) {
		InitMenuBar((GxwWin)win.UnderElem());
		root = GfuiMenuBarItm.root_(winMenu);
		itms.Add(root.Key(), root);
		this.win = win;
		IptBnd_.cmd_to_(GfuiEnv_.IptBndMgr_win, win, this, Invk_visible_toggle, IptKey_.add_(IptKey_.Ctrl, IptKey_.Shift, IptKey_.F12));
		win.SubItms_add(SubItms_key, this);
	}
	HashAdp itms = HashAdp_.new_(); GfuiWin win;
	public static final String SubItms_key = "menuBar";
	public static GfuiMenuBar new_(GfuiWin win) {
		GfuiMenuBar rv = new GfuiMenuBar();
		rv.Init(win);
		return rv;
	}	GfuiMenuBar() {}
}
class GfuiMenuBarItm {
	public String Key() {return key;} public GfuiMenuBarItm Key_(String val) {key = val; return this;} private String key = "";
	public String Text() {return text;} public GfuiMenuBarItm Text_(String val) {text = val; return this;} private String text = "";
	public String Cmd() {return cmd;} public GfuiMenuBarItm Cmd_(String val) {cmd = val; return this;} private String cmd = "";
	public GfuiMenuBarItmType Type() {return type;} public GfuiMenuBarItm Type_(GfuiMenuBarItmType val) {type = val; return this;} GfuiMenuBarItmType type;
	public IptKey Ipt() {return ipt;} public GfuiMenuBarItm Ipt_(IptKey val) {ipt = val; return this;} IptKey ipt;
	public String TipText() {return tipText;} public GfuiMenuBarItm TipText_(String val) {tipText = val; return this;} private String tipText = "";
	public ColorAdp ForeColor() {return foreColor;} public GfuiMenuBarItm ForeColor_(ColorAdp val) {foreColor = val; return this;} ColorAdp foreColor;
	public ColorAdp BackColor() {return backColor;} public GfuiMenuBarItm BackColor_(ColorAdp val) {backColor = val; return this;} ColorAdp backColor;
	public String FontFamily() {return fontFamily;} public GfuiMenuBarItm FontFamily_(String val) {fontFamily = val; return this;} private String fontFamily = "";
	public float FontSize() {return fontSize;} public GfuiMenuBarItm FontSize_(float val) {fontSize = val; return this;} float fontSize = -1;
	public FontStyleAdp FontStyle() {return fontStyle;} public GfuiMenuBarItm FontStyle_(FontStyleAdp val) {fontStyle = val; return this;} FontStyleAdp fontStyle;
	public GfuiMenuBarItm OwnerItm() {return ownerItm;} public GfuiMenuBarItm OwnerItm_(GfuiMenuBarItm val) {ownerItm = val; return this;} GfuiMenuBarItm ownerItm;
	public Object Under() {return under;}
		void ExecProps() {
		if 		(type == GfuiMenuBarItmType.Root) 	Exec_root();
		else if (type == GfuiMenuBarItmType.Cmd)	Exec_cmd();
		else if (type == GfuiMenuBarItmType.Spr) 	Exec_spr();
		else										Exec_mnu();				
	}
	void Exec_root() {
		SetProps((JMenuBar)under);
	}
	void Exec_mnu() {
		JMenu itm = new JMenu(text);
		if 	(ownerItm.type == GfuiMenuBarItmType.Root)
			((JMenuBar)ownerItm.Under()).add(itm);
		else {
			((JMenu)ownerItm.Under()).add(itm);
		}
		SetMnemonic(itm);
		SetProps(itm);
		under = itm;		
	}	
	void Exec_cmd() {
		JMenuItem itm = new JMenuItem(text);
		JMenu ownerMenu = ((JMenu)ownerItm.Under());
		ownerMenu.add(itm);
		itmCmd = GfuiMenuBarItmCmd.new_(this);			
		itm.addActionListener(itmCmd);
		SetMnemonic(itm);
		SetProps(itm);
		under = itm;		
	}
	void Exec_spr() {
		JMenu ownerMenu = ((JMenu)ownerItm.Under());
		JSeparator itm = new JSeparator();
		ownerMenu.add(itm);
		SetProps(itm);
		under = itm;		
	}
	void SetMnemonic(AbstractButton itm) {
		char mnem = GetMnemonic(text, ipt);
		if (mnem != '\0') itm.setMnemonic(mnem); 		
	}
	void SetProps(JComponent itm) {
		if (backColor != null) itm.setBackground(ColorAdpCache._.GetNativeColor(backColor));
		if (foreColor != null) itm.setForeground(ColorAdpCache._.GetNativeColor(foreColor));
		itm.setFont(MakeFont(itm.getFont()));		
		if (String_.Len(tipText) > 0) itm.setToolTipText(tipText);		
	}
	Font MakeFont(Font cur) {
		if (fontFamily == null && fontStyle == null && fontSize == -1) return cur;
		String family = fontFamily == null ? cur.getFamily() : fontFamily;
		int style = fontStyle == null ? cur.getStyle() : fontStyle.Val();
		int size = fontSize == -1 ? cur.getSize() : (int)fontSize;
		return new Font(family, style, (int)size);
	}
	GfuiMenuBarItm Under_(Object o) {under = o; return this;}
	char GetMnemonic(String text, IptKey ipt) {
		if (ipt.Val() == IptKey_.None.Val()) return '\0';
		String iptStr = ipt.XtoUiStr(); if (String_.Len(iptStr) > 1) return '\0';
		return String_.CharAt(iptStr, 0);
	}
	GfuiMenuBarItmCmd itmCmd;
	Object under;
		public static GfoMsg CmdMsg(GfuiMenuBarItm itm) {
		if (itm.cmd == null) throw Err_.null_("cmd was null for menu").Add("key", itm.key).Add("text", itm.text);
		return gplx.gfml.GfmlDataNde.XtoMsgNoRoot(itm.cmd);
	}
	public static GfuiMenuBarItm new_() {return new GfuiMenuBarItm();}
	public static GfuiMenuBarItm sub_(GfuiMenuBarItm owner) {
		GfuiMenuBarItm rv = new_();
		rv.ownerItm = owner;
		rv.foreColor = owner.foreColor;
		rv.backColor = owner.backColor;
		rv.fontFamily = owner.fontFamily;
		rv.fontSize = owner.fontSize;
		rv.fontStyle = owner.fontStyle;
		return rv;
	}
	public static GfuiMenuBarItm root_(Object underMenuBar) {
		GfuiMenuBarItm rv = new GfuiMenuBarItm().Type_(GfuiMenuBarItmType.Root).Key_("root").Under_(underMenuBar);
		return rv;
	}	GfuiMenuBarItm() {}
}
class GfuiMenuBarItmType {
	public int Val() {return val;} int val;
	public String Name() {return name;} private String name;
	GfuiMenuBarItmType(int v, String n) {val = v; name = n; regy.Add(n, this);}
	public static GfuiMenuBarItmType parse_(String raw) {
		try {return (GfuiMenuBarItmType)regy.Fetch(raw);}
		catch (Exception e) {Err_.Noop(e); throw Err_.parse_("GfuiMenuBarItmType", raw);}
	}
	static HashAdp regy = HashAdp_.new_();
	public static final GfuiMenuBarItmType Root = new GfuiMenuBarItmType(1, "root");
	public static final GfuiMenuBarItmType Top = new GfuiMenuBarItmType(2, "top");
	public static final GfuiMenuBarItmType Mnu = new GfuiMenuBarItmType(3, "mnu");
	public static final GfuiMenuBarItmType Cmd = new GfuiMenuBarItmType(4, "cmd");
	public static final GfuiMenuBarItmType Spr = new GfuiMenuBarItmType(5, "spr");
}
class GxwBorderFactory {
	public static final javax.swing.border.Border Empty = new EmptyBorder(0, 0, 1, 0);	
}
class GfuiMenuBarItmCmd implements ActionListener {
	public void actionPerformed(ActionEvent ev) {
		try {
			GfsCore._.ExecOne(GfsCtx._, GfuiMenuBarItm.CmdMsg(itm));
		}
		catch (Exception e) {
			GfuiEnv_.ShowMsg(Err_.Message_gplx(e));
		}
	}
	public static GfuiMenuBarItmCmd new_(GfuiMenuBarItm itm) {
		GfuiMenuBarItmCmd cmd = new GfuiMenuBarItmCmd();
		cmd.itm = itm;
		return cmd;
	}	GfuiMenuBarItm itm;
}
