/** Generates an instance based on the specified file. */
  public static RemoteControlPipeTable readHostFile(String filename) throws IOException {
    RemoteControlPipeTable table = new RemoteControlPipeTable();

    BufferedReader in = null;
    try {
      in = new BufferedReader(new InputStreamReader(new FileInputStream(filename), Main.ENCODING));
    } catch (UnsupportedEncodingException e) {
      // NOTREACHED
    }

    String line;
    while (true) {
      line = in.readLine();
      if (line == null) break; // EOF
      if (line.length() <= 0) continue; // skip brank lines

      if (line.startsWith("#") || line.startsWith(";") || line.startsWith("//"))
        continue; // comments

      String[] splitted = line.split("\\s+");
      HostAndPort hostPort = MessagingUtility.parseHostnameAndPort(splitted[0], Main.DIST_EMU_PORT);
      int startHostID = Integer.parseInt(splitted[1]);

      WorkerEntry entry = new WorkerEntry(hostPort, startHostID);
      table.entrySet.add(entry);
      table.entryMap.put(hostPort.getHostAddress(), entry);
    }

    return table;
  }
  /** Generates an instance based on the specified String. */
  public static RemoteControlPipeTable parseString(String str) throws UnknownHostException {
    RemoteControlPipeTable table = new RemoteControlPipeTable();

    String[] splitted = str.split("\\s*,\\s*");

    try {
      int index = 0;
      while (true) {
        HostAndPort hostPort =
            MessagingUtility.parseHostnameAndPort(splitted[index], Main.DIST_EMU_PORT);
        int startHostID = Integer.parseInt(splitted[index + 1]);

        WorkerEntry entry = new WorkerEntry(hostPort, startHostID);
        table.entrySet.add(entry);
        table.entryMap.put(hostPort.getHostAddress(), entry);

        index += 2;
      }
    } catch (ArrayIndexOutOfBoundsException e) {
      // ignore
    }

    return table;
  }
  public Mcast initialize(
      short applicationID, short applicationVersion, String command, CommandLine cmd)
      throws Exception {
    String transport = null;
    String algorithm = null;
    String routingStyle = null;
    ID selfID = null;
    String statCollectorAddressAndPort = null;
    String selfAddressAndPort = null;
    boolean noUPnP = false;

    boolean join = false;
    String contactHost = null;
    int contactPort = -1;
    String contactString = null;

    // parse command-line arguments
    String optVal;
    if (cmd.hasOption('h')) {
      usage(command);
      System.exit(1);
    }
    optVal = cmd.getOptionValue('i');
    if (optVal != null) {
      selfID = ID.getID(optVal, MAX_ID_SIZE);
    }
    optVal = cmd.getOptionValue('m');
    if (optVal != null) {
      statCollectorAddressAndPort = optVal;
    }
    optVal = cmd.getOptionValue('t');
    if (optVal != null) {
      transport = optVal;
    }
    optVal = cmd.getOptionValue('a');
    if (optVal != null) {
      algorithm = optVal;
    }
    optVal = cmd.getOptionValue('r');
    if (optVal != null) {
      routingStyle = optVal;
    }
    optVal = cmd.getOptionValue('s');
    if (optVal != null) {
      selfAddressAndPort = optVal;
    }
    if (cmd.hasOption('N')) {
      noUPnP = true;
    }

    String[] args = cmd.getArgs();

    // parse initial contact
    if (args.length >= 1) {
      contactHost = args[0];
      join = true;

      if (args.length >= 2) contactPort = Integer.parseInt(args[1]);
    }

    // initialize a Mcast
    McastConfiguration config = McastFactory.getDefaultConfiguration();
    if (transport != null) config.setMessagingTransport(transport);
    if (algorithm != null) config.setRoutingAlgorithm(algorithm);
    if (routingStyle != null) config.setRoutingStyle(routingStyle);
    if (selfAddressAndPort != null) {
      MessagingUtility.HostAndPort hostAndPort =
          MessagingUtility.parseHostnameAndPort(selfAddressAndPort, config.getSelfPort());

      config.setSelfAddress(hostAndPort.getHostName());
      config.setSelfPort(hostAndPort.getPort());
    }
    if (noUPnP) config.setDoUPnPNATTraversal(false);

    if (contactPort < 0) { // not initialized
      contactPort = config.getSelfPort();
    }

    Mcast mcast =
        McastFactory.getMcast(
            applicationID, applicationVersion, config, selfID); // throws Exception

    StringBuilder sb = new StringBuilder();
    sb.append("Mcast configuration:\n");
    sb.append("  hostname:port:     ")
        .append(mcast.getRoutingService().getSelfIDAddressPair().getAddress())
        .append('\n');
    sb.append("  transport type:    ").append(config.getMessagingTransport()).append('\n');
    sb.append("  routing algorithm: ").append(config.getRoutingAlgorithm()).append('\n');
    sb.append("  routing style:     ").append(config.getRoutingStyle()).append('\n');
    // System.out.print(sb);

    try {
      if (statCollectorAddressAndPort != null) {
        StatConfiguration statConfig = StatFactory.getDefaultConfiguration();
        // provides the default port number of stat collector

        MessagingUtility.HostAndPort hostAndPort =
            MessagingUtility.parseHostnameAndPort(
                statCollectorAddressAndPort, statConfig.getSelfPort());

        mcast.setStatCollectorAddress(hostAndPort.getHostName(), hostAndPort.getPort());
      }

      if (join) {
        if (contactPort >= 0) {
          mcast.joinOverlay(contactHost, contactPort);
          contactString = contactHost + " : " + contactPort;
        } else {
          try {
            mcast.joinOverlay(contactHost);
            contactString = contactHost;
          } catch (IllegalArgumentException e) { // port is not specified
            contactPort = config.getContactPort();
            mcast.joinOverlay(contactHost, contactPort);
            contactString = contactHost + ":" + contactPort;
          }
        }
      }
    } catch (UnknownHostException e) {
      System.err.println("A hostname could not be resolved: " + contactHost);
      e.printStackTrace();
      System.exit(1);
    }

    if (join) {
      // System.out.println("  initial contact:   " + contactString);
    }

    // System.out.println("A Mcast started.");
    // System.out.flush();

    return mcast;
  }