/**
   * Returns control when task is complete.
   *
   * @param json
   * @param logger
   */
  private String waitForDeploymentCompletion(JSON json, OctopusApi api, Log logger) {
    final long WAIT_TIME = 5000;
    final double WAIT_RANDOM_SCALER = 100.0;
    JSONObject jsonObj = (JSONObject) json;
    String id = jsonObj.getString("TaskId");
    Task task = null;
    String lastState = "Unknown";
    try {
      task = api.getTask(id);
    } catch (IOException ex) {
      logger.error("Error getting task: " + ex.getMessage());
      return null;
    }

    logger.info("Task info:");
    logger.info("\tId: " + task.getId());
    logger.info("\tName: " + task.getName());
    logger.info("\tDesc: " + task.getDescription());
    logger.info("\tState: " + task.getState());
    logger.info("\n\nStarting wait...");
    boolean completed = task.getIsCompleted();
    while (!completed) {
      try {
        task = api.getTask(id);
      } catch (IOException ex) {
        logger.error("Error getting task: " + ex.getMessage());
        return null;
      }

      completed = task.getIsCompleted();
      lastState = task.getState();
      logger.info("Task state: " + lastState);
      if (completed) {
        break;
      }
      try {
        Thread.sleep(WAIT_TIME + (long) (Math.random() * WAIT_RANDOM_SCALER));
      } catch (InterruptedException ex) {
        logger.info("Wait interrupted!");
        logger.info(ex.getMessage());
        completed = true; // bail out of wait loop
      }
    }
    logger.info("Wait complete!");
    return lastState;
  }
  @Override
  public void onCompleted(AbstractBuild run, TaskListener listener) {
    Lamps plugin = Lamps.getInstance();
    Set<String> jobs = plugin.getJobs();
    String jobName = run.getParent().getFullName();
    XfEventMessage xfEventMessage = new XfEventMessage();

    if (jobs.contains(jobName)) {
      Result result = run.getResult();
      Set<Lamp> activeLamps = plugin.getLampsContainingJob(jobName);
      for (Lamp lamp : activeLamps) {
        Result lampResult = result;

        xfEventMessage.sendColorMessage(lamp, lampResult, States.Action.SOLID);

        // Create Notification for LCD
        StringBuilder infoMsg = new StringBuilder(64);
        infoMsg.append(jobName).append(' ').append(run.getDisplayName()).append('\n');
        if (Result.FAILURE.equals(result)) {
          ArrayList<String> blame = Lists.newArrayList();
          if (lamp.isBlame()) {
            Set<User> culprits = run.getCulprits();
            for (User user : culprits) {
              blame.add(user.getDisplayName());
            }
          }
          if (blame.isEmpty()) {
            blame.add("Somebody");
          }
          infoMsg.insert(0, Joiner.on(", ").join(blame) + " broke the build: ");
          infoMsg.append(result.toString());
          listener.getLogger().println("[XFD] Updating Lamp display: " + infoMsg.toString());
        } else if (Result.ABORTED.equals(result)) {
          String causeMsg = "BUILD ABORTED";
          infoMsg.append(causeMsg);
          listener.getLogger().println("[XFD] Updating Lamp display: " + infoMsg.toString());
        } else {
          infoMsg.append(result.toString());
        }
        xfEventMessage.sendLCDMessage(lamp, infoMsg.toString());

        if (lamp.isSfx()) {
          try {
            Thread.sleep(1000);
            xfEventMessage.sendSfxMessage(lamp, lampResult);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }

        if (States.resultColorMap.get(lampResult).equals(States.Color.RED) && lamp.isNoisy()) {
          try {
            Thread.sleep(1000);
            xfEventMessage.sendBuzzerMessage(lamp);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
        if (lamp.isAggregate()) {
          try {
            Thread.sleep(1000);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          plugin.updateAggregateStatus(lamp);
        }
      }
    }
  }