/**
  * Creates a shell script for starting an existing remote container.
  *
  * @param options
  * @return
  * @throws MalformedURLException
  */
 public static String buildStartScript(CreateRemoteContainerOptions options)
     throws MalformedURLException {
   StringBuilder sb = new StringBuilder();
   sb.append("#!/bin/bash").append("\n");
   sb.append(RUN_FUNCTION).append("\n");
   sb.append(KARAF_CHECK).append("\n");
   sb.append(CONFIGURE_HOSTNAMES).append("\n");
   sb.append("run cd ").append(options.getPath()).append("\n");
   sb.append("run cd ").append(options.getName()).append("\n");
   sb.append("run cd `").append(FIRST_FABRIC_DIRECTORY).append("`\n");
   if (options instanceof CreateJCloudsContainerOptions) {
     sb.append("configure_hostnames")
         .append(" ")
         .append(((CreateJCloudsContainerOptions) options).getProviderName())
         .append("\n");
   }
   if (options.getJvmOpts() != null
       && !options.getJvmOpts().contains("-XX:+UnlockDiagnosticVMOptions -XX:+UnsyncloadClass")) {
     options.setJvmOpts(
         options.getJvmOpts() + " -XX:+UnlockDiagnosticVMOptions -XX:+UnsyncloadClass");
   }
   if (options.getJvmOpts() != null && !options.getJvmOpts().isEmpty()) {
     sb.append("export JAVA_OPTS=\"" + options.getJvmOpts()).append("\"\n");
   }
   sb.append("nohup bin/start &").append("\n");
   sb.append("karaf_check `pwd`").append("\n");
   return sb.toString();
 }
  /**
   * Creates a shell script for installing and starting up a container.
   *
   * @param options
   * @return
   * @throws MalformedURLException
   */
  public static String buildInstallAndStartScript(CreateRemoteContainerOptions options)
      throws MalformedURLException, URISyntaxException {
    StringBuilder sb = new StringBuilder();
    sb.append("#!/bin/bash").append("\n");
    sb.append(RUN_FUNCTION).append("\n");
    sb.append(DOWNLOAD_FUNCTION).append("\n");
    sb.append(MAVEN_DOWNLOAD_FUNCTION).append("\n");
    sb.append(UPDATE_PKGS).append("\n");
    sb.append(INSTALL_CURL).append("\n");
    sb.append(INSTALL_UNZIP).append("\n");
    sb.append(INSTALL_TELNET).append("\n");
    sb.append(INSTALL_JDK).append("\n");
    sb.append(VALIDATE_REQUIREMENTS).append("\n");
    sb.append(EXIT_IF_NOT_EXISTS).append("\n");
    sb.append(COPY_NODE_METADATA).append("\n");
    sb.append(KARAF_CHECK).append("\n");
    sb.append(REPLACE_IN_FILE).append("\n");
    sb.append(CONFIGURE_HOSTNAMES).append("\n");
    sb.append(FIND_FREE_PORT).append("\n");
    sb.append(WAIT_FOR_PORT).append("\n");
    sb.append("run mkdir -p ").append(options.getPath()).append("\n");
    sb.append("run cd ").append(options.getPath()).append("\n");
    sb.append("run mkdir -p ").append(options.getName()).append("\n");
    sb.append("run cd ").append(options.getName()).append("\n");
    // We need admin access to be able to install curl & java.
    if (options.isAdminAccess()) {
      // This is not really needed.
      // Its just here as a silly workaround for some cases which fail to get the first thing
      // installed.
      sb.append("update_pkgs").append("\n");
      sb.append("install_openjdk").append("\n");
      sb.append("install_curl").append("\n");
      sb.append("install_unzip").append("\n");
      sb.append("install_telnet").append("\n");
    }
    sb.append("validate_requirements").append("\n");
    extractZipIntoDirectory(
        sb,
        options.getProxyUri(),
        "org.fusesource.fabric",
        "fuse-fabric",
        FabricConstants.FABRIC_VERSION);
    sb.append("run cd `").append(FIRST_FABRIC_DIRECTORY).append("`\n");
    List<String> lines = new ArrayList<String>();
    String globalResolver =
        options.getResolver() != null ? options.getResolver() : ZkDefs.DEFAULT_RESOLVER;
    lines.add(ZkDefs.GLOBAL_RESOLVER_PROPERTY + "=" + globalResolver);
    appendFile(sb, "etc/system.properties", lines);
    replaceLineInFile(
        sb, "etc/system.properties", "karaf.name=root", "karaf.name=" + options.getName());
    // Apply port range
    sb.append("SSH_PORT=")
        .append("`find_free_port ")
        .append(
            Ports.mapPortToRange(
                DEFAULT_SSH_PORT, options.getMinimumPort(), options.getMaximumPort()))
        .append(" ")
        .append(options.getMaximumPort())
        .append("`\n");
    sb.append("RMI_REGISTRY_PORT=")
        .append("`find_free_port ")
        .append(
            Ports.mapPortToRange(
                DEFAULT_RMI_REGISTRY_PORT, options.getMinimumPort(), options.getMaximumPort()))
        .append(" ")
        .append(options.getMaximumPort())
        .append("`\n");
    sb.append("RMI_SERVER_PORT=")
        .append("`find_free_port ")
        .append(
            Ports.mapPortToRange(
                DEFAULT_RMI_SERVER_PORT, options.getMinimumPort(), options.getMaximumPort()))
        .append(" ")
        .append(options.getMaximumPort())
        .append("`\n");
    sb.append("HTTP_PORT=")
        .append("`find_free_port ")
        .append(
            Ports.mapPortToRange(
                DEFAULT_HTTP_PORT, options.getMinimumPort(), options.getMaximumPort()))
        .append(" ")
        .append(options.getMaximumPort())
        .append("`\n");

    replaceLineInFile(
        sb, "etc/org.apache.karaf.shell.cfg", "sshPort=" + DEFAULT_SSH_PORT, "sshPort=$SSH_PORT");
    replaceLineInFile(
        sb,
        "etc/org.apache.karaf.management.cfg",
        "rmiRegistryPort = " + DEFAULT_RMI_REGISTRY_PORT,
        "rmiRegistryPort=$RMI_REGISTRY_PORT");
    replaceLineInFile(
        sb,
        "etc/org.apache.karaf.management.cfg",
        "rmiServerPort = " + DEFAULT_RMI_SERVER_PORT,
        "rmiServerPort=$RMI_SERVER_PORT");
    replaceLineInFile(
        sb, "etc/org.ops4j.pax.web.cfg", String.valueOf(DEFAULT_HTTP_PORT), "$HTTP_PORT");
    replaceLineInFile(sb, "etc/jetty.xml", String.valueOf(DEFAULT_HTTP_PORT), "$HTTP_PORT");
    appendFile(
        sb,
        "etc/system.properties",
        Arrays.asList(ZkDefs.MINIMUM_PORT + "=" + options.getMinimumPort()));
    appendFile(
        sb,
        "etc/system.properties",
        Arrays.asList(ZkDefs.MAXIMUM_PORT + "=" + options.getMaximumPort()));

    appendFile(sb, "etc/system.properties", Arrays.asList("\n"));

    // Read all system properties
    for (Map.Entry<String, Properties> entry : options.getSystemProperties().entrySet()) {
      Properties sysprops = entry.getValue();
      for (Map.Entry syspropEntry : sysprops.entrySet()) {
        Object type = syspropEntry.getKey();
        Object value = syspropEntry.getValue();
        appendFile(sb, "etc/system.properties", Arrays.asList(type + "=" + value));
      }
    }

    // TODO: Be simple & move all of the code below under system properties MAP.
    if (options.getPreferredAddress() != null) {
      appendFile(
          sb,
          "etc/system.properties",
          Arrays.asList(
              HostUtils.PREFERED_ADDRESS_PROPERTY_NAME + "=" + options.getPreferredAddress()));
    }

    if (options.isEnsembleServer()) {
      appendFile(
          sb,
          "etc/system.properties",
          Arrays.asList("zookeeper.password = "******"etc/system.properties",
          Arrays.asList(SystemProperties.ENSEMBLE_AUTOSTART + "=true"));
      appendFile(
          sb, "etc/system.properties", Arrays.asList(SystemProperties.AGENT_AUTOSTART + "=true"));
      appendFile(
          sb,
          "etc/system.properties",
          Arrays.asList(
              SystemProperties.PROFILES_AUTOIMPORT_PATH + "=${karaf.home}/fabric/import/"));
      if (options.getCreateEnsembleOptions() != null
          && options.getCreateEnsembleOptions().getUsers() != null) {
        for (Map.Entry<String, String> entry :
            options.getCreateEnsembleOptions().getUsers().entrySet()) {
          appendFile(
              sb, "etc/users.properties", Arrays.asList(entry.getKey() + "=" + entry.getValue()));
        }
      }
    } else if (options.getZookeeperUrl() != null) {
      appendFile(
          sb,
          "etc/system.properties",
          Arrays.asList("zookeeper.url = " + options.getZookeeperUrl()));
      appendFile(
          sb,
          "etc/system.properties",
          Arrays.asList("zookeeper.password = "******"etc/system.properties", Arrays.asList(SystemProperties.AGENT_AUTOSTART + "=true"));
      appendToLineInFile(sb, "etc/org.apache.karaf.features.cfg", "featuresBoot=", "fabric-agent,");
    }

    // Add the proxyURI to the list of repositories
    if (options.getProxyUri() != null) {
      appendToLineInFile(
          sb,
          "etc/org.ops4j.pax.url.mvn.cfg",
          "repositories=",
          options.getProxyUri().toString() + ",");
    }
    // Just for ensemble servers we want to copy their creation metadata for import.
    if (options.isEnsembleServer()) {
      CreateContainerMetadata metadata = options.getMetadataMap().get(options.getName());
      if (metadata != null) {
        byte[] metadataPayload = ObjectUtils.toBytes(metadata);
        if (metadataPayload != null && metadataPayload.length > 0) {
          sb.append("copy_node_metadata ")
              .append(options.getName())
              .append(" ")
              .append(new String(Base64Encoder.encode(metadataPayload)))
              .append("\n");
        }
      }
    }
    if (options instanceof CreateJCloudsContainerOptions) {

      sb.append("configure_hostnames")
          .append(" ")
          .append(((CreateJCloudsContainerOptions) options).getProviderName())
          .append("\n");
    }
    if (options.getJvmOpts() != null
        && !options.getJvmOpts().contains("-XX:+UnlockDiagnosticVMOptions -XX:+UnsyncloadClass")) {
      options.setJvmOpts(
          options.getJvmOpts() + " -XX:+UnlockDiagnosticVMOptions -XX:+UnsyncloadClass");
    }
    if (options.getJvmOpts() != null && !options.getJvmOpts().isEmpty()) {
      sb.append("export JAVA_OPTS=\"" + options.getJvmOpts()).append("\"\n");
    }
    sb.append("nohup bin/start &").append("\n");
    sb.append("karaf_check `pwd`").append("\n");
    sb.append("wait_for_port $SSH_PORT").append("\n");
    sb.append("wait_for_port $RMI_REGISTRY_PORT").append("\n");
    return sb.toString();
  }