//*****************************************************************************
/*
** FILE:   xu_FrameConfigManager.java
**
** (c) 1998 Steve Withall.
**
** HISTORY:
**    09May98  stevew  Created, split from xu_FrameConfig.
*/
package xu;

import xe.xe_XmlEngine;

import xm.xm_NodeTypeRegistry;

import xg.xg_Document;
import xg.xg_Element;

import eh.eh_Debug;

import com.sun.java.swing.Action;
import com.sun.java.swing.ImageIcon;
import com.sun.java.swing.JMenuBar;
import com.sun.java.swing.JToolBar;

import java.net.URL;

import java.awt.Dimension;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Toolkit;

import java.util.ResourceBundle;

//*****************************************************************************
/** <p>xu_FrameConfigManager is a repository for configuration details of any kind (ie.
 *  it has no knowledge of what they mean). It also has specific processing for
 *  certain types of configuration: for externally-defined menus and toolbars
 *  (hence the 'Frame' in the class name).</p>
 *
 *  <p>xu_FrameConfigManager can be used for the following purposes:</p>
 *
 *  <LI>Obtaining general configuration values, knowing nothing of their
 *      meaning.
 *
 *  <LI>Setting up menus. It is possible to set up a whole menu bar and all
 *      its menus, or it can set up individual menus one at a time. Note that
 *      xu_FrameConfigManager has a table of the actions supported by the calling
 *      frame, and the appropriate action is automatically associated with
 *      each menu item. (Of course, to do this, the actions must be set up
 *      first - by calling the registerAction and/or registerActions methods.
 *
 *      <p>There are limits to what generic processing can do (though it could
 *      be expanded to handle more), so it is recognised that it may be
 *      necessary to set up certain menus and menu items is a bespoke fashion.
 *      For this reason, xu_FrameConfigManager allows considerable flexibility in how
 *      it is used.</p>
 *
 *  <LI>Setting up a toolbar. As for menu items, each toolbar button is
 *      automatically associated with its action.</p>
 *
 *  <LI>Providing a number of convenience functions, to retrieve the frame's
 *      title, icon image, preferred location and size, etc.
 *
 *  <p>At present, all configuration is read from standard Java resource files
 *  (for the user's default locale) but it is intended to replace these with XML
 *  configuration files.</p>
 */
public class xu_FrameConfigManager extends xg_Document
{
    /** The XML engine, responsible for XML processing. */
    xe_XmlEngine            TheXmlEngine       = null;

    /** The parsed XML document of configuration information. */
    xu_FrameConfigDocument  ConfigDocument     = new xu_FrameConfigDocument();

    /** The parsed XML element of configuration information. */
    xu_FrameConfigElement   ConfigElement      = null;

    /** The pathname of the XML file containing the calling frame's configuration. */
    String                  FilePathnameString = new String();

    /** XML element containing the definition of the menubar. */
    xu_MenuBarElement       TheMenuBarElement  = null;

    /** XML element containing the definition of the toolbar. */
    xu_ToolBarElement       TheToolBarElement  = null;

    //*****************************************************************************
    /** Constructor.
     *
     *  @param InputControlledFrame  The frame whose configuration this is.
     */
    public xu_FrameConfigManager()
    {
        eh_Debug.add(7, "xu_FrameConfigManager: Construct configuration");
    }

    //*****************************************************************************
    /** Load the configuration from the named XML file.
     *
     *  @param  InputConfigFileName  The name of the XML configuration file from
     *                                which to obtain information. It omits its
     *                                '.xml' ending, since locale-specific endings
     *                                are tried as appropriate.
     *  @return                       A flag indicating whether the load was successful
     */
    public boolean load(String  InputConfigFileName)
    {
        boolean  SuccessFlag = true;
        SuccessFlag = ConfigDocument.loadResources(InputConfigFileName);

        if (ConfigElement == null)
            SuccessFlag = loadConfigFile(InputConfigFileName);

        return SuccessFlag;
    }

