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  public ConditionalCommand(Command onTrue, Command onFalse, BooleanSupplier condition) {
036    m_onTrue = requireNonNullParam(onTrue, "onTrue", "ConditionalCommand");
037    m_onFalse = requireNonNullParam(onFalse, "onFalse", "ConditionalCommand");
038    m_condition = requireNonNullParam(condition, "condition", "ConditionalCommand");
039
040    CommandScheduler.getInstance().registerComposedCommands(onTrue, onFalse);
041
042    m_requirements.addAll(m_onTrue.getRequirements());
043    m_requirements.addAll(m_onFalse.getRequirements());
044  }
045
046  @Override
047  public void initialize() {
048    if (m_condition.getAsBoolean()) {
049      m_selectedCommand = m_onTrue;
050    } else {
051      m_selectedCommand = m_onFalse;
052    }
053    m_selectedCommand.initialize();
054  }
055
056  @Override
057  public void execute() {
058    m_selectedCommand.execute();
059  }
060
061  @Override
062  public void end(boolean interrupted) {
063    m_selectedCommand.end(interrupted);
064  }
065
066  @Override
067  public boolean isFinished() {
068    return m_selectedCommand.isFinished();
069  }
070
071  @Override
072  public boolean runsWhenDisabled() {
073    return m_onTrue.runsWhenDisabled() && m_onFalse.runsWhenDisabled();
074  }
075
076  @Override
077  public InterruptionBehavior getInterruptionBehavior() {
078    if (m_onTrue.getInterruptionBehavior() == InterruptionBehavior.kCancelSelf
079        || m_onFalse.getInterruptionBehavior() == InterruptionBehavior.kCancelSelf) {
080      return InterruptionBehavior.kCancelSelf;
081    } else {
082      return InterruptionBehavior.kCancelIncoming;
083    }
084  }
085
086  @Override
087  public void initSendable(SendableBuilder builder) {
088    super.initSendable(builder);
089    builder.addStringProperty("onTrue", m_onTrue::getName, null);
090    builder.addStringProperty("onFalse", m_onFalse::getName, null);
091    builder.addStringProperty(
092        "selected",
093        () -> {
094          if (m_selectedCommand == null) {
095            return "null";
096          } else {
097            return m_selectedCommand.getName();
098          }
099        },
100        null);
101  }
102}