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.BooleanSupplier;
011
012/**
013 * A command composition that runs one of two commands, depending on the value of the given
014 * condition when this command is initialized.
015 *
016 * <p>The rules for command compositions apply: command instances that are passed to it cannot be
017 * added to any other composition or scheduled individually, and the composition requires all
018 * subsystems its components require.
019 *
020 * <p>This class is provided by the NewCommands VendorDep
021 */
022public class ConditionalCommand extends Command {
023  private final Command m_onTrue;
024  private final Command m_onFalse;
025  private final BooleanSupplier m_condition;
026  private Command m_selectedCommand;
027
028  /**
029   * Creates a new ConditionalCommand.
030   *
031   * @param onTrue the command to run if the condition is true
032   * @param onFalse the command to run if the condition is false
033   * @param condition the condition to determine which command to run
034   */
035  @SuppressWarnings("this-escape")
036  public ConditionalCommand(Command onTrue, Command onFalse, BooleanSupplier condition) {
037    m_onTrue = requireNonNullParam(onTrue, "onTrue", "ConditionalCommand");
038    m_onFalse = requireNonNullParam(onFalse, "onFalse", "ConditionalCommand");
039    m_condition = requireNonNullParam(condition, "condition", "ConditionalCommand");
040
041    CommandScheduler.getInstance().registerComposedCommands(onTrue, onFalse);
042
043    addRequirements(m_onTrue.getRequirements());
044    addRequirements(m_onFalse.getRequirements());
045  }
046
047  @Override
048  public void initialize() {
049    if (m_condition.getAsBoolean()) {
050      m_selectedCommand = m_onTrue;
051    } else {
052      m_selectedCommand = m_onFalse;
053    }
054    m_selectedCommand.initialize();
055  }
056
057  @Override
058  public void execute() {
059    m_selectedCommand.execute();
060  }
061
062  @Override
063  public void end(boolean interrupted) {
064    m_selectedCommand.end(interrupted);
065  }
066
067  @Override
068  public boolean isFinished() {
069    return m_selectedCommand.isFinished();
070  }
071
072  @Override
073  public boolean runsWhenDisabled() {
074    return m_onTrue.runsWhenDisabled() && m_onFalse.runsWhenDisabled();
075  }
076
077  @Override
078  public InterruptionBehavior getInterruptionBehavior() {
079    if (m_onTrue.getInterruptionBehavior() == InterruptionBehavior.kCancelSelf
080        || m_onFalse.getInterruptionBehavior() == InterruptionBehavior.kCancelSelf) {
081      return InterruptionBehavior.kCancelSelf;
082    } else {
083      return InterruptionBehavior.kCancelIncoming;
084    }
085  }
086
087  @Override
088  public void initSendable(SendableBuilder builder) {
089    super.initSendable(builder);
090    builder.addStringProperty("onTrue", m_onTrue::getName, null);
091    builder.addStringProperty("onFalse", m_onFalse::getName, null);
092    builder.addStringProperty(
093        "selected",
094        () -> {
095          if (m_selectedCommand == null) {
096            return "null";
097          } else {
098            return m_selectedCommand.getName();
099          }
100        },
101        null);
102  }
103}