001// Copyright (c) FIRST and other WPILib contributors.
002// Open Source Software; you can modify and/or share it under the terms of
003// the WPILib BSD license file in the root directory of this project.
004
005package org.wpilib.commands3;
006
007import static edu.wpi.first.util.ErrorMessages.requireNonNullParam;
008
009import java.util.ArrayList;
010import java.util.HashSet;
011import java.util.List;
012import java.util.Set;
013
014/**
015 * A sequence of commands that run one after another. Each successive command only starts after its
016 * predecessor completes execution. The priority of a sequence is equal to the highest priority of
017 * any of its commands. If all commands in the sequence are able to run while the robot is disabled,
018 * then the sequence itself will be allowed to run while the robot is disabled.
019 *
020 * <p>The sequence will <i>own</i> all mechanisms required by all commands in the sequence for the
021 * entire duration of the sequence. This means that a mechanism owned by one command in the
022 * sequence, but not by a later one, will be <i>uncommanded</i> while that later command executes.
023 */
024public final class SequentialGroup implements Command {
025  private final String m_name;
026  private final List<Command> m_commands = new ArrayList<>();
027  private final Set<Mechanism> m_requirements = new HashSet<>();
028  private final int m_priority;
029
030  /**
031   * Creates a new command sequence.
032   *
033   * @param name the name of the sequence
034   * @param commands the commands to execute within the sequence
035   */
036  SequentialGroup(String name, List<Command> commands) {
037    requireNonNullParam(name, "name", "SequentialGroup");
038    requireNonNullParam(commands, "commands", "SequentialGroup");
039    for (int i = 0; i < commands.size(); i++) {
040      requireNonNullParam(commands.get(i), "commands[" + i + "]", "SequentialGroup");
041    }
042
043    m_name = name;
044    m_commands.addAll(commands);
045
046    for (var command : commands) {
047      m_requirements.addAll(command.requirements());
048    }
049
050    m_priority =
051        commands.stream().mapToInt(Command::priority).max().orElse(Command.DEFAULT_PRIORITY);
052  }
053
054  @Override
055  public void run(Coroutine coroutine) {
056    for (var command : m_commands) {
057      coroutine.await(command);
058    }
059  }
060
061  @Override
062  public String name() {
063    return m_name;
064  }
065
066  @Override
067  public Set<Mechanism> requirements() {
068    return m_requirements;
069  }
070
071  @Override
072  public int priority() {
073    return m_priority;
074  }
075
076  @Override
077  public String toString() {
078    return "SequentialGroup[name=" + m_name + "]";
079  }
080}