/**
   * Retrieves the value associated with the provided iteration of the given optimizing job.
   *
   * @param iteration The job iteration for which to retrieve the value.
   * @return The value associated with the provided iteration of the given optimizing job.
   * @throws SLAMDException If a problem occurs while trying to determine the value for the given
   *     optimizing job iteration.
   */
  @Override()
  public double getIterationOptimizationValue(Job iteration) throws SLAMDException {
    StatTracker[] trackers = iteration.getStatTrackers(optimizeStat);
    if ((trackers == null) || (trackers.length == 0)) {
      throw new SLAMDException(
          "The provided optimizing job iteration did "
              + "not include any values for the statistic to "
              + "optimize, \""
              + optimizeStat
              + "\".");
    }

    StatTracker tracker = trackers[0].newInstance();
    tracker.aggregate(trackers);

    double summaryValue = tracker.getSummaryValue();
    iteration.slamdServer.logMessage(
        Constants.LOG_LEVEL_JOB_DEBUG,
        "SingleStatisticWithReplicationLatency"
            + "OptimizationAlgorithm."
            + "getIterationOptimizationValue("
            + iteration.getJobID()
            + ") returning "
            + summaryValue);

    return summaryValue;
  }
  /**
   * Initializes this optimization algorithm with the provided set of parameters for the given
   * optimizing job.
   *
   * @param optimizingJob The optimizing job with which this optimization algorithm will be used.
   * @param parameters The parameter list containing the parameter values provided by the end user
   *     when scheduling the optimizing job.
   * @throws InvalidValueException If the contents of the provided parameter list are not valid for
   *     use with this optimization algorithm.
   */
  @Override()
  public void initializeOptimizationAlgorithm(OptimizingJob optimizingJob, ParameterList parameters)
      throws InvalidValueException {
    this.optimizingJob = optimizingJob;

    String[] monitorClients = optimizingJob.getResourceMonitorClients();
    if ((monitorClients == null) || (monitorClients.length == 0)) {
      throw new InvalidValueException(
          "No resource monitor clients have been "
              + "requested for this optimizing job.  "
              + "At least one is required to provide "
              + "replication latency data.");
    }

    // Get the optimization statistic parameter and name.
    optimizeStatParameter = parameters.getMultiChoiceParameter(PARAM_OPTIMIZE_STAT);
    if ((optimizeStatParameter == null) || (!optimizeStatParameter.hasValue())) {
      throw new InvalidValueException("No value provided for the statistic " + "to optimize");
    }
    optimizeStat = optimizeStatParameter.getStringValue();

    // Get the optimization type parameter and value.
    optimizeTypeParameter = parameters.getMultiChoiceParameter(PARAM_OPTIMIZE_TYPE);
    if ((optimizeTypeParameter == null) || (!optimizeTypeParameter.hasValue())) {
      throw new InvalidValueException("No value provided for the " + "optimization type");
    }
    String optimizeTypeStr = optimizeTypeParameter.getStringValue();
    if (optimizeTypeStr.equalsIgnoreCase(Constants.OPTIMIZE_TYPE_MAXIMIZE)) {
      optimizeType = OPTIMIZE_TYPE_MAXIMIZE;
    } else if (optimizeTypeStr.equalsIgnoreCase(Constants.OPTIMIZE_TYPE_MINIMIZE)) {
      optimizeType = OPTIMIZE_TYPE_MINIMIZE;
    } else {
      throw new InvalidValueException(
          "Invalid value \"" + optimizeTypeStr + "\" for optimization type.");
    }

    // Get the maximum percent increase parameter and value.
    maxIncreaseParameter = parameters.getFloatParameter(PARAM_MAX_PERCENT_INCREASE);
    if ((maxIncreaseParameter == null) || (!maxIncreaseParameter.hasValue())) {
      throw new InvalidValueException(
          "No value provided for the maximum "
              + "allowed percentage increase in "
              + "replication latency.");
    }
    maxIncrease = maxIncreaseParameter.getFloatValue();

    // Get the maximum latency parameter and value.
    maxLatencyParameter = parameters.getFloatParameter(PARAM_MAX_REPLICA_LATENCY);
    if ((maxLatencyParameter == null) || (!maxLatencyParameter.hasValue())) {
      maxLatency = -1.0;
    } else {
      maxLatency = maxLatencyParameter.getFloatValue();
    }

    // Get the minimum percent improvement required for a new best iteration.
    minPctImprovement = 0.0F;
    minPctImprovementParameter = parameters.getFloatParameter(PARAM_MIN_PCT_IMPROVEMENT);
    if ((minPctImprovementParameter != null) && minPctImprovementParameter.hasValue()) {
      minPctImprovement = minPctImprovementParameter.getFloatValue();
    }

    // See If the provided optimizing job has run any iterations so far.  If so,
    // then look through them to determine the best value so far.
    bestValueSoFar = Double.NaN;
    Job[] iterations = optimizingJob.getAssociatedJobs();
    if (iterations != null) {
      for (int i = 0; i < iterations.length; i++) {
        try {
          if (!isAcceptableReplicationLatency(iterations[i])) {
            continue;
          }
        } catch (Exception e) {
        }

        StatTracker[] trackers = iterations[i].getStatTrackers(optimizeStat);
        if ((trackers != null) && (trackers.length > 0)) {
          StatTracker tracker = trackers[0].newInstance();
          tracker.aggregate(trackers);
          double value = tracker.getSummaryValue();
          if (Double.isNaN(bestValueSoFar)) {
            bestValueSoFar = value;
          } else if ((optimizeType == OPTIMIZE_TYPE_MAXIMIZE)
              && (value > bestValueSoFar)
              && (value >= (bestValueSoFar + bestValueSoFar * minPctImprovement))) {
            bestValueSoFar = value;
          } else if ((optimizeType == OPTIMIZE_TYPE_MINIMIZE)
              && (value < bestValueSoFar)
              && (value <= (bestValueSoFar - bestValueSoFar * minPctImprovement))) {
            bestValueSoFar = value;
          }
        }
      }
    }

    SLAMDServer slamdServer = optimizingJob.slamdServer;
    slamdServer.logMessage(
        Constants.LOG_LEVEL_JOB_DEBUG,
        "SingleStatisticWithReplicationLatencyOptimization"
            + "Algorithm.initializeOptimizationAlgorith("
            + optimizingJob.getOptimizingJobID()
            + ") best so far is "
            + String.valueOf(bestValueSoFar));
  }