001/*
002  Licensed to the Apache Software Foundation (ASF) under one or more
003  contributor license agreements.  See the NOTICE file distributed with
004  this work for additional information regarding copyright ownership.
005  The ASF licenses this file to You under the Apache License, Version 2.0
006  (the "License"); you may not use this file except in compliance with
007  the License.  You may obtain a copy of the License at
008
009      https://www.apache.org/licenses/LICENSE-2.0
010
011  Unless required by applicable law or agreed to in writing, software
012  distributed under the License is distributed on an "AS IS" BASIS,
013  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014  See the License for the specific language governing permissions and
015  limitations under the License.
016 */
017
018package org.apache.commons.cli;
019
020import java.io.Serializable;
021import java.util.Collection;
022import java.util.Iterator;
023import java.util.LinkedHashMap;
024import java.util.Map;
025
026/**
027 * A group of mutually exclusive options.
028 */
029public class OptionGroup implements Serializable {
030
031    /** The serial version UID. */
032    private static final long serialVersionUID = 1L;
033
034    /**
035     * Maps options where keys are option name and values are the options.
036     */
037    private final Map<String, Option> optionMap = new LinkedHashMap<>();
038
039    /** The name of the selected option. */
040    private String selected;
041
042    /** Specified whether this group is required. */
043    private boolean required;
044
045    /**
046     * Constructs a new instance.
047     */
048    public OptionGroup() {
049        // empty
050    }
051
052    /**
053     * Adds the given {@code Option} to this group.
054     *
055     * @param option the option to add to this group.
056     * @return this option group with the option added.
057     */
058    public OptionGroup addOption(final Option option) {
059        optionMap.put(option.getKey(), option);
060        return this;
061    }
062
063    /**
064     * Gets the names of the options in this group as a {@code Collection}.
065     *
066     * @return the names of the options in this group as a {@code Collection}.
067     */
068    public Collection<String> getNames() {
069        // the key set is the collection of names
070        return optionMap.keySet();
071    }
072
073    /**
074     * Gets the options in this group as a {@code Collection}.
075     *
076     * @return the options in this group as a {@code Collection}.
077     */
078    public Collection<Option> getOptions() {
079        // the values are the collection of options
080        return optionMap.values();
081    }
082
083    /**
084     * Gets the selected option name.
085     *
086     * If the selected option is deprecated <em>no warning is logged</em>.
087     * @return the selected option name.
088     */
089    public String getSelected() {
090        return selected;
091    }
092
093    /**
094     * Tests whether this option group is required.
095     *
096     * @return whether this option group is required.
097     */
098    public boolean isRequired() {
099        return required;
100    }
101
102    /**
103     * Tests whether an option is selected.
104     *
105     *  If an option is selected and is deprecated <em>no warning is logged</em>.
106     * @return whether whether an option is selected.
107     * @since 1.9.0
108     */
109    public boolean isSelected() {
110        return selected != null;
111    }
112
113    /**
114     * Sets whether this group is required.
115     *
116     * @param required whether this group is required.
117     */
118    public void setRequired(final boolean required) {
119        this.required = required;
120    }
121
122    /**
123     * Sets the selected option of this group to {@code name}.
124     *
125     * If the selected option is deprecated <em>no warning is logged</em>.
126     * @param option the option that is selected.
127     * @throws AlreadySelectedException if an option from this group has already been selected.
128     */
129    public void setSelected(final Option option) throws AlreadySelectedException {
130        if (option == null) {
131            // reset the option previously selected
132            selected = null;
133            return;
134        }
135        // if no option has already been selected or the
136        // same option is being reselected then set the
137        // selected member variable
138        if (selected != null && !selected.equals(option.getKey())) {
139            throw new AlreadySelectedException(this, option);
140        }
141        selected = option.getKey();
142    }
143
144    /**
145     * Returns the stringified version of this OptionGroup.
146     *
147     * @return the stringified representation of this group.
148     */
149    @Override
150    public String toString() {
151        final StringBuilder buff = new StringBuilder();
152        final Iterator<Option> iter = getOptions().iterator();
153        buff.append("[");
154        while (iter.hasNext()) {
155            final Option option = iter.next();
156            if (option.getOpt() != null) {
157                buff.append("-");
158                buff.append(option.getOpt());
159            } else {
160                buff.append("--");
161                buff.append(option.getLongOpt());
162            }
163
164            if (option.getDescription() != null) {
165                buff.append(Char.SP);
166                buff.append(option.getDescription());
167            }
168
169            if (iter.hasNext()) {
170                buff.append(", ");
171            }
172        }
173        buff.append("]");
174        return buff.toString();
175    }
176}