    //*****************************************************************************
    /** Load the configuration from the named XML file.
     *
     *  @param  InputConfigFileName  The name of the XML configuration file from which
     *                                to obtain information. It omits its '.xml'
     *                                ending, since locale-specific endings are tried
     *                                as appropriate.
     *  @return                      A flag indicating whether the load was successful
     */
    public boolean loadConfigFile(String  InputConfigFileName)
    {
        eh_Debug.add(7, "xu_FrameConfigManager.loadConfigFile: Load config from '" + InputConfigFileName + ".xml'");
        xe_XmlEngine  ConfigXmlEngine    = new xe_XmlEngine();
        ConfigXmlEngine.setVerifyFlag(true);  // We need verification!
        
        String        BasePathname       = InputConfigFileName.replace('.', '/');
        String        FilePathnameString = new String(BasePathname + ".xml");
        boolean       SuccessFlag        = false;  // Be pessimistic!

        registerElementClasses();

        try
        {
            ConfigXmlEngine.parseFile(FilePathnameString, ConfigDocument);

            xg_Element  ChildElement
                          = (xg_Element)ConfigDocument.getFirstChildOfType(xu_FrameConfigElement.RegisteredName);
            if (ChildElement == null)
                eh_Debug.add(2, "xu_FrameConfigManager.loadConfigFile: No '"
                                      + xu_FrameConfigElement.RegisteredName
                                      + "' definition in XML config file");
            else if (ChildElement instanceof xu_FrameConfigElement)
            {
                ConfigElement = (xu_FrameConfigElement)ChildElement;

                // Retrieve the menu bar element.
                xg_Element  FirstMenuBarElement
                              = (xg_Element)ConfigElement.getFirstChildOfType(xu_MenuBarElement.RegisteredName);
                if (FirstMenuBarElement instanceof xu_MenuBarElement)
                    TheMenuBarElement = (xu_MenuBarElement)FirstMenuBarElement;

                // Retrieve the tool bar element.
                xg_Element  FirstToolBarElement
                              = (xg_Element)ConfigElement.getFirstChildOfType(xu_ToolBarElement.RegisteredName);
                if (FirstToolBarElement instanceof xu_ToolBarElement)
                    TheToolBarElement = (xu_ToolBarElement)FirstToolBarElement;

                SuccessFlag = true;
            }
            else
                eh_Debug.add(2, "xu_FrameConfigManager.loadConfigFile: '"
                                      + xu_FrameConfigElement.RegisteredName
                                      + "' element is not an xu_FrameConfigElement object");
        }
        catch (Exception  InputException)
        {
            eh_Debug.add(2, "xu_FrameConfigManager: Error loading XML configuration file '"
                                  + FilePathnameString + "': " + InputException);
            eh_Debug.printStackTrace(2, InputException);
        }

        return SuccessFlag;
    }

    //*****************************************************************************
    /** <p>Register special types of element classes used to represent particular
     *  parts of the configuration.</p>
     *
     *  <p>The present approach isn't ideal: it's static, so affects <b>all</b> XML
     *  parsing, and it doesn't permit the unregistering of all the special
     *  registrations.</p>
     */
    public void registerElementClasses()
    {
        xm_NodeTypeRegistry.setDefaultParserClassName("xe.xe_ElementParser");
        xm_NodeTypeRegistry.setDefaultCustomizerClassName("xc.xc_ElementCustomizer");
        xm_NodeTypeRegistry.setDefaultViewClassName("xv.xv_BoxViewX");

        xm_NodeTypeRegistry.register(xu_FrameConfigElement.RegisteredName,
                                                    "xu.xu_FrameConfigElement");
        xm_NodeTypeRegistry.register(xu_ActionElement.RegisteredName,
                                                    "xu.xu_ActionElement");

        // Support the loading of database drivers during the config loading.
//        xm_NodeTypeRegistry.register(xu_DatabaseDriverElement.RegisteredName,
//                                                    "xu.xu_DatabaseDriverElement");

        xm_NodeTypeRegistry.register(xu_MenuBarElement.RegisteredName,
                                                    "xu.xu_MenuBarElement");
        xm_NodeTypeRegistry.register(xu_MenuElement.RegisteredName,
                                                    "xu.xu_MenuElement");
        xm_NodeTypeRegistry.register(xu_MenuButtonGroupElement.RegisteredName,
                                                    "xu.xu_MenuButtonGroupElement");
        xm_NodeTypeRegistry.register(xu_MenuItemElement.RegisteredName,
                                                    "xu.xu_MenuItemElement");
        xm_NodeTypeRegistry.register(xu_ToolBarElement.RegisteredName,
                                                    "xu.xu_ToolBarElement");
        xm_NodeTypeRegistry.register(xu_ToolBarButtonElement.RegisteredName,
                                                    "xu.xu_ToolBarButtonElement");
    }

