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 edu.wpi.first.util.sendable.SendableBuilder;
010import java.util.function.Supplier;
011
012/**
013 * Schedules the given command when this command is initialized, and ends when it ends. Useful for
014 * forking off from CommandGroups. If this command is interrupted, it will cancel the command.
015 *
016 * <p>This class is provided by the NewCommands VendorDep
017 */
018public class ProxyCommand extends Command {
019  private final Supplier<Command> m_supplier;
020  private Command m_command;
021
022  /**
023   * Creates a new ProxyCommand that schedules the supplied command when initialized, and ends when
024   * it is no longer scheduled. Useful for lazily creating commands at runtime.
025   *
026   * @param supplier the command supplier
027   */
028  public ProxyCommand(Supplier<Command> supplier) {
029    m_supplier = requireNonNullParam(supplier, "supplier", "ProxyCommand");
030  }
031
032  /**
033   * Creates a new ProxyCommand that schedules the given command when initialized, and ends when it
034   * is no longer scheduled.
035   *
036   * @param command the command to run by proxy
037   */
038  @SuppressWarnings("this-escape")
039  public ProxyCommand(Command command) {
040    this(() -> command);
041    setName("Proxy(" + command.getName() + ")");
042  }
043
044  @Override
045  public void initialize() {
046    m_command = m_supplier.get();
047    m_command.schedule();
048  }
049
050  @Override
051  public void end(boolean interrupted) {
052    if (interrupted) {
053      m_command.cancel();
054    }
055    m_command = null;
056  }
057
058  @Override
059  public void execute() {}
060
061  @Override
062  public boolean isFinished() {
063    // because we're between `initialize` and `end`, `m_command` is necessarily not null
064    // but if called otherwise and m_command is null,
065    // it's UB, so we can do whatever we want -- like return true.
066    return m_command == null || !m_command.isScheduled();
067  }
068
069  /**
070   * Whether the given command should run when the robot is disabled. Override to return true if the
071   * command should run when disabled.
072   *
073   * @return true. Otherwise, this proxy would cancel commands that do run when disabled.
074   */
075  @Override
076  public boolean runsWhenDisabled() {
077    return true;
078  }
079
080  @Override
081  public void initSendable(SendableBuilder builder) {
082    super.initSendable(builder);
083    builder.addStringProperty(
084        "proxied", () -> m_command == null ? "null" : m_command.getName(), null);
085  }
086}