// Path: src/main/java/org/avmframework/Vector.java
// public class Vector extends AbstractVector {
// 
//   public void addVariable(Variable variable) {
//     variables.add(variable);
//   }
// 
//   public List<Variable> getVariables() {
//     return new ArrayList<>(variables);
//   }
// 
//   public void setVariablesToInitial() {
//     for (Variable var : variables) {
//       var.setValueToInitial();
//     }
//   }
// 
//   public void setVariablesToRandom(RandomGenerator rg) {
//     for (Variable var : variables) {
//       var.setValueToRandom(rg);
//     }
//   }
// 
//   public Vector deepCopy() {
//     Vector copy = new Vector();
//     deepCopyVariables(copy);
//     return copy;
//   }
// }
// 
// Path: src/main/java/org/avmframework/objective/NumericObjectiveValue.java
// public class NumericObjectiveValue extends ObjectiveValue<NumericObjectiveValue> {
// 
//   protected double value;
//   protected boolean higherIsBetter;
// 
//   protected boolean haveOptimum = false;
//   protected double optimum;
// 
//   public NumericObjectiveValue(double value, boolean higherIsBetter) {
//     this.value = value;
//     this.higherIsBetter = higherIsBetter;
//   }
// 
//   public NumericObjectiveValue(double value, boolean higherIsBetter, double optimum) {
//     this(value, higherIsBetter);
//     this.haveOptimum = true;
//     this.optimum = optimum;
//   }
// 
//   public double getValue() {
//     return value;
//   }
// 
//   @Override
//   public boolean isOptimal() {
//     if (!haveOptimum) {
//       return false;
//     }
// 
//     if (higherIsBetter) {
//       return value >= optimum;
//     } else {
//       return value <= optimum;
//     }
//   }
// 
//   @Override
//   public int compareTo(NumericObjectiveValue other) {
//     if (value == other.value) {
//       return 0;
//     } else if (value < other.value) {
//       return higherIsBetter ? -1 : 1;
//     } else {
//       return higherIsBetter ? 1 : -1;
//     }
//   }
// 
//   @Override
//   public String toString() {
//     return "" + getValue();
//   }
// 
//   public static NumericObjectiveValue higherIsBetterObjectiveValue(double value) {
//     return new NumericObjectiveValue(value, true);
//   }
// 
//   public static NumericObjectiveValue higherIsBetterObjectiveValue(double value, double optimum) {
//     return new NumericObjectiveValue(value, true, optimum);
//   }
// 
//   public static NumericObjectiveValue lowerIsBetterObjectiveValue(double value) {
//     return new NumericObjectiveValue(value, false);
//   }
// 
//   public static NumericObjectiveValue lowerIsBetterObjectiveValue(double value, double optimum) {
//     return new NumericObjectiveValue(value, false, optimum);
//   }
// }
// 
// Path: src/main/java/org/avmframework/objective/ObjectiveFunction.java
// public abstract class ObjectiveFunction {
// 
//   public static final boolean USE_CACHE_DEFAULT = true;
// 
//   protected boolean useCache = USE_CACHE_DEFAULT;
//   protected Map<Vector, ObjectiveValue> previousVals = new HashMap<>();
//   protected Monitor monitor;
// 
//   public void setMonitor(Monitor monitor) {
//     this.monitor = monitor;
//   }
// 
//   public ObjectiveValue evaluate(Vector vector) throws TerminationException {
//     monitor.observeVector();
// 
//     if (useCache && previousVals.containsKey(vector)) {
//       return previousVals.get(vector);
//     }
// 
//     ObjectiveValue objVal = computeObjectiveValue(vector);
// 
//     if (useCache) {
//       previousVals.put(vector.deepCopy(), objVal);
//     }
// 
//     if (monitor != null) {
//       monitor.observePreviouslyUnseenVector(vector, objVal);
//     }
// 
//     return objVal;
//   }
// 
//   protected abstract ObjectiveValue computeObjectiveValue(Vector vector);
// }
// 
// Path: src/main/java/org/avmframework/objective/ObjectiveValue.java
// public abstract class ObjectiveValue<T extends ObjectiveValue> implements Comparable<T> {
// 
//   public abstract boolean isOptimal();
// 
//   public boolean betterThan(T other) {
//     return compareTo(other) > 0;
//   }
// 
//   public boolean sameAs(T other) {
//     return compareTo(other) == 0;
//   }
// 
//   public boolean worseThan(T other) {
//     return compareTo(other) < 0;
//   }
// }
// 
// Path: src/main/java/org/avmframework/variable/Variable.java
// public interface Variable {
// 
//   void setValueToInitial();
// 
//   void setValueToRandom(RandomGenerator randomGenerator);
// 
//   Variable deepCopy();
// }


