/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999 Bull S.A.
 * Contact: jonas-team@objectweb.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.objectweb.jonas.webapp.jonasadmin;

import java.io.UnsupportedEncodingException;

import javax.management.ObjectName;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionServlet;
import org.objectweb.jonas.common.JProp;
import org.objectweb.jonas.jmx.CatalinaObjectName;
import org.objectweb.jonas.jmx.J2eeObjectName;
import org.objectweb.jonas.jmx.JonasManagementRepr;
import org.objectweb.jonas.jmx.JonasObjectName;
import org.objectweb.jonas.jmx.ManagementException;
import org.objectweb.jonas.webapp.taglib.TreeControl;
import org.objectweb.jonas.webapp.taglib.TreeControlNode;

/**
 * @author Michel-Ange ANTON
 */
public class WhereAreYou {

// --------------------------------------------------------- Public Constants
    /**
     * Exceptions
     */
    public final static String EXCEPTION_MBEANSERVER_NOTFOUND = "error.mbeanserver.notfound";
    public final static String EXCEPTION_JONASSERVER_NOTFOUND = "error.jonasserver.notfound";
    public final static String EXCEPTION_MBEAN_J2EEDOMAIN_NOTFOUND = "error.mbean.j2eedomain.notfound";
    public final static String EXCEPTION_MBEAN_J2EESERVER_NOTFOUND = "error.mbean.j2eeserver.notfound";

    /**
     * Name of the variable in http session
     */
    public final static String SESSION_NAME = "WhereAreYou";

    // Constant environnement
    public final static String TAGS_IMAGES_ROOT_KEY = "tagsimagesroot";
    public final static String CONTEXT_MACRO = "${CONTEXT}";
    public final static String TREE_PAGE_REFRESH = "viewTree.do?select=";

    /**
     * Used separator in the ident node in the tree
     */
    public final static String NODE_SEPARATOR = "*";

    // Deployment identification number
    public final static int DEPLOYMENT_EAR = 1;
    public final static int DEPLOYMENT_JAR = 2;
    public final static int DEPLOYMENT_WAR = 3;
    public final static int DEPLOYMENT_RAR = 4;
    public final static int DEPLOYMENT_DATASOURCE = 5;
    public final static int DEPLOYMENT_JMS = 6;
    public final static int DEPLOYMENT_MAIL = 7;

    // Deployment identification number for domain management
    public final static int DOMAIN_DEPLOYMENT_EAR = 8;
    public final static int DOMAIN_DEPLOYMENT_JAR = 9;
    public final static int DOMAIN_DEPLOYMENT_WAR = 10;
    public final static int DOMAIN_DEPLOYMENT_RAR = 11;

    // Deployment identification string
    public final static String DEPLOYMENT_STRING_EAR = "ear";
    public final static String DEPLOYMENT_STRING_JAR = "jar";
    public final static String DEPLOYMENT_STRING_WAR = "war";
    public final static String DEPLOYMENT_STRING_RAR = "rar";
    public final static String DEPLOYMENT_STRING_DATASOURCE = "datasource";
    public final static String DEPLOYMENT_STRING_JMS = "jms";
    public final static String DEPLOYMENT_STRING_MAILFACTORY = "mail";

//  Deployment identification strings for domain management
    public final static String DOMAIN_DEPLOYMENT_STRING_EAR = "domain-ear";
    public final static String DOMAIN_DEPLOYMENT_STRING_JAR = "domain-jar";
    public final static String DOMAIN_DEPLOYMENT_STRING_WAR = "domain-war";
    public final static String DOMAIN_DEPLOYMENT_STRING_RAR = "domain-rar";

// --------------------------------------------------------- Properties variable

    private String imagesRoot = null;
    private TreeControl treeControl = null;
    private boolean treeToRefresh = false;

    private int applicationServerPort = 0;
    private String applicationContextPath = null;

    private boolean catalinaServer = false;
    private String currentCatalinaDomainName = null;
    private String currentCatalinaServiceName = null;
    private String currentCatalinaEngineName = null;
    private String currentCatalinaDefaultHostName = null;
    private boolean jettyServer = false;

