// 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;
  public Map<String, Node> getNodeMap() {
    return nodeMap;
  }

  /**
   * Create a plan of tasks to be executed in order to perform the cluster operation. Each item in the list represents
   * a stage of tasks that can be performed. All tasks in a stage may be run in parallel, but every task in a stage
   * must be successfully completed before moving on to the next stage.
   *
   * @return Plan of tasks to be executed in order to perform a cluster operation.
   */
  public List<Set<TaskNode>> linearizeDependentTasks() {
    TaskDag taskDag = createTaskDag();

    long start = System.currentTimeMillis();
    List<Set<TaskNode>> linearizedTasks = taskDag.linearize();
    long dur = System.currentTimeMillis() - start;
    LOG.debug("took {} ms to linearize action plan.", dur);

    return linearizedTasks;
  }

  /**
   * Creates a DAG (directed acyclic graph) of tasks to execute in order to perform the cluster job.
   *
   * @return Task dag for the cluster operation.
   */
  TaskDag createTaskDag() {
    long start = System.currentTimeMillis();
    TaskDag taskDag = new TaskDag();
// 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;

  public Map<String, Node> getNodeMap() {
    return nodeMap;
  }

  /**
   * Create a plan of tasks to be executed in order to perform the cluster operation. Each item in the list represents
   * a stage of tasks that can be performed. All tasks in a stage may be run in parallel, but every task in a stage
   * must be successfully completed before moving on to the next stage.
   *
   * @return Plan of tasks to be executed in order to perform a cluster operation.
   */
  public List<Set<TaskNode>> linearizeDependentTasks() {
    TaskDag taskDag = createTaskDag();

    long start = System.currentTimeMillis();
    List<Set<TaskNode>> linearizedTasks = taskDag.linearize();
    long dur = System.currentTimeMillis() - start;
    LOG.debug("took {} ms to linearize action plan.", dur);

    return linearizedTasks;
  }

  /**
   * Creates a DAG (directed acyclic graph) of tasks to execute in order to perform the cluster job.
   *
   * @return Task dag for the cluster operation.
   */
  TaskDag createTaskDag() {
    long start = System.currentTimeMillis();
    TaskDag taskDag = new TaskDag();
    List<ProvisionerAction> actionOrder = actions.getActionOrder().get(clusterAction);