import org.avmframework.Vector;
import org.avmframework.objective.NumericObjectiveValue;
import org.avmframework.objective.ObjectiveFunction;
import org.avmframework.objective.ObjectiveValue;
import org.avmframework.variable.Variable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
  // in selection the order does not matter, so we include  the coverage and execution time of all
  // the selected test cases
  public ObjectiveValue computeObjectiveValue(Vector vector) {
    List<TestCase> selectedTestSuite = new ArrayList<TestCase>();
    selectedTestSuite = selectTestCases(vector);

    double executionTime = 0;
    double fdc = 0;
    Set<String> coveredCoverageSet = new HashSet<String>();
    for (int i = 0; i < selectedTestSuite.size(); i++) {
      TestCase tempCase = selectedTestSuite.get(i);
      coveredCoverageSet.addAll(tempCase.getApiCovered());
      executionTime += tempCase.getTime();
      fdc += tempCase.getFaultDetection();
    }
    double fitness;
    // convert time budget from percentage to real number
    if (executionTime <= (transitionStateCoverage.getExecutionTime() * timeBudget / 100)) {
      double objCoverage;
      double objFaultDetectionCoverage;
      objCoverage = coveredCoverageSet.size() / transitionStateCoverage.getCoverage().size();
      objFaultDetectionCoverage = fdc / transitionStateCoverage.getFaultDetection();
      // subtract 1 for minimization
      fitness =
          (1 - objCoverage) * this.weightCoverage
          + (1 - objFaultDetectionCoverage) * this.weightFaultDetection;
    } else {
      fitness = 1; // this solution is bad since it exceeds the alloted time budget
    }

// Path: src/main/java/org/avmframework/Vector.java
// public class Vector extends AbstractVector {
// 
//   public void addVariable(Variable variable) {
//     variables.add(variable);
//   }
// 
//   public List<Variable> getVariables() {
//     return new ArrayList<>(variables);
//   }
// 
//   public void setVariablesToInitial() {
//     for (Variable var : variables) {
//       var.setValueToInitial();
//     }
//   }
// 
//   public void setVariablesToRandom(RandomGenerator rg) {
//     for (Variable var : variables) {
//       var.setValueToRandom(rg);
//     }
//   }
// 
//   public Vector deepCopy() {
//     Vector copy = new Vector();
//     deepCopyVariables(copy);
//     return copy;
//   }
// }
// 
// Path: src/main/java/org/avmframework/objective/NumericObjectiveValue.java
// public class NumericObjectiveValue extends ObjectiveValue<NumericObjectiveValue> {
// 
//   protected double value;
//   protected boolean higherIsBetter;
// 
//   protected boolean haveOptimum = false;
//   protected double optimum;
// 
//   public NumericObjectiveValue(double value, boolean higherIsBetter) {
//     this.value = value;
//     this.higherIsBetter = higherIsBetter;
//   }
// 
//   public NumericObjectiveValue(double value, boolean higherIsBetter, double optimum) {
//     this(value, higherIsBetter);
//     this.haveOptimum = true;
//     this.optimum = optimum;
//   }
// 
//   public double getValue() {
//     return value;
//   }
// 
//   @Override
//   public boolean isOptimal() {
//     if (!haveOptimum) {
//       return false;
//     }
// 
//     if (higherIsBetter) {
//       return value >= optimum;
//     } else {
//       return value <= optimum;
//     }
//   }
// 
//   @Override
//   public int compareTo(NumericObjectiveValue other) {
//     if (value == other.value) {
//       return 0;
//     } else if (value < other.value) {
//       return higherIsBetter ? -1 : 1;
//     } else {
//       return higherIsBetter ? 1 : -1;
//     }
//   }
// 
//   @Override
//   public String toString() {
//     return "" + getValue();
//   }
// 
//   public static NumericObjectiveValue higherIsBetterObjectiveValue(double value) {
//     return new NumericObjectiveValue(value, true);
//   }
// 
//   public static NumericObjectiveValue higherIsBetterObjectiveValue(double value, double optimum) {
//     return new NumericObjectiveValue(value, true, optimum);
//   }
// 
//   public static NumericObjectiveValue lowerIsBetterObjectiveValue(double value) {
//     return new NumericObjectiveValue(value, false);
//   }
// 
//   public static NumericObjectiveValue lowerIsBetterObjectiveValue(double value, double optimum) {
//     return new NumericObjectiveValue(value, false, optimum);
//   }
// }
// 
// Path: src/main/java/org/avmframework/objective/ObjectiveFunction.java
// public abstract class ObjectiveFunction {
// 
//   public static final boolean USE_CACHE_DEFAULT = true;
// 
//   protected boolean useCache = USE_CACHE_DEFAULT;
//   protected Map<Vector, ObjectiveValue> previousVals = new HashMap<>();
//   protected Monitor monitor;
// 
//   public void setMonitor(Monitor monitor) {
//     this.monitor = monitor;
//   }
// 
//   public ObjectiveValue evaluate(Vector vector) throws TerminationException {
//     monitor.observeVector();
// 
//     if (useCache && previousVals.containsKey(vector)) {
//       return previousVals.get(vector);
//     }
// 
//     ObjectiveValue objVal = computeObjectiveValue(vector);
// 
//     if (useCache) {
//       previousVals.put(vector.deepCopy(), objVal);
//     }
// 
//     if (monitor != null) {
//       monitor.observePreviouslyUnseenVector(vector, objVal);
//     }
// 
//     return objVal;
//   }
// 
//   protected abstract ObjectiveValue computeObjectiveValue(Vector vector);
// }
// 
// Path: src/main/java/org/avmframework/objective/ObjectiveValue.java
// public abstract class ObjectiveValue<T extends ObjectiveValue> implements Comparable<T> {
// 
//   public abstract boolean isOptimal();
// 
//   public boolean betterThan(T other) {
//     return compareTo(other) > 0;
//   }
// 
//   public boolean sameAs(T other) {
//     return compareTo(other) == 0;
//   }
// 
//   public boolean worseThan(T other) {
//     return compareTo(other) < 0;
//   }
// }
// 
// Path: src/main/java/org/avmframework/variable/Variable.java
// public interface Variable {
// 
//   void setValueToInitial();
// 
//   void setValueToRandom(RandomGenerator randomGenerator);
// 
//   Variable deepCopy();
// }


// Path: src/main/java/org/avmframework/examples/testoptimization/SelectionObjectiveFunction.java
import org.avmframework.Vector;
import org.avmframework.objective.NumericObjectiveValue;
import org.avmframework.objective.ObjectiveFunction;
import org.avmframework.objective.ObjectiveValue;
import org.avmframework.variable.Variable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

  // in selection the order does not matter, so we include  the coverage and execution time of all
  // the selected test cases
  public ObjectiveValue computeObjectiveValue(Vector vector) {
    List<TestCase> selectedTestSuite = new ArrayList<TestCase>();
    selectedTestSuite = selectTestCases(vector);

    double executionTime = 0;
    double fdc = 0;
    Set<String> coveredCoverageSet = new HashSet<String>();
    for (int i = 0; i < selectedTestSuite.size(); i++) {
      TestCase tempCase = selectedTestSuite.get(i);
      coveredCoverageSet.addAll(tempCase.getApiCovered());
      executionTime += tempCase.getTime();
      fdc += tempCase.getFaultDetection();
    }
    double fitness;
    // convert time budget from percentage to real number
    if (executionTime <= (transitionStateCoverage.getExecutionTime() * timeBudget / 100)) {
      double objCoverage;
      double objFaultDetectionCoverage;
      objCoverage = coveredCoverageSet.size() / transitionStateCoverage.getCoverage().size();
      objFaultDetectionCoverage = fdc / transitionStateCoverage.getFaultDetection();
      // subtract 1 for minimization
      fitness =
          (1 - objCoverage) * this.weightCoverage
          + (1 - objFaultDetectionCoverage) * this.weightFaultDetection;
    } else {
      fitness = 1; // this solution is bad since it exceeds the alloted time budget
    }

    return NumericObjectiveValue.lowerIsBetterObjectiveValue(fitness, 0);