package org.jcon.ui.menu;

import org.jcon.ui.CommandSourceEvent;
import org.jcon.ui.CommandSourceListener;
import org.jcon.ui.DelayWindow;
import org.jcon.ui.WindowTitleBlinker;
import org.jcon.util.BenchMark;
import org.jcon.util.GenLib;
import org.jcon.util.msg.Message;
import org.jcon.util.msg.MessageDef;
import org.jcon.util.msg.MessageListener;
import org.jcon.util.msg.MessageSourceStd;
//import org.jcon.util.security.SecurityServices;
import org.jcon.util.service.ContainerServices;
import org.jcon.util.service.ContainerServicesUser;
import org.jcon.ba.system.BasketServices;
import org.jcon.ba.system.BeanActionClose;
import org.jcon.ba.system.BeanPriv;
import org.jcon.param.Param;
import org.jcon.param.ParamDriven;
import org.jcon.param.ParamDrivenInfo;
import java.awt.CheckboxMenuItem;
import java.awt.Frame;
import java.awt.Window;
import java.awt.event.*;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

/**
 * A wrapper for a MenuFrame that allows use as a Bean instance.
 * It configures itself from a Param and fires Messages
 * when the user selects menu items. PD means ParamDriven.
 *
 * @author Jack Harichw
 */
