/**
* Copyright (C) 2002-2012 The FreeCol Team
*
* This file is part of FreeCol.
*
* FreeCol is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* FreeCol is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with FreeCol. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.freecol.common.option;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import org.freecolandroid.xml.stream.XMLStreamConstants;
import org.freecolandroid.xml.stream.XMLStreamException;
import org.freecolandroid.xml.stream.XMLStreamReader;
import org.freecolandroid.xml.stream.XMLStreamWriter;
import net.sf.freecol.client.gui.i18n.Messages;
import net.sf.freecol.common.model.Specification;
/**
* Used for grouping objects of {@link Option}s.
*/
public class OptionGroup extends AbstractOption<OptionGroup> {
private static Logger logger = Logger.getLogger(OptionGroup.class.getName());
private List<Option> options = new ArrayList<Option>();
private Map<String, Option> optionMap = new HashMap<String, Option>();
/**
* Creates a new <code>OptionGroup</code>.
* @param id The identifier for this option.
*/
public OptionGroup(String id) {
super(id);
}
public OptionGroup(Specification specification) {
super(specification);
}
public OptionGroup(String id, Specification specification) {
super(id, specification);
}
public OptionGroup clone() throws CloneNotSupportedException {
OptionGroup result = new OptionGroup(getId());
result.setValues(this);
result.options = new ArrayList<Option>(options);
result.optionMap = new HashMap<String, Option>(optionMap);
return result;
}
/**
* Adds the given <code>Option</code>.
* @param option The <code>Option</code> that should be
* added to this <code>OptionGroup</code>.
*/
public void add(Option option) {
String id = option.getId();
if (optionMap.containsKey(id)) {
for (int index = 0; index < options.size(); index++) {
if (id.equals(options.get(index).getId())) {
options.remove(index);
options.add(index, option);
break;
}
}
} else {
options.add(option);
}
optionMap.put(id, option);
if (option instanceof OptionGroup) {
addOptionGroup((OptionGroup) option);
}
}
private void addOptionGroup(OptionGroup group) {
for (Option option : group.getOptions()) {
optionMap.put(option.getId(), option);
if (option instanceof OptionGroup) {
addOptionGroup((OptionGroup) option);
}
}
}
public List<Option> getOptions() {
return options;
}
public Option getOption(String id) {
return optionMap.get(id);
}
/**
* Gets the integer value of an option.
*
* @param id The id of the option.
* @return The value.
* @exception IllegalArgumentException If there is no integer
* value associated with the specified option.
* @exception NullPointerException if the given <code>Option</code> does not exist.
*/
public int getInteger(String id) {
try {
return ((IntegerOption) getOption(id)).getValue();
} catch (ClassCastException e) {
throw new IllegalArgumentException("No integer value associated with the specified option.");
}
}
/**
* Sets the integer value of an option.
*
* @param id The id of the option.
* @param value the new value of the option.
* @exception IllegalArgumentException If there is no integer
* value associated with the specified option.
* @exception NullPointerException if the given <code>Option</code> does not exist.
*/
public void setInteger(String id, int value) {
try {
((IntegerOption) getOption(id)).setValue(value);
} catch (ClassCastException e) {
throw new IllegalArgumentException("No integer value associated with the specified option.");
}
}
/**
* Gets the boolean value of an option.
*
* @param id The id of the option.
* @return The value.
* @exception IllegalArgumentException If there is no boolean
* value associated with the specified option.
* @exception NullPointerException if the given <code>Option</code> does not exist.
*/
public boolean getBoolean(String id) {
try {
return ((BooleanOption) getOption(id)).getValue();
} catch (ClassCastException e) {
throw new IllegalArgumentException("No boolean value associated with the specified option.");
}
}
/**
* Sets the boolean value of an option.
*
* @param id The id of the option.
* @param value the new value of the option.
* @exception IllegalArgumentException If there is no boolean
* value associated with the specified option.
* @exception NullPointerException if the given <code>Option</code> does not exist.
*/
public void setBoolean(String id, boolean value) {
try {
((BooleanOption) getOption(id)).setValue(value);
} catch (ClassCastException e) {
throw new IllegalArgumentException("No boolean value associated with the specified option.");
}
}
/**
* Gets the string value of an option.
*
* @param id String, option ID
* @return String option value.
* @throws IllegalArgumentException If the specified option is not of String type
* @throws NullPointerException if the given <code>Option</code> does not exist.
*/
public String getString(String id) {
try {
return ((StringOption) getOption(id)).getValue();
} catch (ClassCastException e) {
throw new IllegalArgumentException("No String value associated with the specified option.");
}
}
/**
* Sets the string value of an option.
*
* @param id String, option ID
* @param value String, the new value of the option
* @throws IllegalArgumentException If the specified option is not of String type
* @throws NullPointerException if the given <code>Option</code> does not exist.
*/
public void setString(String id, String value) {
try {
((StringOption) getOption(id)).setValue(value);
} catch (ClassCastException e) {
throw new IllegalArgumentException("No String value associated with the specified option.");
}
}
/**
* Removes all of the <code>Option</code>s from this <code>OptionGroup</code>.
*/
public void removeAll() {
options.clear();
optionMap.clear();
}
/**
* Returns an <code>Iterator</code> for the <code>Option</code>s.
* @return The <code>Iterator</code>.
*/
public Iterator<Option> iterator() {
return options.iterator();
}
/**
* This method writes an XML-representation of this object to
* the given stream.
*
* @param out The target stream.
* @throws XMLStreamException if there are any problems writing
* to the stream.
*/
protected void toXMLImpl(XMLStreamWriter out) throws XMLStreamException {
// Start element:
out.writeStartElement(getXMLElementTagName());
out.writeAttribute(ID_ATTRIBUTE_TAG, getId());
Iterator<Option> oi = options.iterator();
while (oi.hasNext()) {
(oi.next()).toXML(out);
}
out.writeEndElement();
}
/**
* Initialize this object from an XML-representation of this object.
* @param in The input stream with the XML.
* @throws XMLStreamException if a problem was encountered
* during parsing.
*/
@Override
protected void readFromXMLImpl(XMLStreamReader in) throws XMLStreamException {
final String id = in.getAttributeValue(null, ID_ATTRIBUTE_TAG);
if (id != null) {
setId(id);
}
while (in.nextTag() != XMLStreamConstants.END_ELEMENT) {
String optionId = in.getAttributeValue(null, ID_ATTRIBUTE_TAG);
Option option = getOption(optionId);
if (option == null) {
AbstractOption abstractOption = readOption(in);
if (abstractOption != null) {
add(abstractOption);
abstractOption.setGroup(this.getId());
}
} else {
option.readFromXML(in);
}
}
}
/**
* Returns the name of this <code>Option</code>.
*
* @return The name as provided in the constructor.
*/
public String getName() {
return Messages.message(getId() + ".name");
}
/**
* Gives a short description of this <code>Option</code>. Can for
* instance be used as a tooltip text.
*
* @return A short description of this <code>Option</code>.
*/
public String getShortDescription() {
return Messages.message(getId() + ".shortDescription");
}
/**
* Returns the OptionGroup itself.
*
* @return an <code>Object</code> value
*/
public OptionGroup getValue() {
return this;
}
/**
* Copy the options of another OptionGroup.
*
* @param value an <code>Object</code> value
*/
@SuppressWarnings("unchecked")
public void setValue(OptionGroup value) {
for (Option other : value.getOptions()) {
Option mine = getOption(other.getId());
// could be null if using custom.xml generated from an
// older version of the specification, for example
if (mine != null) {
mine.setValue(other.getValue());
}
}
}
/**
* Debug print helper.
*
* @return Human-readable description of this OptionGroup.
*/
@Override
public String toString() {
StringBuilder g = new StringBuilder();
g.append(getName() + "<");
for (Option o : getOptions()) {
g.append(" ");
if (o instanceof OptionGroup) {
g.append(((OptionGroup)o).toString());
} else if (o instanceof ListOption) {
g.append(((ListOption)o).toString());
} else {
g.append(o.getId()); // TODO: add useful toString() to others
}
}
g.append(" >\n");
return g.toString();
}
/**
* Gets the tag name of the root element representing this object.
*
* @return "optionGroup".
*/
public static String getXMLElementTagName() {
return "optionGroup";
}
}