/*
 * This file is part of the DistSim distributed simulation framework (wrapper)
 * Copyright (C) 2008 Mathias Kurth
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

package brn.distsim;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.Enumeration;
import java.util.Properties;

import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.jmx.HierarchyDynamicMBean;
import org.apache.log4j.spi.LoggerRepository;

import com.sun.jdmk.comm.HtmlAdaptorServer;

/**
 * http://mc4j.org/confluence/display/MC4J/Home
 *
 * jconsole service:jmx:rmi:///jndi/rmi://localhost:51180/jmxrmi
 *
 * Note: we could not use com.sun.management.jmxremote.port because it
 * creates a read-only registry
 *
 * -Dbrn.distsim.jmxremote.port=51180
 * -Dbrn.distsim.jmxremote.ssl=false
 * -Dbrn.distsim.jmxremote.authenticate=false
 * -Dbrn.distsim.jmxremote.password.file=jmxremote.password
 * -brn.distsim.jmxremote.access.file=jmxremote.access
 * @author kurth
 */
public class Main {

  public static final String RMI_NAME = "jmxrmi";

  public static final int getRmiRegistryPort() {
    int port = 51180;
    String portString = System.getProperties().getProperty("brn.distsim.jmxremote.port");
    try {
      port = Integer.parseInt(portString);
    } catch (NumberFormatException e) {}
    return port;
  }

  public static final String getJmxUrlLocalPrefix() {
    return getJmxUrlPrefix("localhost", getRmiRegistryPort());
  }

  public static final String getJmxUrlLocalPrefix2() {
    return getJmxUrlPrefix2("localhost", getRmiRegistryPort());
  }

  public static final String getJmxUrlPrefix(String host, int port) {
    return "service:jmx:rmi:///jndi/rmi://"+host+":" + port;
  }

  public static final String getJmxUrlPrefix2(String host, int port) {
    return "service:jmx:rmi://" + host + ":" + (port+1) + "/jndi/rmi://"+host+":" + port;
  }

  public static void main(String[] args) {
    boolean restart = false;
//    if(System.getSecurityManager() == null) {
//      System.setSecurityManager(new RMISecurityManager());
//   }
    if (null == System.getProperty("java.rmi.server.hostname")
        || 0 == System.getProperty("java.rmi.server.hostname").trim().length()) {
      try {
        String s = InetAddress.getLocalHost().getHostName();
        System.setProperty("java.rmi.server.hostname", s);
      } catch (UnknownHostException e3) {
        // TODO Auto-generated catch block
        e3.printStackTrace();
      }
    }

    try {
      File f = new File("log4j.properties");
      FileInputStream fin = new FileInputStream(f);
      Properties properties = new Properties();
      properties.load(fin);
      fin.close();

      //    Logger.getRootLogger().setLevel(Level.OFF);
      PropertyConfigurator.configure(properties);
    } catch(IOException e) {
      BasicConfigurator.configure();
//    Logger.getRootLogger().setLevel(Level.OFF);
    }

    Registry registry;
    try {
      registry = LocateRegistry.createRegistry(getRmiRegistryPort());
    } catch (RemoteException e) {
      try {
        registry = LocateRegistry.getRegistry(getRmiRegistryPort());
      } catch (RemoteException e1) {
        System.err.println("couldn't create registry");
        return;
      }
    }
    try {
      registry.unbind(RMI_NAME);
    } catch (Exception e2) {}

    MBeanServer server = ManagementFactory.getPlatformMBeanServer();
    try {
      // Create JMX RMI Connector
      String url = brn.distsim.Main.getJmxUrlLocalPrefix2() + "/" + RMI_NAME;
      JMXConnectorServer connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(
          new JMXServiceURL( url ), null, server );
      connectorServer.start();

      // Create HTML Adaptor
      int httpPort = 0;
      HtmlAdaptorServer adaptor = null;
      try {
        httpPort = Integer.parseInt(System.getProperty("brn.distsim.jmxremote.http.port"));
      } catch (NumberFormatException e) {}
      if (httpPort > 0) {
        adaptor = new HtmlAdaptorServer(httpPort);
        ObjectName adaptorName = new ObjectName("adaptor:proptocol=HTTP");
        server.registerMBean(adaptor, adaptorName);
        adaptor.start();
      }

       // Create and Register the top level Log4J MBean
      HierarchyDynamicMBean hdm = new HierarchyDynamicMBean();
      ObjectName mbo = new ObjectName("log4j:hiearchy=default");
      server.registerMBean(hdm, mbo);

      // Add the root logger to the Hierarchy MBean
      Logger rootLogger = Logger.getRootLogger();
      hdm.addLoggerMBean(rootLogger.getName());

      // Get each logger from the Log4J Repository and add it to
      // the Hierarchy MBean created above.
      LoggerRepository r = LogManager.getLoggerRepository();
      Enumeration currentLoggers = r.getCurrentLoggers();
      while (currentLoggers.hasMoreElements()){
        Logger logger = (Logger) currentLoggers.nextElement();
        hdm.addLoggerMBean(logger.getName());
      }

      // Create Distsim MBean
      ObjectName nameWrapper = new ObjectName(WrapperManager.JMX_NAME);
      WrapperManager manager = new WrapperManager();
      server.registerMBean(manager, nameWrapper);

      // Create Distsim MBean
      ObjectName name = new ObjectName(DistsimManager.JMX_NAME);
      DistsimManager distsim = new DistsimManager(manager);
      server.registerMBean(distsim, name);

      restart = distsim.run();

      server.unregisterMBean(nameWrapper);
      server.unregisterMBean(name);
      connectorServer.stop();
      if (adaptor != null)
        adaptor.stop();
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }

    if (restart)
      System.exit( 2 );
    System.exit( 0 );
  }

}
