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 edu.wpi.first.wpilibj2.command;
006
007import static edu.wpi.first.util.ErrorMessages.requireNonNullParam;
008
009import java.util.Map;
010import java.util.Set;
011import java.util.function.BooleanSupplier;
012import java.util.function.Supplier;
013
014/**
015 * Namespace for command factory methods.
016 *
017 * <p>For convenience, you might want to static import the members of this class.
018 */
019public final class Commands {
020  /**
021   * Constructs a command that does nothing, finishing immediately.
022   *
023   * @return the command
024   */
025  public static Command none() {
026    return new InstantCommand();
027  }
028
029  /**
030   * Constructs a command that does nothing until interrupted.
031   *
032   * @param requirements Subsystems to require
033   * @return the command
034   */
035  public static Command idle(Subsystem... requirements) {
036    return run(() -> {}, requirements);
037  }
038
039  // Action Commands
040
041  /**
042   * Constructs a command that runs an action once and finishes.
043   *
044   * @param action the action to run
045   * @param requirements subsystems the action requires
046   * @return the command
047   * @see InstantCommand
048   */
049  public static Command runOnce(Runnable action, Subsystem... requirements) {
050    return new InstantCommand(action, requirements);
051  }
052
053  /**
054   * Constructs a command that runs an action every iteration until interrupted.
055   *
056   * @param action the action to run
057   * @param requirements subsystems the action requires
058   * @return the command
059   * @see RunCommand
060   */
061  public static Command run(Runnable action, Subsystem... requirements) {
062    return new RunCommand(action, requirements);
063  }
064
065  /**
066   * Constructs a command that runs an action once and another action when the command is
067   * interrupted.
068   *
069   * @param start the action to run on start
070   * @param end the action to run on interrupt
071   * @param requirements subsystems the action requires
072   * @return the command
073   * @see StartEndCommand
074   */
075  public static Command startEnd(Runnable start, Runnable end, Subsystem... requirements) {
076    return new StartEndCommand(start, end, requirements);
077  }
078
079  /**
080   * Constructs a command that runs an action every iteration until interrupted, and then runs a
081   * second action.
082   *
083   * @param run the action to run every iteration
084   * @param end the action to run on interrupt
085   * @param requirements subsystems the action requires
086   * @return the command
087   */
088  public static Command runEnd(Runnable run, Runnable end, Subsystem... requirements) {
089    requireNonNullParam(end, "end", "Command.runEnd");
090    return new FunctionalCommand(
091        () -> {}, run, interrupted -> end.run(), () -> false, requirements);
092  }
093
094  /**
095   * Constructs a command that prints a message and finishes.
096   *
097   * @param message the message to print
098   * @return the command
099   * @see PrintCommand
100   */
101  public static Command print(String message) {
102    return new PrintCommand(message);
103  }
104
105  // Idling Commands
106
107  /**
108   * Constructs a command that does nothing, finishing after a specified duration.
109   *
110   * @param seconds after how long the command finishes
111   * @return the command
112   * @see WaitCommand
113   */
114  public static Command waitSeconds(double seconds) {
115    return new WaitCommand(seconds);
116  }
117
118  /**
119   * Constructs a command that does nothing, finishing once a condition becomes true.
120   *
121   * @param condition the condition
122   * @return the command
123   * @see WaitUntilCommand
124   */
125  public static Command waitUntil(BooleanSupplier condition) {
126    return new WaitUntilCommand(condition);
127  }
128
129  // Selector Commands
130
131  /**
132   * Runs one of two commands, based on the boolean selector function.
133   *
134   * @param onTrue the command to run if the selector function returns true
135   * @param onFalse the command to run if the selector function returns false
136   * @param selector the selector function
137   * @return the command
138   * @see ConditionalCommand
139   */
140  public static Command either(Command onTrue, Command onFalse, BooleanSupplier selector) {
141    return new ConditionalCommand(onTrue, onFalse, selector);
142  }
143
144  /**
145   * Runs one of several commands, based on the selector function.
146   *
147   * @param <K> The type of key used to select the command
148   * @param selector the selector function
149   * @param commands map of commands to select from
150   * @return the command
151   * @see SelectCommand
152   */
153  public static <K> Command select(Map<K, Command> commands, Supplier<? extends K> selector) {
154    return new SelectCommand<>(commands, selector);
155  }
156
157  /**
158   * Runs the command supplied by the supplier.
159   *
160   * @param supplier the command supplier
161   * @param requirements the set of requirements for this command
162   * @return the command
163   * @see DeferredCommand
164   */
165  public static Command defer(Supplier<Command> supplier, Set<Subsystem> requirements) {
166    return new DeferredCommand(supplier, requirements);
167  }
168
169  /**
170   * Constructs a command that schedules the command returned from the supplier when initialized,
171   * and ends when it is no longer scheduled. The supplier is called when the command is
172   * initialized.
173   *
174   * @param supplier the command supplier
175   * @return the command
176   * @see ProxyCommand
177   */
178  public static Command deferredProxy(Supplier<Command> supplier) {
179    return new ProxyCommand(supplier);
180  }
181
182  // Command Groups
183
184  /**
185   * Runs a group of commands in series, one after the other.
186   *
187   * @param commands the commands to include
188   * @return the command group
189   * @see SequentialCommandGroup
190   */
191  public static Command sequence(Command... commands) {
192    return new SequentialCommandGroup(commands);
193  }
194
195  /**
196   * Runs a group of commands in series, one after the other. Once the last command ends, the group
197   * is restarted.
198   *
199   * @param commands the commands to include
200   * @return the command group
201   * @see SequentialCommandGroup
202   * @see Command#repeatedly()
203   */
204  public static Command repeatingSequence(Command... commands) {
205    return sequence(commands).repeatedly();
206  }
207
208  /**
209   * Runs a group of commands at the same time. Ends once all commands in the group finish.
210   *
211   * @param commands the commands to include
212   * @return the command
213   * @see ParallelCommandGroup
214   */
215  public static Command parallel(Command... commands) {
216    return new ParallelCommandGroup(commands);
217  }
218
219  /**
220   * Runs a group of commands at the same time. Ends once any command in the group finishes, and
221   * cancels the others.
222   *
223   * @param commands the commands to include
224   * @return the command group
225   * @see ParallelRaceGroup
226   */
227  public static Command race(Command... commands) {
228    return new ParallelRaceGroup(commands);
229  }
230
231  /**
232   * Runs a group of commands at the same time. Ends once a specific command finishes, and cancels
233   * the others.
234   *
235   * @param deadline the deadline command
236   * @param otherCommands the other commands to include
237   * @return the command group
238   * @see ParallelDeadlineGroup
239   * @throws IllegalArgumentException if the deadline command is also in the otherCommands argument
240   */
241  public static Command deadline(Command deadline, Command... otherCommands) {
242    return new ParallelDeadlineGroup(deadline, otherCommands);
243  }
244
245  private Commands() {
246    throw new UnsupportedOperationException("This is a utility class");
247  }
248}