001/*----------------------------------------------------------------------------*/
002/* Copyright (c) FIRST 2008-2012. All Rights Reserved.                        */
003/* Open Source Software - may be modified and shared by FRC teams. The code   */
004/* must be accompanied by the FIRST BSD license file in the root directory of */
005/* the project.                                                               */
006/*----------------------------------------------------------------------------*/
007
008package edu.wpi.first.wpilibj.command;
009
010import edu.wpi.first.wpilibj.NamedSendable;
011import edu.wpi.first.wpilibj.tables.ITable;
012import java.util.Enumeration;
013import java.util.Vector;
014
015/**
016 * This class defines a major component of the robot.
017 *
018 * <p>A good example of a subsystem is the driveline, or a claw if the robot has one.</p>
019 *
020 * <p>All motors should be a part of a subsystem. For instance, all the wheel motors should be
021 * a part of some kind of "Driveline" subsystem.</p>
022 *
023 * <p>Subsystems are used within the command system as requirements for {@link Command}.
024 * Only one command which requires a subsystem can run at a time.  Also, subsystems
025 * can have default commands which are started if there is no command running which
026 * requires this subsystem.</p>
027 *
028 * @author Joe Grinstead
029 * @see Command
030 */
031public abstract class Subsystem implements NamedSendable {
032
033    /** Whether or not getDefaultCommand() was called */
034    private boolean initializedDefaultCommand = false;
035    /** The current command */
036    private Command currentCommand;
037    private boolean currentCommandChanged;
038
039    /** The default command */
040    private Command defaultCommand;
041    /** The name */
042    private String name;
043    /** List of all subsystems created */
044    private static Vector allSubsystems = new Vector();
045
046    /**
047     * Creates a subsystem with the given name
048     * @param name the name of the subsystem
049     */
050    public Subsystem(String name) {
051        this.name = name;
052        Scheduler.getInstance().registerSubsystem(this);
053    }
054
055    /**
056     * Creates a subsystem.  This will set the name to the name of the class.
057     */
058    public Subsystem() {
059        this.name = getClass().getName().substring(getClass().getName().lastIndexOf('.') + 1);
060        Scheduler.getInstance().registerSubsystem(this);
061        currentCommandChanged = true;
062    }
063
064    /**
065     * Initialize the default command for a subsystem
066     * By default subsystems have no default command, but if they do, the default command is set
067     * with this method. It is called on all Subsystems by CommandBase in the users program after
068     * all the Subsystems are created.
069     */
070    protected abstract void initDefaultCommand();
071
072    /**
073     * Sets the default command.  If this is not called or is called with null,
074     * then there will be no default command for the subsystem.
075     *
076     * <p><b>WARNING:</b> This should <b>NOT</b> be called in a constructor if the subsystem is a
077     * singleton.</p>
078     *
079     * @param command the default command (or null if there should be none)
080     * @throws IllegalUseOfCommandException if the command does not require the subsystem
081     */
082    protected void setDefaultCommand(Command command) {
083        if (command == null) {
084            defaultCommand = null;
085        } else {
086            boolean found = false;
087            Enumeration requirements = command.getRequirements();
088            while (requirements.hasMoreElements()) {
089                if (requirements.nextElement().equals(this)) {
090                    found = true;
091//            } else {
092//                throw new IllegalUseOfCommandException("A default command cannot require multiple subsystems");
093                }
094            }
095            if (!found) {
096                throw new IllegalUseOfCommandException("A default command must require the subsystem");
097            }
098            defaultCommand = command;
099        }
100        if (table != null) {
101            if (defaultCommand != null) {
102                table.putBoolean("hasDefault", true);
103                table.putString("default", defaultCommand.getName());
104            } else {
105                table.putBoolean("hasDefault", false);
106            }
107        }
108    }
109
110    /**
111     * Returns the default command (or null if there is none).
112     * @return the default command
113     */
114    protected Command getDefaultCommand() {
115        if (!initializedDefaultCommand) {
116            initializedDefaultCommand = true;
117            initDefaultCommand();
118        }
119        return defaultCommand;
120    }
121
122    /**
123     * Sets the current command
124     * @param command the new current command
125     */
126    void setCurrentCommand(Command command) {
127        currentCommand = command;
128        currentCommandChanged = true;
129    }
130
131    /**
132     * Call this to alert Subsystem that the current command is actually the command.
133     * Sometimes, the {@link Subsystem} is told that it has no command while the {@link Scheduler}
134     * is going through the loop, only to be soon after given a new one.  This will avoid that situation.
135     */
136    void confirmCommand() {
137        if (currentCommandChanged) {
138            if (table != null) {
139                if (currentCommand != null) {
140                    table.putBoolean("hasCommand", true);
141                    table.putString("command", currentCommand.getName());
142                } else {
143                    table.putBoolean("hasCommand", false);
144                }
145            }
146            currentCommandChanged = false;
147        }
148    }
149
150    /**
151     * Returns the command which currently claims this subsystem.
152     * @return the command which currently claims this subsystem
153     */
154    public Command getCurrentCommand() {
155        return currentCommand;
156    }
157
158    public String toString() {
159        return getName();
160    }
161
162    /**
163     * Returns the name of this subsystem, which is by default the class name.
164     * @return the name of this subsystem
165     */
166    public String getName() {
167        return name;
168    }
169
170    public String getSmartDashboardType() {
171        return "Subsystem";
172    }
173    private ITable table;
174    public void initTable(ITable table) {
175        this.table = table;
176        if(table!=null) {
177            if (defaultCommand != null) {
178                table.putBoolean("hasDefault", true);
179                table.putString("default", defaultCommand.getName());
180            } else {
181                table.putBoolean("hasDefault", false);
182            }
183            if (currentCommand != null) {
184                table.putBoolean("hasCommand", true);
185                table.putString("command", currentCommand.getName());
186            } else {
187                table.putBoolean("hasCommand", false);
188            }
189        }
190    }
191    /**
192     * {@inheritDoc}
193     */
194    public ITable getTable() {
195        return table;
196    }
197}