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.wpilibj.command; 006 007import java.util.Enumeration; 008 009/** 010 * A {@link ConditionalCommand} is a {@link Command} that starts one of two commands. 011 * 012 * <p>A {@link ConditionalCommand} uses m_condition to determine whether it should run m_onTrue or 013 * m_onFalse. 014 * 015 * <p>A {@link ConditionalCommand} adds the proper {@link Command} to the {@link Scheduler} during 016 * {@link ConditionalCommand#initialize()} and then {@link ConditionalCommand#isFinished()} will 017 * return true once that {@link Command} has finished executing. 018 * 019 * <p>If no {@link Command} is specified for m_onFalse, the occurrence of that condition will be a 020 * no-op. 021 * 022 * <p>A ConditionalCommand will require the superset of subsystems of the onTrue and onFalse 023 * commands. 024 * 025 * @see Command 026 * @see Scheduler 027 */ 028public abstract class ConditionalCommand extends Command { 029 /** The Command to execute if {@link ConditionalCommand#condition()} returns true. */ 030 private Command m_onTrue; 031 032 /** The Command to execute if {@link ConditionalCommand#condition()} returns false. */ 033 private Command m_onFalse; 034 035 /** Stores command chosen by condition. */ 036 private Command m_chosenCommand; 037 038 private void requireAll() { 039 if (m_onTrue != null) { 040 for (Enumeration<?> e = m_onTrue.getRequirements(); e.hasMoreElements(); ) { 041 requires((Subsystem) e.nextElement()); 042 } 043 } 044 045 if (m_onFalse != null) { 046 for (Enumeration<?> e = m_onFalse.getRequirements(); e.hasMoreElements(); ) { 047 requires((Subsystem) e.nextElement()); 048 } 049 } 050 } 051 052 /** 053 * Creates a new ConditionalCommand with given onTrue and onFalse Commands. 054 * 055 * <p>Users of this constructor should also override condition(). 056 * 057 * @param onTrue The Command to execute if {@link ConditionalCommand#condition()} returns true 058 */ 059 public ConditionalCommand(Command onTrue) { 060 this(onTrue, null); 061 } 062 063 /** 064 * Creates a new ConditionalCommand with given onTrue and onFalse Commands. 065 * 066 * <p>Users of this constructor should also override condition(). 067 * 068 * @param onTrue The Command to execute if {@link ConditionalCommand#condition()} returns true 069 * @param onFalse The Command to execute if {@link ConditionalCommand#condition()} returns false 070 */ 071 public ConditionalCommand(Command onTrue, Command onFalse) { 072 m_onTrue = onTrue; 073 m_onFalse = onFalse; 074 075 requireAll(); 076 } 077 078 /** 079 * Creates a new ConditionalCommand with given name and onTrue and onFalse Commands. 080 * 081 * <p>Users of this constructor should also override condition(). 082 * 083 * @param name the name for this command group 084 * @param onTrue The Command to execute if {@link ConditionalCommand#condition()} returns true 085 */ 086 public ConditionalCommand(String name, Command onTrue) { 087 this(name, onTrue, null); 088 } 089 090 /** 091 * Creates a new ConditionalCommand with given name and onTrue and onFalse Commands. 092 * 093 * <p>Users of this constructor should also override condition(). 094 * 095 * @param name the name for this command group 096 * @param onTrue The Command to execute if {@link ConditionalCommand#condition()} returns true 097 * @param onFalse The Command to execute if {@link ConditionalCommand#condition()} returns false 098 */ 099 public ConditionalCommand(String name, Command onTrue, Command onFalse) { 100 super(name); 101 m_onTrue = onTrue; 102 m_onFalse = onFalse; 103 104 requireAll(); 105 } 106 107 /** 108 * The Condition to test to determine which Command to run. 109 * 110 * @return true if m_onTrue should be run or false if m_onFalse should be run. 111 */ 112 protected abstract boolean condition(); 113 114 /** Calls {@link ConditionalCommand#condition()} and runs the proper command. */ 115 @Override 116 protected void _initialize() { 117 if (condition()) { 118 m_chosenCommand = m_onTrue; 119 } else { 120 m_chosenCommand = m_onFalse; 121 } 122 123 if (m_chosenCommand != null) { 124 /* 125 * This is a hack to make canceling the chosen command inside a 126 * CommandGroup work properly 127 */ 128 m_chosenCommand.clearRequirements(); 129 130 m_chosenCommand.start(); 131 } 132 super._initialize(); 133 } 134 135 @Override 136 protected synchronized void _cancel() { 137 if (m_chosenCommand != null && m_chosenCommand.isRunning()) { 138 m_chosenCommand.cancel(); 139 } 140 141 super._cancel(); 142 } 143 144 @Override 145 protected boolean isFinished() { 146 if (m_chosenCommand != null) { 147 return m_chosenCommand.isCompleted(); 148 } else { 149 return true; 150 } 151 } 152 153 @Override 154 protected void _interrupted() { 155 if (m_chosenCommand != null && m_chosenCommand.isRunning()) { 156 m_chosenCommand.cancel(); 157 } 158 159 super._interrupted(); 160 } 161}