package jycessing.mode.run;

import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

import jycessing.mode.PythonMode;

public class RMIUtils {
  static final int RMI_PORT = 8220;

  static {
    System.setProperty("java.rmi.server.hostname", "127.0.0.1");
    // Timeout RMI calls after 1.5 seconds. Good for detecting a hanging sketch runner.
    System.setProperty("sun.rmi.transport.tcp.responseTimeout", "1500");
    System.setProperty("sun.rmi.transport.tcp.localHostNameTimeOut", "1000");
  }

  private static void log(final String msg) {
    if (PythonMode.VERBOSE) {
      System.err.println(RMIUtils.class.getSimpleName() + ": " + msg);
    }
  }

  public static class RMIProblem extends Exception {
    RMIProblem(final Exception e) {
      super(e);
    }
  }

  private RMIUtils() {}

  public static Registry registry() throws RemoteException {
    try {
      return LocateRegistry.createRegistry(RMI_PORT);
    } catch (final RemoteException e) {
    }
    return LocateRegistry.getRegistry(RMI_PORT);
  }

  public static void bind(final Remote remote, final Class<? extends Remote> remoteInterface)
      throws RMIProblem {
    final String registryKey = remoteInterface.getSimpleName();
    log("Binding instance of " + remote.getClass().getName() + " to registry as " + registryKey);
    try {
      final Remote stub = export(remote);
      registry().bind(registryKey, stub);
      Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
        @Override
        public void run() {
          try {
            log("Unbinding " + registryKey + " from registry.");
            registry().unbind(registryKey);
          } catch (final Exception e) {
          }
        }
      }));
    } catch (final Exception e) {
      throw new RMIProblem(e);
    }
  }

  public static Remote export(final Remote remote) throws RMIProblem {
    try {
      return UnicastRemoteObject.exportObject(remote, 0);
    } catch (final RemoteException e) {
      throw new RMIProblem(e);
    }
  }

  @SuppressWarnings("unchecked")
  public static <T extends Remote> T lookup(final Class<T> klass) throws RMIProblem {
    try {
      log("Looking up ModeService in registry.");
      return (T)registry().lookup(klass.getSimpleName());
    } catch (final Exception e) {
      throw new RMIProblem(e);
    }
  }
}

@@ -265,53 +265,191 @@
 %7B%0A  
-static final int RMI_PORT = 8220;%0A%0A  static %7B
+private static final boolean EXTREMELY_VERSBOSE = false;%0A%0A  static final int RMI_PORT = 8220;%0A%0A  static %7B%0A    System.setProperty(%22sun.rmi.transport.tcp.localHostNameTimeOut%22, %221000%22);
 %0A   
@@ -506,24 +506,25 @@
 27.0.0.1%22);%0A
+%0A
     // Timeo
@@ -676,85 +676,302 @@
 %22);%0A
-    System.setProperty(%22sun.rmi.transport.tcp.localHostNameTimeOut%22, %221000%22);
+%0A    if (EXTREMELY_VERSBOSE) %7B%0A      System.setProperty(%22java.rmi.server.logCalls%22, %22true%22);%0A      System.setProperty(%22sun.rmi.server.logLevel%22, %22VERBOSE%22);%0A      System.setProperty(%22sun.rmi.client.logCalls%22, %22true%22);%0A      System.setProperty(%22sun.rmi.transport.tcp.logLevel%22, %22VERBOSE%22);%0A    %7D
 %0A  %7D

Add more verbose RMI debugging options.