/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2006-2007 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$
 * --------------------------------------------------------------------------
 */
package org.ow2.jonas.cluster.daemon;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.net.URI;
import java.net.URL;
import java.util.Properties;

import org.ow2.carol.rmi.util.PortNumber;
import org.ow2.carol.util.configuration.CarolDefaultValues;
import org.ow2.carol.util.configuration.ConfigurationRepository;
import org.ow2.carol.util.configuration.ProtocolConfiguration;
import org.ow2.jonas.cluster.daemon.api.ClusterDaemonException;
import org.ow2.jonas.deployment.clusterd.ClusterDaemonConfiguration;
import org.ow2.jonas.deployment.clusterd.ClusterDaemonConfigurationException;
import org.ow2.jonas.deployment.clusterd.lib.ClusterDaemonConfigurationManager;
import org.ow2.jonas.lib.bootstrap.JProp;


/**
 *  Commons tools
 */

public class ClusterDaemonTools  {


    public static Long ONE_MEGA=new Long(1024);


    /**
     * Current cluster configuration (loaded)
     */
    private static ClusterDaemonConfiguration currentConfiguration = null;


    /**
     * Current cluster daemon configuration file (loaded)
     */
    private static String currentConfigurationFileName = null;

    /**
     *  constructor
     */
    private ClusterDaemonTools() {

    }

    /**
     * Init carol.
     *
     * @throws ClusterDaemonException
     *             if an error occurs
     * @return the configuration file.
     */
    public static String initCarol() throws ClusterDaemonException {
        System.setProperty("carol.server.mode", "true");
        String carolFile = null;
        try {
            // hack
            Writer fw;
            File fConf = null;
            if (carolFile == null) {
                // 1st, try to use the carol.properties in $JONAS_BASE/conf
                File jonasBaseConf = new File(JProp.getJonasBase(), "conf");
                URL myCarolFile = new File(jonasBaseConf, CarolDefaultValues.CAROL_CONFIGURATION_FILE).toURI().toURL();

                if (myCarolFile == null) {
                    fConf = new File(System.getProperty("java.io.tmpdir")
                            + File.separator + "cs-carol.properties");
                    try {
                        fw = new FileWriter(fConf);
                        fw.write("carol.protocols=irmi\n");
                        fw.write("carol.irmi.url=rmi://localhost:1806\n");
                        // fw.write("carol.jvm.rmi.local.registry=true");
                        fw.close();
                    } catch (IOException e) {
                        throw new ClusterDaemonException(
                                "Cannot initialize carol", e);
                    }
                } else {
                    fConf = new File(myCarolFile.getFile());
                }
            } else {
                fConf = new File(carolFile);
            }
            ConfigurationRepository.init(fConf.toURL());
        } catch (Exception e) {
            throw new ClusterDaemonException("Cannot initialize carol", e);
        }
        return carolFile;
    }

