// Path: coopr-server/src/main/java/co/cask/coopr/spec/ProvisionerAction.java
// public enum ProvisionerAction {
//   CREATE,
//   CONFIRM,
//   BOOTSTRAP,
//   INSTALL,
//   REMOVE,
//   INITIALIZE,
//   CONFIGURE,
//   START,
//   STOP,
//   DELETE;
// 
//   public boolean isHardwareAction() {
//     return this == CREATE || this == CONFIRM || this == BOOTSTRAP || this == DELETE;
//   }
// 
//   public boolean isRuntimeAction() {
//     return this == INITIALIZE || this == START || this == STOP;
//   }
// 
//   public boolean isInstallTimeAction() {
//     return this == INSTALL || this == REMOVE;
//   }
// }


import co.cask.coopr.cluster.Node;
import co.cask.coopr.scheduler.dag.TaskDag;
import co.cask.coopr.scheduler.dag.TaskNode;
import co.cask.coopr.scheduler.task.ClusterJob;
import co.cask.coopr.scheduler.task.ClusterTask;
import co.cask.coopr.spec.ProvisionerAction;
import co.cask.coopr.spec.service.Service;
import com.google.common.base.Function;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Map;
import java.util.Set;
    }
  }

  private Set<String> expandStopServices(Set<String> services) {
    Set<String> expandedServices = Sets.newHashSet(services);
    // if svc A depends on svc B and we're asked to restart svc B, we actually need to restart both svc A and svc B.
    // similarly, if svc A depends on svc B and we're asked to stop svc B, we actually need to stop both svc A and B.
    Set<String> additionalServicesToStop = Sets.newHashSet();
    do {
      additionalServicesToStop.clear();
      for (String otherService : Sets.difference(serviceMap.keySet(), expandedServices)) {
        for (String expandedService : expandedServices) {
          // if the other service depends on the expanded service, we need to add it to the list of services to stop.
          // ex: otherService=A and expandedService=B, A depends on B, and B is being stopped/restarted
          if (dependencyResolver.runtimeDependsOn(otherService, expandedService)) {
            additionalServicesToStop.add(otherService);
          }
        }
      }
      expandedServices.addAll(additionalServicesToStop);
    } while (!additionalServicesToStop.isEmpty());
    return expandedServices;
  }

  private Set<String> expandStartServices(Set<String> services) {
    Set<String> expandedServices = Sets.newHashSet(services);
    // if svc A depends on svc B and we're asked to start svc A, we need to start svc B first.
    Set<String> additionalServicesToStart = Sets.newHashSet();
    do {
      additionalServicesToStart.clear();
// Path: coopr-server/src/main/java/co/cask/coopr/spec/ProvisionerAction.java
// public enum ProvisionerAction {
//   CREATE,
//   CONFIRM,
//   BOOTSTRAP,
//   INSTALL,
//   REMOVE,
//   INITIALIZE,
//   CONFIGURE,
//   START,
//   STOP,
//   DELETE;
// 
//   public boolean isHardwareAction() {
//     return this == CREATE || this == CONFIRM || this == BOOTSTRAP || this == DELETE;
//   }
// 
//   public boolean isRuntimeAction() {
//     return this == INITIALIZE || this == START || this == STOP;
//   }
// 
//   public boolean isInstallTimeAction() {
//     return this == INSTALL || this == REMOVE;
//   }
// }


// Path: coopr-server/src/main/java/co/cask/coopr/scheduler/JobPlanner.java
import co.cask.coopr.cluster.Node;
import co.cask.coopr.scheduler.dag.TaskDag;
import co.cask.coopr.scheduler.dag.TaskNode;
import co.cask.coopr.scheduler.task.ClusterJob;
import co.cask.coopr.scheduler.task.ClusterTask;
import co.cask.coopr.spec.ProvisionerAction;
import co.cask.coopr.spec.service.Service;
import com.google.common.base.Function;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Map;
import java.util.Set;

    }
  }

  private Set<String> expandStopServices(Set<String> services) {
    Set<String> expandedServices = Sets.newHashSet(services);
    // if svc A depends on svc B and we're asked to restart svc B, we actually need to restart both svc A and svc B.
    // similarly, if svc A depends on svc B and we're asked to stop svc B, we actually need to stop both svc A and B.
    Set<String> additionalServicesToStop = Sets.newHashSet();
    do {
      additionalServicesToStop.clear();
      for (String otherService : Sets.difference(serviceMap.keySet(), expandedServices)) {
        for (String expandedService : expandedServices) {
          // if the other service depends on the expanded service, we need to add it to the list of services to stop.
          // ex: otherService=A and expandedService=B, A depends on B, and B is being stopped/restarted
          if (dependencyResolver.runtimeDependsOn(otherService, expandedService)) {
            additionalServicesToStop.add(otherService);
          }
        }
      }
      expandedServices.addAll(additionalServicesToStop);
    } while (!additionalServicesToStop.isEmpty());
    return expandedServices;
  }

  private Set<String> expandStartServices(Set<String> services) {
    Set<String> expandedServices = Sets.newHashSet(services);
    // if svc A depends on svc B and we're asked to start svc A, we need to start svc B first.
    Set<String> additionalServicesToStart = Sets.newHashSet();
    do {
      additionalServicesToStart.clear();
      for (String otherService : Sets.difference(serviceMap.keySet(), expandedServices)) {