/**
   * Add the given map to the respective list
   *
   * @param int generateType - The type of item to add
   * @param Map<Integer, Integer> toAdd - The map to add
   */
  private void addToList(int generateType, Map<Integer, Integer> toAdd) {
    /* Containers for various types */
    State stateContainer;
    Action actionContainer;
    Consumption consumptionContainer;

    switch (generateType) {
      case 0:
        stateContainer = new State(toAdd);
        if (!this.possibleStates.contains(stateContainer)) {
          stateContainer.setCost(sumOf(toAdd));
          this.policy.put(stateContainer, null);
          this.possibleStates.add(stateContainer);
        }
        break;
      case 1:
        actionContainer = new Action(toAdd);
        if (!this.possibleActions.contains(actionContainer)) {
          this.possibleActions.add(actionContainer);
        }
        break;
      case 2:
        consumptionContainer = new Consumption(toAdd);
        if (!this.possibleConsumptions.contains(consumptionContainer)) {
          this.possibleConsumptions.add(consumptionContainer);
        }
        break;
      default:
        System.err.println("Invalid generation type");
        System.exit(13);
    }
  }
  /**
   * Print out important values
   *
   * @param mode - Indicates the type of values to print out.
   */
  private void printImportantValues(int mode) {
    Set<?> toPrint = null; // The set to print
    int currentIndex = 0; // The current index

    switch (mode) {
      case 0: // States
        System.err.println("Printing out states");
        toPrint = this.possibleStates;
        break;
      case 1: // Actions
        System.err.println("Printing out actions");
        toPrint = this.possibleActions;
        break;
      case 2: // Consumption
        System.err.println("Printing out consumptions");
        toPrint = this.possibleConsumptions;
        break;
      case 3: // Policies
        for (State current : this.policy.keySet()) {
          System.out.println(
              "State "
                  + (currentIndex + 1)
                  + ": "
                  + current.getState().toString()
                  + ". Do Action: "
                  + this.policy.get(current).getPurchases().toString());
          currentIndex++;
        }
        return;
      default: // Invalid mode
        System.err.println("Invalid mode for printing");
        System.exit(100);
    }

    if (toPrint == null) {
      System.err.println("Something really horrible went wrong");
      System.exit(150);
    }
    for (Object current : toPrint) {
      System.out.println("Value: " + (currentIndex + 1) + current.toString());
      currentIndex++;
    }
  }
  /** Generate all possible actions */
  private void generateAllPossibleActions() {
    double startTime, endTime; // Timer for generating states
    Map<Integer, Integer> action; // Action
    int maxSum = this.fridge.getMaxPurchase(); // The maximum amount we can purchase
    int maxIndex = this.fridge.getMaxTypes() - 1; // The maximum index of an action

    System.out.println("Generating all possible actions");
    startTime = endTime = Global.currentTime(); /* Set the time */
    action = new HashMap<Integer, Integer>();

    /* Generate zero case */
    for (int i = 0; i < (maxIndex + 1); ++i) {
      action.put(i, 0);
    }
    this.possibleActions.add(new Action(action));
    System.out.println("Size of action: " + action.size());

    while ((endTime - startTime) < this.MAX_GENERATION_TIME) {
      if (this.fridge.getMaxTypes() <= 0) {
        System.err.println("Invalid number of item types");
        System.exit(10);
      } else if (this.fridge.getMaxTypes() == 1) { // Only have 1 type of item
        break;
      } else { // Fridge has 2 or more types of items
        for (int i = maxSum; i >= 0; --i) {
          for (int j = 0; j < (maxIndex + 1); ++j) {
            recursiveGeneration(1, maxSum, i, j, action, this.fridge.getMaxPurchase());
            for (int k = 0; k < (maxIndex + 1); ++k) { // Reset list
              action.put(k, 0);
            }
          }
          endTime = Global.currentTime();
          if ((endTime - startTime) >= this.MAX_GENERATION_TIME) {
            break;
          }
        }
      }
      endTime = Global.currentTime(); // Get current time
      this.timeRemaining -= (endTime - startTime);
      System.out.println("Time remaining: " + this.timeRemaining);
      break;
    }
  }
  /** Generate all the possible states */
  private void generateAllPossibleStates() {
    double startTime, endTime; // Timer for generating states
    Map<Integer, Integer> state; // Action
    int maxSum = this.fridge.getCapacity(); // The maximum amount we can have in a state
    int maxIndex = this.fridge.getMaxTypes() - 1; // The maximum index of a state

    System.out.println("Generating all possible states");
    startTime = endTime = Global.currentTime(); /* Set the time */
    state = new HashMap<Integer, Integer>();

    /* Generate zero case */
    for (int i = 0; i < (maxIndex + 1); ++i) {
      state.put(i, 0);
    }
    this.possibleStates.add(new State(state));
    System.out.println("Size of state: " + state.size());

    while ((endTime - startTime) < this.MAX_GENERATION_TIME) {
      if (this.fridge.getMaxTypes() <= 0) {
        System.exit(10);
      } else if (this.fridge.getMaxTypes() == 1) { // Only have 1 type of item
        break;
      } else { // Fridge has 2 or more types of items
        for (int i = maxSum; i >= 0; --i) {
          for (int j = 0; j < (maxIndex + 1); ++j) {
            recursiveGeneration(0, maxSum, i, j, state, this.fridge.getMaxItemsPerType());
            for (int k = 0; k < (maxIndex + 1); ++k) { // Reset list
              state.put(k, 0);
            }
          }
          endTime = Global.currentTime();
          if ((endTime - startTime) >= this.MAX_GENERATION_TIME) {
            break;
          }
        }
      }
      endTime = Global.currentTime(); // Get current time
      this.timeRemaining -= (endTime - startTime);
      System.out.println("Time remaining: " + this.timeRemaining);
      break;
    }
  }