    /**
     * Get the JMX URL of a server
     * @param host The host of the server
     * @param port The JMX port of the server
     * @param serverName The name of the server
     * @param carolProtocol The RMI protocol
     * @return the JMX url of the server
     * @throws ClusterDaemonException
     */
    public static String getJmxUrl(final String host, final String port, final String serverName,
                                   final String carolProtocol)
        throws ClusterDaemonException {

        String serviceURL = null;
        try {
            if ("jrmp".equals(carolProtocol)) {
                // Treat RMI/JRMP case
                String myName = "jrmpconnector_" + serverName;
                serviceURL = "service:jmx:rmi://" + host;
                int jrmpExportedPort = 0;
                // Add port number of exported objects if one is set by carol.
                String propertyName = CarolDefaultValues.SERVER_JRMP_PORT;
                Properties p = ConfigurationRepository.getProperties();
                if (p != null) {
                    jrmpExportedPort = PortNumber.strToint(p.getProperty(propertyName, "0"), propertyName);
                }
                if (jrmpExportedPort > 0) {
                    serviceURL += ":" + jrmpExportedPort;
                }
                serviceURL += "/jndi/rmi://" + host + ":" + port + "/" + myName;
            } else if ("irmi".equals(carolProtocol)) {
                // Treat RMI/IRMI case
                String myName = "irmiconnector_" + serverName;
                serviceURL = "service:jmx:rmi://" + host;
                int irmiExportedPort = 0;
                // Add port number of exported objects if one is set by carol.
                String propertyName = CarolDefaultValues.SERVER_IRMI_PORT;
                Properties p = ConfigurationRepository.getProperties();
                if (p != null) {
                    irmiExportedPort = PortNumber.strToint(p.getProperty(propertyName, "0"), propertyName);
                    // Add 1 to this port for IRMI as the JMX object will not
                    // use IRMI to bind but JRMP methods.
                    irmiExportedPort++;
                }
                if (irmiExportedPort > 1) {
                    serviceURL += ":" + irmiExportedPort;
                }
                serviceURL += "/jndi/rmi://" + host + ":" + port + "/" + myName;
            } else if ("iiop".equals(carolProtocol)) {
                // Treat RMI/IIOP case
                String myName = "iiopconnector_" + serverName;

                serviceURL = "service:jmx:iiop://" + host + "/jndi/iiop://" + host + ":" + port + "/" + myName;
            }
        } catch (Exception e) {
            throw new ClusterDaemonException("Cannot get JMX URL", e);
        }
        return serviceURL;
    }


    
    /**
     * Build the JMX url connection
     * @param cdName cluster daemon name
     * @return JMX url
     * @throws ClusterDaemonException if an error occurs
     */
    public static String getJmxUrl(String cdName) throws ClusterDaemonException {

        // Determine protocols used by Carol and their configuration, only the current one is considered
        String serviceURL = null;
        try {
            initCarol();
            ProtocolConfiguration protocolConfiguration = ConfigurationRepository.getCurrentConfiguration();
            ConfigurationRepository.setCurrentConfiguration(protocolConfiguration);
            String carolProtocol = protocolConfiguration.getName();
            String providerUrl = protocolConfiguration.getProviderURL();
            URI carolURL = new URI(providerUrl);
            String host = carolURL.getHost();
            String port = String.valueOf(carolURL.getPort());
            String scheme = carolURL.getScheme();

            if (scheme.equals("rmi") && carolProtocol.equals("jrmp")) {
                // Treat RMI/JRMP cas
                String myName = "jrmpconnector_" + cdName;
                serviceURL = "service:jmx:rmi://" + host;
                int jrmpExportedPort = 0;
                // Add port number of exported objects if one is set by carol.
                String propertyName = CarolDefaultValues.SERVER_JRMP_PORT;
                Properties p = ConfigurationRepository.getProperties();
                if (p != null) {
                    jrmpExportedPort = PortNumber.strToint(p.getProperty(propertyName, "0"), propertyName);
                }
                if (jrmpExportedPort > 0) {
                    serviceURL += ":" + jrmpExportedPort;
                }
                serviceURL += "/jndi/rmi://" + host + ":" + port + "/" + myName;
            } else if (scheme.equals("rmi") && carolProtocol.equals("irmi")) {
                // Treat RMI/IRMI cas
                String myName = "irmiconnector_" + cdName;
                serviceURL = "service:jmx:rmi://" + host;
                int irmiExportedPort = 0;
                // Add port number of exported objects if one is set by carol.
                String propertyName = CarolDefaultValues.SERVER_IRMI_PORT;
                Properties p = ConfigurationRepository.getProperties();
                if (p != null) {
                    irmiExportedPort = PortNumber.strToint(p.getProperty(propertyName, "0"), propertyName);
                    // Add 1 to this port for IRMI as the JMX object will not
                    // use IRMI to bind but JRMP methods.
                    irmiExportedPort++;
                }
                if (irmiExportedPort > 1) {
                    serviceURL += ":" + irmiExportedPort;
                }
                serviceURL += "/jndi/rmi://" + host + ":" + port + "/" + myName;
            } /*else if (scheme.equals("jrmi")) {
                // Treat JEREMIE case
                String myName = "jeremieconnector_" + cdName;
                serviceURL = "service:jmx:rmi://" + host;
                int jeremieExportedPort = 0;
                // Add port number of exported objects if one is set by carol.
                String propertyName = CarolDefaultValues.SERVER_JEREMIE_PORT;
                Properties p = ConfigurationRepository.getProperties();
                if (p != null) {
                    jeremieExportedPort = PortNumber.strToint(p.getProperty(propertyName, "0"), propertyName);
                    // Add 1 to this port for jeremie as the JMX object will not
                    // use jeremie to bind but JRMP methods.
                    jeremieExportedPort++;
                }
                if (jeremieExportedPort > 1024) {
                    serviceURL += ":" + jeremieExportedPort;
                }
                serviceURL += "/jndi/jrmi://" + host + ":" + port + "/" + myName;

            } */else if (scheme.equals("cmi")) {
                // Treat CMI case
                String myName = "cmiconnector_" + cdName;
                serviceURL = "service:jmx:rmi://" + host;

                int jrmpExportedPort = 0;
                // Add port number of exported objects if one is set by carol.
                String propertyName = CarolDefaultValues.SERVER_JRMP_PORT;
                Properties p = ConfigurationRepository.getProperties();
                if (p != null) {
                    jrmpExportedPort = PortNumber.strToint(p.getProperty(propertyName, "0"), propertyName);
                }
                if (jrmpExportedPort > 0) {
                    serviceURL += ":" + jrmpExportedPort;
                }
                serviceURL += "/jndi/cmi://" + host + ":" + port + "/" + myName;


            } else if (scheme.equals("iiop")) {
                // Treat RMI/IIOP case
                String myName = "iiopconnector_" + cdName;

                serviceURL = "service:jmx:iiop://" + host + "/jndi/iiop://" + host + ":" + port + "/" + myName;
            }
        } catch (Exception e) {
            throw new ClusterDaemonException("Cannot get JMX URL", e);
        }
        return serviceURL;

    }

