/**
  * Clean the checked flag of a taskset
  *
  * @return $none
  */
 public void cleanTaskSetChecked() {
   Collection sets = mTask2TaskSet.values();
   for (Iterator it = sets.iterator(); it.hasNext(); ) {
     TaskSet set = (TaskSet) it.next();
     set.hasChecked = false;
   }
 }
  /** Update task set dependencies */
  private void updateTaskSetDependencies() {

    Collection sets = mTask2TaskSet.values();
    for (Iterator it = sets.iterator(); it.hasNext(); ) {
      TaskSet set = (TaskSet) it.next();
      if (!set.hasChecked) {
        set.hasChecked = true;
        set.getChildList().clear();
        set.getParentList().clear();
        for (Task task : set.getTaskList()) {
          for (Iterator tIt = task.getParentList().iterator(); tIt.hasNext(); ) {
            Task parent = (Task) tIt.next();
            TaskSet parentSet = (TaskSet) mTask2TaskSet.get(parent);
            if (!set.getParentList().contains(parentSet) && set != parentSet) {
              set.getParentList().add(parentSet);
            }
          }
          for (Iterator tIt = task.getChildList().iterator(); tIt.hasNext(); ) {
            Task child = (Task) tIt.next();
            TaskSet childSet = (TaskSet) mTask2TaskSet.get(child);
            if (!set.getChildList().contains(childSet) && set != childSet) {
              set.getChildList().add(childSet);
            }
          }
        }
      }
    }
    // within each method
    cleanTaskSetChecked();
  }
  /** Print out the clustering information. */
  private void printOut() {
    Collection sets = mTask2TaskSet.values();
    for (Iterator it = sets.iterator(); it.hasNext(); ) {
      TaskSet set = (TaskSet) it.next();
      if (!set.hasChecked) {
        set.hasChecked = true;

        Log.printLine("Job");
        for (Task task : set.getTaskList()) {
          Log.printLine(
              "Task "
                  + task.getCloudletId()
                  + " "
                  + task.getImpact()
                  + " "
                  + task.getCloudletLength());
        }
      }
    }
    // within each method
    cleanTaskSetChecked();
  }
  /**
   * Gets the current tasks per level
   *
   * @return tasks list per level
   */
  public Map<Integer, ArrayList<TaskSet>> getCurrentTaskSetAtLevels() {
    // makesure it is updated

    // makesure Taskset.hasChecked is false
    Map map = new HashMap<Integer, ArrayList<TaskSet>>();
    Collection sets = mTask2TaskSet.values();
    for (Iterator it = sets.iterator(); it.hasNext(); ) {
      TaskSet set = (TaskSet) it.next();
      if (!set.hasChecked) {
        set.hasChecked = true;
        int depth = getDepth(set);
        if (!map.containsKey(depth)) {
          map.put(depth, new ArrayList<TaskSet>());
        }
        ArrayList list = (ArrayList) map.get(depth);
        list.add(set);
      }
    }
    mTaskSet2Depth.clear();
    // must do
    cleanTaskSetChecked();
    return map;
  }
  @Override
  public void run() {

    if (clusterNum > 0) {
      for (Iterator it = getTaskList().iterator(); it.hasNext(); ) {
        Task task = (Task) it.next();
        TaskSet set = new TaskSet();
        set.addTask(task);
        mTask2TaskSet.put(task, set);
      }
    }

    remove();
    updateTaskSetDependencies();

    printMetrics();
    String code = Parameters.getClusteringParameters().getCode();
    Map<Integer, ArrayList<TaskSet>> map = getCurrentTaskSetAtLevels();
    if (code != null) {
      for (char c : code.toCharArray()) {

        switch (c) {
          case 'v':

            // verticalClustering();
            VerticalBalancing v = new VerticalBalancing(map, this.mTask2TaskSet, this.clusterNum);
            v.run();
            break;
          case 'c':
            // childAwareHorizontalClustering();
            ChildAwareHorizontalClustering ch =
                new ChildAwareHorizontalClustering(map, this.mTask2TaskSet, this.clusterNum);
            ch.run();
            updateTaskSetDependencies();
            break;
          case 'r':
            // horizontalRuntimeBalancing();
            HorizontalRuntimeBalancing r =
                new HorizontalRuntimeBalancing(map, this.mTask2TaskSet, this.clusterNum);
            r.run();
            updateTaskSetDependencies();
            break;
          case 'i':
            HorizontalImpactBalancing i =
                new HorizontalImpactBalancing(map, this.mTask2TaskSet, this.clusterNum);
            i.run();
            break;
          case 'd':
            HorizontalDistanceBalancing d =
                new HorizontalDistanceBalancing(map, this.mTask2TaskSet, this.clusterNum);
            d.run();
            break;
          case 'h':
            HorizontalRandomClustering h =
                new HorizontalRandomClustering(map, this.mTask2TaskSet, this.clusterNum);
            h.run();
            break;
          default:
            break;
        }
      }
      printMetrics();
    }

    printOut();

    Collection sets = mTask2TaskSet.values();
    for (Iterator it = sets.iterator(); it.hasNext(); ) {
      TaskSet set = (TaskSet) it.next();
      if (!set.hasChecked) {
        set.hasChecked = true;
        addTasks2Job(set.getTaskList());
      }
    }
    // a good habit
    cleanTaskSetChecked();

    updateDependencies();
    addClustDelay();

    recover();
  }