/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2009 Bull S.A.S
 * Contact: jonas-team@ow2.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: AdminHelper.java 18291 2009-08-18 08:48:15Z eyindanga $
 * --------------------------------------------------------------------------
 */
package org.ow2.jonas.lib.management.extensions.base;

import java.util.ArrayList;
import java.util.Hashtable;

import javax.management.MBeanServerConnection;
import javax.management.ObjectName;

import org.ow2.jonas.lib.management.extensions.server.ServerItem;
import org.ow2.jonas.lib.util.JonasObjectName;
import org.ow2.jonas.management.extensions.base.api.ManagementException;

/**
 * Helper class providing basic info about the current server. Used by
 * management tools.
 * @author Adriana Danes
 */
public class AdminHelper {
    // --------------------------------------------------------- Public
    // Constants

    // Deployment identification number
    public final static int DEPLOYMENT = 0;

    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;

    public final static int DOMAIN_DEPLOYMENT = 12;

    // 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 = "*";

    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";

    public final static String DOMAIN_DEPLOYMENT_STRING = "**";

    // ------------- protected fields
    protected int applicationServerPort = 0;

    protected String applicationContextPath = null;

    protected boolean catalinaServer = false;

    protected String currentCatalinaDomainName = null;

    protected String currentCatalinaServiceName = null;

    protected String currentCatalinaEngineName = null;

    protected String currentCatalinaDefaultHostName = null;

    protected boolean jettyServer = false;

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

    protected ObjectName currentJonasServer = null;

    // the current jonas node server selected from the treecontrol
    // this var is used for when plotting current server graphs.
    // its creation is due to ambiguous meaning of currentJonasServerName
    /**
     * @uml.property name="currentClusterDaemon"
     */
    protected ObjectName currentClusterDaemon = null;

    // before adding a server to a clusterd supervivion, the server to be added
    // should be configured
    // to set infos that are neede by this operation
    // this var is the name of the server to be configured.
    protected String currentSrvToConfigure = null;

    /**
     * @uml.property name="currentDomainName"
     */
    protected String currentDomainName = null;

    protected String currentJonasServerName = null;

    // the current cluster daemon name
    /**
     * @uml.property name="currentClusterDaemonName"
     */
    protected String currentClusterDaemonName = null;

    // The server hosting JonasAdmin application
    protected String adminJonasServerName = null;

    // The hosting server's configuration directory
    protected String adminJonasServerConfDir = null;

    protected boolean theCurrentJonasServer = false;

    /**
     * Type of deployment in progress : JAR, EAR, WAR, RAR, DATASOURCE.
     */
    protected int currentJonasDeploymentType = 0;

    /**
     * Hashtable to store cluster daemons attributes. key: clusterd name, value:
     * an attribute
     */
    protected Hashtable<String, Hashtable<String, Integer>> clusterdGraphAttributes = null;

    /**
     * List of servers that are already configured for cluster daemon
     * affactation that means they have jonasBase, JavaHome...(cf clusterd.xml)
     */
    protected Hashtable<String, ServerItem> configuredServerForClusterDaemonList = null;

    /**
     * new cmi Mbeanserver TODO: Remove this before integfrating newCmi to jons.
     */
    protected MBeanServerConnection newCmiMbeanServerConnection = null;

    /**
     * Removed servers for each clusterd used if user did not choose to save
     * server remove operation in clusted.xml
     */
    protected Hashtable<String, ArrayList<String>> removedServersPerClusterd = null;

    protected Hashtable<String, String> variables = new Hashtable();

    /**
     * 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 servlet server.
     * @return The name of the servlet server.
     */
    protected String getServletServerName(final String domainName) throws ManagementException {
        String servletServerName = null;
        ObjectName on = JonasObjectName.webContainerService(domainName);
        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;
    }

    // -----------------------------misc

    public boolean isCatalinaServer() {
        return catalinaServer;
    }