    // J2EE Management information (used in construction of JSR77 ObjectNames)
    // These names correspond to the server being currently managed
    private ObjectName currentDomain = null;
    private ObjectName currentJonasServer = null;
    private String currentDomainName = null;
    private String currentJonasServerName = null;

    // The server hosting JonasAdmin application
    private String adminJonasServerName = null;
    // The hosting server's configuration directory
    private String adminJonasServerConfDir = null;
    private boolean theCurrentJonasServer = false;
    /**
     * Type of deployment in progress : JAR, EAR, WAR, RAR, DATASOURCE.
     */
    private int currentJonasDeploymentType = 0;


// --------------------------------------------------------- Constructor

    public WhereAreYou() {
        try {
            // Get the name of the Jonas Server who is running the application
            JProp oJProp = JProp.getInstance();
            adminJonasServerName = oJProp.getValue(JProp.JONAS_NAME);
            adminJonasServerConfDir = oJProp.getConfDir();
            currentDomainName = oJProp.getValue(JProp.DOMAIN_NAME);
            currentDomain = J2eeObjectName.J2EEDomain(currentDomainName);
            currentJonasServerName = adminJonasServerName;
            currentJonasServer = J2eeObjectName.J2EEServer(currentDomainName, currentJonasServerName);
        } catch (Exception e) {
            // Current Jonas not found, can't run jonasAdmin
            throw new JonasAdminException(EXCEPTION_JONASSERVER_NOTFOUND, e.getMessage(), e);
        }
    }

// --------------------------------------------------------- Public Methods

    /**
     * Initialize the properties in only reading.
     *
     * @param p_Servlet The instance of servlet to access to the parameter of the servlet config
     * @param p_Request The request to access to the HTTP informations
     * @throws JonasAdminException
     */
    public void initialize(ActionServlet p_Servlet, HttpServletRequest p_Request)
        throws JonasAdminException {
        // Tags Images Root directory
        String sImagesRoot = (String) p_Servlet.getServletConfig().getInitParameter(
            TAGS_IMAGES_ROOT_KEY);
        if (sImagesRoot != null) {
            sImagesRoot = JonasAdminJmx.replace(sImagesRoot, CONTEXT_MACRO
                , p_Request.getContextPath());
        }
        this.imagesRoot = sImagesRoot;
        refreshServers(p_Request, currentJonasServerName);
    }

    /**
     * Return the current Jonas server name.
     *
     * @return The name
     */
    public String getCurrentJonasServerName() {
        return currentJonasServerName;
    }

    /**
     * Return the ObjectName of the MBean associated to the current Jonas server.
     *
     * @return The ObjectName
     */
    public ObjectName getCurrentJonasServer() {
        return currentJonasServer;
    }

    /**
     * Return the current J2EE domain ObjectName.
     *
     * @return The ObjectName
     */
    public ObjectName getCurrentDomain() {
        return currentDomain;
    }

    /**
     * Return the current J2EE domain name.
     *
     * @return The name
     */
    public String getCurrentDomainName() {
        return currentDomainName;
    }

    /**
     * Return the name of the selected node in the tree.
     *
     * @return The name
     */
    public String getSelectedNameNode() {
        if (treeControl != null) {
            TreeControlNode oNode = treeControl.getSelected();
            if (oNode != null) {
                return oNode.getName();
            }
        }
        return null;
    }

    /**
     * Return the URL to refresh the selected node in the tree.
     *
     * @param p_Request HTTP request
     * @param p_Response HTTP response
     * @return The URL
     */
    public String getUrlToRefreshSelectedNode(HttpServletRequest p_Request
        , HttpServletResponse p_Response) {
        if (treeControl != null) {
            TreeControlNode oNode = treeControl.getSelected();
            if (oNode != null) {
                // Disable refresh
                treeToRefresh = false;
                // Build URL refresh
                String encodedName = null;
                try {
                    encodedName = java.net.URLEncoder.encode(oNode.getName(), "UTF-8");
                } catch (UnsupportedEncodingException e) {
                    // Node name can't be encoded
                    encodedName = oNode.getName();
                }
                StringBuffer sb = new StringBuffer();
                sb.append(p_Request.getContextPath());
                sb.append("/");
                sb.append(TREE_PAGE_REFRESH);
                sb.append(encodedName);
                // Force the browser to refresh the tree (Netscape and Mozilla)
                sb.append("&s=");
                sb.append(Math.random());

                return p_Response.encodeURL(sb.toString());
            }
        }
        return null;
    }