    /**
     * Build the Object Name
     * @return Object name
     * @throws ClusterDaemonException if an error occurs
     */
    public static String getObjectName() throws ClusterDaemonException {

        // Determine protocols used by Carol and their configuration, only the current one is considered
        String objName = null;
        try {
            ProtocolConfiguration protocolConfiguration = ConfigurationRepository.getCurrentConfiguration();
            ConfigurationRepository.setCurrentConfiguration(protocolConfiguration);
            String carolProtocol = protocolConfiguration.getName();
            String providerUrl = protocolConfiguration.getProviderURL();
            URI carolURL = new URI(providerUrl);
            String scheme = carolURL.getScheme();

            if (scheme.equals("rmi") && carolProtocol.equals("jrmp")) {
                // Treat RMI/JRMP cas
                objName = "connectors:protocol=jrmp, name=cs_connector";
            } else if (scheme.equals("rmi") && carolProtocol.equals("irmi")) {
                // Treat RMI/IRMI cas
                objName = "connectors:protocol=irmi, name=cs_connector";
            } else if (scheme.equals("jrmi")) {
                // Treat JEREMIE case
                objName = "connectors:protocol=jrmi, name=cs_connector";
            } else if (scheme.equals("cmi")) {
                // Treat CMI case
                objName = "connectors:protocol=cmi, name=cs_connector";

            } else if (scheme.equals("iiop")) {
                // Treat RMI/IIOP case
                objName = "connectors:protocol=iiop, name=cs_connector";
            }
        } catch (Exception e) {
            throw new ClusterDaemonException("Cannot get ObjectName", e);
        }
        return objName;

    }


    /**
     * Load the cluster daemon configuration (clusterd.xml)
     * @param confFileName configuration file to used
     * @throws ClusterDaemonException if an error occurs
     */
    public static void loadClusterDaemonConfiguration(String confFileName) throws ClusterDaemonException {
        ClassLoader currentLoader = Thread.currentThread().getContextClassLoader();

        currentConfiguration = null;
        try {
            currentConfiguration = ClusterDaemonConfigurationManager.getClusterDaemonConfiguration(confFileName, currentLoader);
            currentConfigurationFileName = ClusterDaemonConfigurationManager.getClusterDaemonFileName(confFileName);
        } catch (ClusterDaemonConfigurationException e) {
            throw new ClusterDaemonException(e);
        }

    }


    /**
     * @return current configuration
     */
    public static ClusterDaemonConfiguration getCurrentConfiguration() {
        return currentConfiguration;
    }

    /**
     * @return current configuration
     */
    public static String getCurrentConfigurationFileName() {
        return currentConfigurationFileName;
    }

}