    public String getCurrentCatalinaServiceName() {
        return currentCatalinaServiceName;
    }

    public boolean isCurrentJonasServer() {
        return theCurrentJonasServer;
    }

    public int getCurrentJonasDeploymentType() {
        return currentJonasDeploymentType;
    }

    public void setCurrentJonasDeploymentType(final 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;
    }

    /**
     * @return
     * @uml.property name="currentClusterDaemon"
     */
    public ObjectName getCurrentClusterDaemon() {
        return currentClusterDaemon;
    }

    /**
     * @param currentClusterDaemon
     * @uml.property name="currentClusterDaemon"
     */
    public void setCurrentClusterDaemon(final ObjectName currentClusterDaemon) {
        this.currentClusterDaemon = currentClusterDaemon;
    }

    /**
     * @return
     * @uml.property name="currentClusterDaemonName"
     */
    public String getCurrentClusterDaemonName() {
        return currentClusterDaemonName;
    }

    /**
     * @param currentClusterDaemonName
     * @uml.property name="currentClusterDaemonName"
     */
    public void setCurrentClusterDaemonName(final String currentClusterDaemonName) {
        this.currentClusterDaemonName = currentClusterDaemonName;
    }

    /**
     * @return hashtable containing cluster daemons attributes for graphs
     */
    public Hashtable<String, ?> getClusterdGraphAttributes() {
        return clusterdGraphAttributes;
    }

    public void setClusterdGraphAttributes(final Hashtable<String, Hashtable<String, Integer>> clusterdGraphAttribute) {
        this.clusterdGraphAttributes = clusterdGraphAttribute;
    }

    /**
     *Get a value of given attribute for given cluster daemon
     * @param clusterd the cluster daemon name
     * @param attKey get value of this attribute
     * @return Value of the given attribute for the given cluster daemon -1 else
     * @throws Exception
     */
    public int getClusterdGraphAttribute(final String clusterd, final String attKey) throws Exception {
        int ret = -1;
        try {
            Hashtable<String, Integer> myHash = clusterdGraphAttributes.get(clusterd);
            if (myHash != null) {
                ret = myHash.get(attKey);
            }
        } catch (Exception e) {
            throw new Exception("Cannot find value for attribute " + attKey + " from the cluster daemon named  " + clusterd + e);
        }
        return ret;
    }

    /**
     *Set given value of given attribute for given cluster daemon
     * @param clusterd the cluster daemon name
     * @param attKey set value of this attribute
     * @param Val the value to set
     * @throws Exception
     */
    public void setClusterdGraphAttribute(final String clusterd, final String attKey, final Integer val) throws Exception {
        try {
            Hashtable<String, Integer> myHash = clusterdGraphAttributes.get(clusterd);
            if (myHash != null) {
                // there is already a valur for this key .
                myHash.remove(attKey);
                myHash.put(attKey, val);
            } else {
                // create the hashtable for the clusterd attributes
                clusterdGraphAttributes.put(clusterd, new Hashtable<String, Integer>());
                // and put the given attribute value
                clusterdGraphAttributes.get(clusterd).put(attKey, val);
            }

        } catch (Exception e) {
            throw new Exception("Cannot put value for attribute " + attKey + "for the cluster daemon named " + clusterd + e);
        }

    }

    /**
     * @return the currentSrvToConfigure
     */
    public String getCurrentSrvToConfigure() {
        return currentSrvToConfigure;
    }

    /**
     * @param currentSrvToConfigure the currentSrvToConfigure to set
     */
    public void setCurrentSrvToConfigure(final String currentSrvToConfigure) {
        this.currentSrvToConfigure = currentSrvToConfigure;
    }