    //*****************************************************************************
    /** Add an array of actions to the array of known actions.
     */
    public void registerActions(Action[]  InputActionArray)
    {
        ConfigDocument.registerActions(InputActionArray);
    }

    //*****************************************************************************
    /* Add the InputAction to the hashtable of known actions.
     */
    public void registerAction(Action  InputAction)
    {
        ConfigDocument.registerAction(InputAction);
    }

    //*****************************************************************************
    /** Get the value of the URL whose name is InputResourceName.
     */
    public URL getResourceURL(String  InputResourceName)
    {
        eh_Debug.add(7, "xu_FrameConfigElement.getResourceURL:");
    	String  ResourceValue = getResourceString(InputResourceName);
    	return (convertToURL(ResourceValue) );
    }

    //*****************************************************************************
    /** Get the value of the URL whose name is InputResourceName.
     */
    public URL convertToURL(String  InputValue)
    {
        eh_Debug.add(7, "xu_FrameConfigManager.convertToURL:");
    	URL  ResourceURL = null;
    	if (ConfigElement != null)
    	    ResourceURL = ConfigElement.convertToURL(InputValue);
    	return ResourceURL;
    }

    //*****************************************************************************
    /** Get the value of the string whose name is InputResourceName.
     */
    public String getResourceString(String  InputResourceName)
    {
    	return ConfigDocument.getResourceString(InputResourceName);
    }

    //*****************************************************************************
    /** Get the action registered under the given name.
     */
    public Action getAction(String  InputActionName)
    {
        return ConfigDocument.getAction(InputActionName);
    }

    //*****************************************************************************
    /** Get the tool bar.
     */
    public JToolBar getToolBar()
    {
        JToolBar  TheToolBar = null;
        if (TheToolBarElement != null)
            TheToolBar = TheToolBarElement.getToolBar();
    	return TheToolBar;
    }

    //*****************************************************************************
    /** Get the first menu bar.
     */
    public JMenuBar getMenuBar()
    {
        JMenuBar  TheMenuBar = null;
        if (TheMenuBarElement != null)
            TheMenuBar = TheMenuBarElement.getMenuBar();
    	return TheMenuBar;
    }

    //*****************************************************************************
    /** Get the location and size of the controlled frame. (Presently, the values
     *  are fixed, but it is intended - once we've switched to XML - to obtain them
     *  from the config. file.)
     */
    public Rectangle getFrameRectangle()
    {
        Toolkit    DefaultToolkit = Toolkit.getDefaultToolkit();
        Dimension  ScreenSize     = DefaultToolkit.getScreenSize();
        return (new Rectangle(80, 80, ScreenSize.width - 80, ScreenSize.height - 112) );  //TEMP values
    }

    //*****************************************************************************
    /** Get the icon image for this frame.
     */
    public Image  getFrameIconImage()
    {
	    Image  FrameImage = null;
        URL    IconUrl    = getResourceURL("WindowIconImage");
    	if (IconUrl != null)
    	{
	        ImageIcon  FrameImageIcon = new ImageIcon(IconUrl);
	        FrameImage = FrameImageIcon.getImage();
	    }

    	return FrameImage;
    }

    //*****************************************************************************
    /** Get the title of this frame.
     */
    public String getFrameTitle()
    {
    	return (getResourceString("Title") );
    }

    //*****************************************************************************
    /** Get the text resource bundle.
     */
    public ResourceBundle getResourceBundle()
    {
    	return (ConfigDocument.getResourceBundle() );
    }

    //*****************************************************************************
    /** Output a list of all registered actions to debug.
     */
    public void listToDebug()
    {
        ConfigDocument.listToDebug();
    }
}

//*****************************************************************************
