/*******************************************************************************
 * Copyright (c), 2001, 2002 N2 Broadband, Inc.  All Rights Reserved.
 *
 * This module contains unpublished, confidential, proprietary
 * material.  The use and dissemination of this material are
 * governed by a license.  The above copyright notice does not
 * evidence any actual or intended publication of this material.
 *
 * Author:  Drake H. Henderson
 * Created:  11-12-01
 *
 ******************************************************************************/

package com.n2bb.plugins;

import com.n2bb.util.N2bbSettings;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.action.PlugIn;
import org.apache.struts.config.ModuleConfig;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.InputStream;
import java.util.*;

/**
 * Menu generator.
 * <p>
 * Generates menu based on xml file.
 */
public final class MenuPlugIn implements PlugIn {

    private Log n2bbLog = LogFactory.getLog(N2bbSettings.N2BB_LOG);

    private ActionServlet servlet = null;

    private String menuConfig;

    private List menuNames = new ArrayList();

    /** menu name */
    private String menuName = "";
    /** masthead image to go with this menu */
    private String mastheadImage;

    public String getMenuConfig() {
        return menuConfig;
    }

    public void setMenuConfig(String menuConfig) {
        this.menuConfig = menuConfig;
    }

    public String getMenuName() {
        return menuName;
    }

    public void setMenuName(String menuName) {
        this.menuName = menuName;
    }

    public String getMastheadImage() {
        return mastheadImage;
    }

    public void setMastheadImage(String mastheadImage) {
        this.mastheadImage = mastheadImage;
    }

    /*****
     *
     *****/
    public void init(ActionServlet servlet, ModuleConfig config) throws ServletException {
        n2bbLog.debug("enter");

        this.servlet = servlet;

        if (menuConfig == null) {
            menuConfig = servlet.getServletConfig().getInitParameter("menuConfig");
        }

        ServletContext servletContext = servlet.getServletContext();

        try {
            DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder domBuilder = domFactory.newDocumentBuilder();

            InputStream is = servletContext.getResourceAsStream(menuConfig);
            Document menuDoc = domBuilder.parse(is);

            Map topMenuMap = findOrCreateMap(servletContext, "topMenuMap");
            topMenuMap.put(menuName, getTopMenu(menuDoc));
            Map bottomMenuMap = findOrCreateMap(servletContext, "bottomMenuMap");
            bottomMenuMap.put(menuName, getBtmMenu(menuDoc));

            if (mastheadImage != null) {
                Map mastheadImages = findOrCreateMap(servletContext, "mastheadImageMap");
                mastheadImages.put(menuName, mastheadImage);
            }
        }
        catch (Exception e) {
            n2bbLog.error("failed to load menu - message... " + e.getMessage(), e);
        }

    }

    private Map findOrCreateMap(ServletContext servletContext, String mapName) {
        Map map = (Map) servletContext.getAttribute(mapName);
        if (map == null) {
            map = new HashMap();
            servletContext.setAttribute(mapName, map);
        }
        return map;
    }

    /*****
     *
     *****/
    private String getTopMenu(Document menuDoc) {
        Node menuNode = menuDoc.getFirstChild();
        NodeList list = menuNode.getChildNodes(); // top level menu items

        return getMainMenuItems(list);
    }

    /*****
     *
     *****/
    private String getBtmMenu(Document menuDoc) {
        Node menuNode = menuDoc.getFirstChild();
        NodeList list = menuNode.getChildNodes(); // top level menu items

        return getSubMenuBarOpener() + getSubMenus(list) + getCloser() + getInitScript();
    }

    /*****
     *
     *****/
    private String quoted(String text) {
        return "'" + text + "'";
    }

    /*****
     *
     *****/
    private String getMainMenuItems(NodeList list) {
        String mainMenuItems = "";
        for (int i = 0; i < list.getLength(); i++) {
            Node node = list.item(i);

            // if statement used to filter text nodes
            if (node.getNodeName().equals("menuItem")) {

                String id = ((Element) node).getAttribute("id");
                String display = ((Element) node).getAttribute("display");
                String path = ((Element) node).getAttribute("path");

                mainMenuItems += getMainMenuItem(id, display, path);

                menuNames.add(id);
            }
        }
        return mainMenuItems;
    }

    private String getMainMenuItem(String menuName, String display, String path) {
        return "        <td id=" + quoted(menuName + "MainMenu") + ">\n" +
                mainMenuLink(path, display) + "        </td>\n";
    }

    private String mainMenuLink(String path, String display) {
        return "            <a href=" + quoted(path) + " target='_top'>&gt; " + display + "</a>\n";
    }

    private String subMenuLink(String path, String display) {
        return "            <a href=" + quoted(path) + " target='_top'>" + display + "</a>\n";
    }

    /*****
     *
     *****/
    private String getMainMenuCloser() {
        return "        <td style=" + quoted("width: 99%") + ">&nbsp;</td>\n" + "    </tr>\n</table>\n";
    }

    /*****
     *
     *****/
    private String getSubMenuBarOpener() {
        return "<div id=" + quoted("subMenuBar") + ">\n";
    }

    /*****
     *
     *****/
    private String getSubMenus(NodeList list) {
        String subMenus = "";
        for (int i = 0; i < list.getLength(); i++) {
            Node node = list.item(i);

            // if statement used to filter text nodes
            if (node.getNodeName().equals("menuItem")) {

                String id = ((Element) node).getAttribute("id");
                // add sub menu items
                NodeList subList = node.getChildNodes();

                if (subList.getLength() == 0) {
                    continue;
                }

                subMenus += getSubMenuOpener(id);

                for (int j = 0; j < subList.getLength(); j++) {
                    Node subNode = subList.item(j);

                    // if statement used to filter text nodes
                    if (subNode.getNodeName().equals("menuItem")) {

                        String display = ((Element) subNode).getAttribute("display");
                        String path = ((Element) subNode).getAttribute("path");

                        subMenus += getSubMenuItem(display, path);
                    }
                }

                subMenus += getSubMenuCloser();
            }
        }
        return subMenus;
    }

    /*****
     *
     *****/
    private String getSubMenuOpener(String menuName) {
        return "<div id=" + quoted(menuName + "SubMenu") + " style=" +
                quoted("display: none; position: relative") + ">\n" + "<table class=" +
                quoted("sub-menu") + ">\n" + "    <tr>\n";
    }

    private String getSubMenuItem(String display, String path) {
        return "        <td>\n" + subMenuLink(path, display) + "        </td>\n";
    }

    /*****
     *
     *****/
    private String getSubMenuCloser() {
        return "    </tr>\n" + "</table>\n" + "</div>\n";
    }

    /*****
     *
     *****/
    private String getCloser() {
        return "</div>\n"; // close menuBar, subMenuBar
    }

    /*****
     *
     *****/
    private String getInitScript() {
        String script = "<script>\n" + "var menuNames = new Array(";
        for (Iterator iterator = menuNames.iterator(); iterator.hasNext();) {
            String menuName = (String) iterator.next();
            script += quoted(menuName) + (iterator.hasNext() ? ", " : "");
        }
        script +=
                ");\n" + "function initAlignMenu() {\n" + "    alignMenu = new AlignMenu(menuNames);\n" +
                "}\n" + "</script>\n";

        return script;
    }

    /*****
     *
     *****/
    public void destroy() {
        servlet.getServletContext().removeAttribute("topMenuMap");
        servlet.getServletContext().removeAttribute("bottomMenuMap");
        servlet.getServletContext().removeAttribute("mastheadImageMap");
    }

}