    /**
     * The given server has been configuered to be affected to a clusterd.
     * @param srv
     * @throws Exception if the ServerItem parameter is null
     */
    @SuppressWarnings("unchecked")
    public void addSrvConfiguredForClusterd(final ServerItem srv) throws Exception {
        try {
            if (configuredServerForClusterDaemonList == null) {
                configuredServerForClusterDaemonList = new Hashtable();
            }
            configuredServerForClusterDaemonList.remove(srv.getName());
            configuredServerForClusterDaemonList.put(srv.getName(), srv);
        } catch (NullPointerException e) {
            // TODO: handle exception
            throw new Exception("Server item must not be null" + e);
        }
    }

    /**
     * Gets a server item for the given key. this server has been configured for
     * clusterd affectation.
     * @param key
     * @return ServerItem corresponding to the given key. null if not found
     * @throws Exception if the ServerItem parameter is null
     */
    public ServerItem getSrvConfiguredForClusterd(final String key) throws Exception {
        ServerItem ret = null;
        try {
            ret = configuredServerForClusterDaemonList.get(key);
        } catch (NullPointerException e) {
            throw new Exception("Server item name must not be Null " + e);
        } finally {
            return ret;
        }

    }

    /**
     * Checks if the given server is already configured for being affected to a
     * cluster daemon.
     * @param srvName the server to find
     * @return true if the server is already configured for clusterd
     *         affectation.
     * @throws Exception
     */
    // TODO Remove this method. getSrvConfiguredForClusterd should return Null
    // if serverItem not found.
    public boolean isConfiguredForClusterd(final String srvName) throws Exception {
        // ret == true : the server is already configured for clusterd
        // affectation
        boolean ret = false;
        try {
            ret = configuredServerForClusterDaemonList.containsKey(srvName);
        } catch (Exception e) {
            throw new Exception("Server name or configuredServerForClusterDaemonList attribute is null " + e);
        }
        return ret;
    }

    /**
     *clears the configuredServerForClusterDaemonList list
     */
    public void clearConfigureForClusterList() {
        if (configuredServerForClusterDaemonList != null) {
            configuredServerForClusterDaemonList.clear();
        }
    }

    /**
     * @param newCmiMbeanServerConnection the newCmiMbeanServerConnection to set
     */
    public void setNewCmiMbeanServerConnection(final MBeanServerConnection newCmiMbeanServerConnection) {
        this.newCmiMbeanServerConnection = newCmiMbeanServerConnection;
    }

    /**
     * Called when substracting a server to clusterd supervision
     * @param clusterdName the cluster daemon name
     * @param srvName the server to remove
     */
    public void addRemovedServer(final String clusterdName, final String srvName) {
        ArrayList<String> removedServers = removedServersPerClusterd.get(clusterdName);
        if (removedServers == null) {
            removedServers = new ArrayList();
            removedServers.add(srvName);
            removedServersPerClusterd.put(clusterdName, removedServers);
        } else {
            removedServers.add(srvName);
        }
    }

    /**
     * Checks if the given server has been removed from clusterd affectation
     * @param clusterdName
     * @param srvName
     * @return
     */

    public boolean isSrvRemovedFromClusterd(final String clusterdName, final String srvName) {
        ArrayList<String> removedServers = removedServersPerClusterd.get(clusterdName);
        if (removedServers != null) {
            return removedServers.contains(srvName);
        }
        return false;
    }

    /**
     * Called when substracting a server to clusterd supervision
     * @param clusterdName the cluster daemon name
     * @param srvName the server to remove
     */
    public void rmvFromClusterdRemovedList(final String clusterdName, final String srvName) {
        ArrayList<String> removedServers = removedServersPerClusterd.get(clusterdName);
        if (removedServers != null) {
            removedServers.remove(srvName);
        }
    }

    /**
     * Add a value for the given key
     * @param key the key to add
     * @param value to add
     */
    public void addVar(final String key, final String value) {
        variables.remove(key);
        variables.put(key, value);
    }

    /**
     * Remove a variable
     * @param key the variable key
     */
    public void removeVar(final String key) {
        variables.remove(key);
    }

    /**
     * Remove a variable
     * @param key the variable key
     */
    public String getVar(final String key) {
        return variables.get(key);
    }

}