    /**
     * Select the node in the tree.
     *
     * @param p_Name The name of node to select
     * @param p_Expand Expand parent branch
     */
    public void selectNameNode(String p_Name, boolean p_Expand) {
        if (treeControl != null) {
            // Changing node ?
            if (p_Name.equals(getSelectedNameNode()) == false) {
                // Change node
                treeControl.selectNode(p_Name);
                if (p_Expand == true) {
                    treeControl.expandSelectedParents();
                }
                treeToRefresh = true;
            }
            // Query node not found
            if ((getSelectedTreeControlNode() == null) && (p_Name != null) && (p_Name.length() > 0)) {
                // Try to select the parent node
                String s = p_Name.substring(0, p_Name.lastIndexOf(WhereAreYou.NODE_SEPARATOR));
                if ((s != null) && (s.length() > 0)) {
                    selectNameNode(s, p_Expand);
                }
            }
        }
    }

    /**
     * Return the selected node in the tree.
     *
     * @return The selected node
     */
    public TreeControlNode getSelectedTreeControlNode() {
        if (treeControl != null) {
            return treeControl.getSelected();
        }
        return null;
    }

    /**
     * Return the state of current display of tree.
     *
     * @return True if the current tree is not correctly displaying
     */
    public boolean isTreeToRefresh() {
        return treeToRefresh;
    }

    /**
     * Change the state of current display of tree.
     *
     * @param treeToRefresh True to refresh
     */
    public void setTreeToRefresh(boolean treeToRefresh) {
        this.treeToRefresh = treeToRefresh;
    }

    /**
     * Refresh all the servers properties.
     *
     * @param p_Request The request to access to the HTTP informations
     * @throws ManagementException if could not connect to the MBeanServer
     * @throws JonasAdminException
     */
    public void refreshServers(HttpServletRequest p_Request, String serverName)
        throws ManagementException, JonasAdminException {
        refreshJonas(p_Request, serverName);
        applicationServerPort = p_Request.getServerPort();
        applicationContextPath = p_Request.getContextPath();
        refreshCatalina(p_Request);
        refreshJetty(p_Request);
    }
    public void refreshServers(HttpServletRequest p_Request) {
    	// Nothing to do, no server change
    }
    /**
     * Refresh the Catalina server properties.
     *
     * @param p_Request The request to access to the HTTP informations
     */
    public void refreshCatalina(HttpServletRequest p_Request) {
        resetCatalina();
        try {
            String servletServerName = getServletServerName();
            if (servletServerName == null) {
                return;
            }
            String sServer = servletServerName.toLowerCase();
            catalinaServer = (sServer.indexOf("tomcat") > -1);
            if (catalinaServer) {
                ObjectName onServer = JonasAdminJmx.getFirstMbean(CatalinaObjectName.catalinaServer(), currentJonasServerName);
                ObjectName[] aonServices = (ObjectName[]) JonasManagementRepr.getAttribute(onServer
                , "serviceNames", currentJonasServerName);
                // Service : the first !
                currentCatalinaServiceName = aonServices[0].getKeyProperty("serviceName");
                // Domain
                currentCatalinaDomainName = aonServices[0].getDomain();
                // Engine
                currentCatalinaEngineName = currentCatalinaDomainName;
                ObjectName onEngine = CatalinaObjectName.catalinaEngine(currentCatalinaDomainName);
                // Default Host
                currentCatalinaDefaultHostName = (String) JonasManagementRepr.getAttribute(onEngine
                , "defaultHost", currentJonasServerName);
            }
        } catch (Exception e) {
            // none
        }
    }