public class MenuFramePD extends MessageSourceStd
    implements MessageListener, BeanPriv, BeanActionClose,
    ParamDriven, ActionListener, ItemListener,
    MenuItemListListener, CommandSourceListener,
    ContainerServicesUser {

//---------- Private Fields ------------------------------
private BasketServices    basketServices;
private MenuFrame   menuFrame = new MenuFrame();
private Vector      commandPrefixes = new Vector();
//private DelayWindow delayWindow = new DelayWindow();

private String      showMessageName;    // null if none
private String      closeBranchCommand; // null if none
private WindowTitleBlinker blinker = new WindowTitleBlinker();

//---------- Initialization ------------------------------
public MenuFramePD() {
    menuFrame.addActionListener(this);
    menuFrame.addItemListener(this);
    blinker.setWindow((Window)menuFrame.getFrame()); // Use other property defaults

    //delayWindow.setTitle("Patience Is A Virtue");
    //delayWindow.setMessage(
    //    "Constructing task from parameters\n" +
    //    "and loading data....");
}
//---------- MessageSourceStd Abstractions ---------------
public Vector getMessageDefs() {
    Vector defs = new Vector();
    Hashtable defNames = new Hashtable();
    MessageDef def;

    def = new MessageDef(menuFrame.getWindowClosingCommand(), this);
    defs.addElement(def);
    defNames.put(def.getEventName(), "Dummy");

    // Menubar - Includes dynamic menu items
    Enumeration enum = menuFrame.getMenuBarActionCommands();
    while (enum.hasMoreElements()) {
        String command = (String)enum.nextElement();
        def = new MessageDef(command, this);
        // Check commandPrefixes
        for (int i = 0; i < commandPrefixes.size(); i++) {
            String prefix = (String)commandPrefixes.elementAt(i);
            if (command.startsWith(prefix)) {
                // Replace def with special one
                def = new MessageDef(prefix, this);
                def.add("ItemValue", String.class, "MenuListList value, such as file name.");
                break;
            }
        }
        // Add no duplicates
        if (defNames.get(def.getEventName()) == null) {
            defs.addElement(def);
            defNames.put(def.getEventName(), "Dummy");
        }
    }
    return defs;
}
//---------- MessageListener Implementation --------------
public void processMessage(Message message) {
    String name = message.getName();
    //print(".processMessage() - name = '" + name + "'");

    if (name == showMessageName) {
        setVisible(true);
    }
}
public String[] loadMessageInterests() {
    if (showMessageName == null) {
        return new String[0];
    } else {
        return new String[] {showMessageName};
    }
}
//---------- BeanPriv Implementation ---------------------
public void setBasketServices(BasketServices services) {
    basketServices = services;
}
//---------- BeanActionClose Implementation --------------
public String canClose() {
    return null; // null means yes I can close
}
public void close() {
    menuFrame.dispose();
    //delayWindow.close();
}
//---------- ParamDriven Implementation ------------------
public void setParam(Param param) {
    menuFrame.setParam(param);
}
public Param getParam() {
    return menuFrame.getParam(); // May need to build dynamically
}
public boolean applyNewParam(Param newParam) {
    return menuFrame.applyNewParam(newParam);
}
public ParamDrivenInfo getParamDrivenInfo() {
    return null;
}
//---------- ActionListener Implementation ---------------
public void actionPerformed(ActionEvent evt) {
    String command = evt.getActionCommand().intern();
    //print(".actionPerformed() - " + command);

    if (command == closeBranchCommand && closeBranchCommand != null) {
        closeBranch();

    } else {
        //System.out.println("----------------------");
        //print(".actionPerformed() - " + command + " start " + BenchMark.startTimeSeries(0));
        BenchMark.startRun();
            blinker.start();
                fireMessageEvent(new Message(command));
            blinker.stop();
        BenchMark.endRun();

        // Comment out to disable printing run results
        //print(".actionPerformed() - BenchMark run results are:");
        //System.out.println(BenchMark.listRun());

        //print(".actionPerformed() - " + command + " done  " + BenchMark.getTimePoint(0));
    }
}
//---------- ItemListener Implementation -----------------
/**
 * Checkbox menu items have Messages with boolean property
 * "ToggleOn".
 */
public void itemStateChanged(ItemEvent evt) {
    // Poor event design. Tight coupling to source.
    CheckboxMenuItem item = (CheckboxMenuItem)evt.getSource();
    Message message = new Message(item.getActionCommand());
    message.setBoolean("ToggleOn", item.getState());
    fireMessageEvent(message);
}
//---------- MenuItemListListener Implementation ---------
public void menuItemListChanged(MenuItemListEvent evt) {
    menuFrame.menuItemListChanged(evt);
}
//---------- CommandSourceListener Implementation --------
public void commandSourceChanged(CommandSourceEvent evt) {
    menuFrame.commandSourceChanged(evt);
}
//---------- ContainerServicesUser Implementation --------
public void setContainerServices(ContainerServices services) {
    menuFrame.setContainerServices(services);
}
public String[] getContainerServicesInterests() {
    return new String[] {"SecurityServices"};
}  
//---------- Properties ----------------------------------
//----- windowClosingCommand
public void setWindowClosingCommand(String command) {
    menuFrame.setWindowClosingCommand(command);
}
public String getWindowClosingCommand() {
    return menuFrame.getWindowClosingCommand();
}
//----- showMessageName
public void setShowMessageName(String name) {
    showMessageName = name.intern();
}
public String getShowMessageName() {
    return showMessageName;
}
//----- closeBranchCommand
public void setCloseBranchCommand(String command) {
    closeBranchCommand = command.intern();
}
public String getCloseBranchCommand() {
    return closeBranchCommand;
}
//----- visible
public void setVisible(boolean isVisible) {
    menuFrame.setVisible(isVisible);
}
public boolean isVisible() {
    return menuFrame.isVisible();
}
//----- Other
public Frame getFrame() {
    return menuFrame.getFrame();
}
//---------- Public Methods ------------------------------
/**
 * Adding a commandPrefix will cause Messages with that
 * prefix to be translated. The Message eventName will be
 * the prefix and property "ItemValue" will be the remainder
 * of what was the eventName.
 *
 * For example "OpenPriorTreeOrg.jcon.ba.Assembler" becomes
 * eventName = "OpenPriorTree" with "ItemValue" = "Org.jcon.ba.Assembler".
 * This is useful for working with MenuItemList.
 */
public void addCommandPrefix(String commandPrefix) {
    commandPrefixes.addElement(commandPrefix);
}
/**
 * Causes the current param to be applied, ie reset. No
 * result if current param is null.
 */
public void resetParam() {
    menuFrame.applyNewParam(menuFrame.getParam());
}    
//---------- Private Methods -----------------------------
private void fireMessageEvent(Message message) {
    // Translate considering commandPrefixes
    String oldName = message.getName();
    for (int i = 0; i < commandPrefixes.size(); i++) {
        String prefix = (String)commandPrefixes.elementAt(i);
        if (oldName.startsWith(prefix)) {
            message.setName(prefix);
            String suffix = oldName.substring(prefix.length());
            message.set("ItemValue", suffix);
        }
    }
    // Send event to messageRouter
    messageRouter.fire(message, this);
}
private void closeBranch() {
    // Can the branch be closed?
    String reason = basketServices.canCloseItem("this");

    if (reason != null) {
        GenLib.helpfulHint("Sorry, cannot close now because:"
            + "\n" + reason);
    } else {
        basketServices.closeItem("this");
    }
}
//--- Std
private static void print(String text) {
    System.out.println("MenuFramePD" + text);
}

} // End class