    /**
     * Refresh the Jetty server properties.
     *
     * @param p_Request The request to access to the HTTP informations
     */
    public void refreshJetty(HttpServletRequest p_Request) {
        resetJetty();
        try {
            String servletServerName = getServletServerName();
            if (servletServerName == null) {
                return;
            }
            String sServer = servletServerName.toLowerCase();
            jettyServer = (sServer.indexOf("jetty") > -1);
            if (jettyServer == true) {
                // none action
            }
        }
        catch (Exception e) {
            // none
        }
    }

    /**
     * Refresh the managed JOnAS server properties.
     *
     * @param p_Request The request to access to the HTTP informations
     * @throws ManagementException if could not connect to the MBeanServer
     * @throws JonasAdminException
     */
    public void refreshJonas(HttpServletRequest p_Request, String serverName)
        throws ManagementException, JonasAdminException {
        resetJonas();
        // Set J2EEServer information
        currentJonasServerName = serverName;
        currentJonasServer = J2eeObjectName.J2EEServer(currentDomainName, serverName);

        // Detect if the current managed JOnAS server is the one where the application is running
        theCurrentJonasServer = adminJonasServerName.equals(currentJonasServerName);

    }

    /**
     * Return in a string the contents of the instance for each propertie.
     * Debug utility.
     *
     * @return The string contents
     */
    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append("imagesRoot=[").append(imagesRoot).append("] ");
        sb.append("treeControl=[").append(treeControl).append("] ");
        sb.append("catalinaServer=[").append(catalinaServer).append("] ");
        return sb.toString();
    }

// --------------------------------------------------------- Protected Methods

    /**
     * Return the name of the servlet server.
     * @return The name of the servlet server.
     */
    protected String getServletServerName() throws ManagementException {
        String servletServerName = null;
        ObjectName on = JonasObjectName.webContainerService();
        if (JonasManagementRepr.isRegistered(on, currentJonasServerName)) {
            servletServerName = (String) JonasManagementRepr.getAttribute(on, "ServerName", currentJonasServerName);
        }
        return servletServerName;
    }

    /**
     * Reset the Catalina server properties.
     */
    protected void resetCatalina() {
        catalinaServer = false;
        currentCatalinaServiceName = null;
    }

    /**
     * Reset the Jetty server properties.
     */
    protected void resetJetty() {
        jettyServer = false;
    }

    /**
     * Reset the JOnAS server properties.
     */
    protected void resetJonas() {
        theCurrentJonasServer = false;
        currentJonasServer = null;
        currentJonasServerName = null;
    }

    /**
     * Reset the domain properties.
     */
    protected void resetDomain() {
        currentDomain = null;
        currentDomainName = null;
    }

// --------------------------------------------------------- Properties Methods

    public String getImagesRoot() {
        return imagesRoot;
    }

    public TreeControl getTreeControl() {
        return treeControl;
    }

    public void setTreeControl(TreeControl treeControl) {
        this.treeControl = treeControl;
    }

    public boolean isCatalinaServer() {
        return catalinaServer;
    }

    public String getCurrentCatalinaServiceName() {
        return currentCatalinaServiceName;
    }

    public boolean isCurrentJonasServer() {
        return theCurrentJonasServer;
    }

    public int getCurrentJonasDeploymentType() {
        return currentJonasDeploymentType;
    }

    public void setCurrentJonasDeploymentType(int currentJonasDeploymentType) {
        this.currentJonasDeploymentType = currentJonasDeploymentType;
    }

    public int getApplicationServerPort() {
        return applicationServerPort;
    }

    public String getApplicationContextPath() {
        return applicationContextPath;
    }

    public String getCurrentCatalinaDefaultHostName() {
        return currentCatalinaDefaultHostName;
    }

    public String getCurrentCatalinaEngineName() {
        return currentCatalinaEngineName;
    }

    public String getCurrentCatalinaDomainName() {
        return currentCatalinaDomainName;
    }

    public boolean isJettyServer() {
        return jettyServer;
    }
    /**
     * @return Returns the adminJonasServerName.
     */
    public String getAdminJonasServerName() {
        return adminJonasServerName;
    }

    public String getAdminJonasServerConfDir() {
        return adminJonasServerConfDir;
    }
}
