/**
* 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.model;
import java.util.Set;
import net.sf.freecol.common.option.OptionGroup;
import org.freecolandroid.xml.stream.XMLStreamConstants;
import org.freecolandroid.xml.stream.XMLStreamException;
import org.freecolandroid.xml.stream.XMLStreamReader;
import org.freecolandroid.xml.stream.XMLStreamWriter;
/**
* The base class for all types defined by the specification. It can
* be instantiated in order to provide a source for modifiers and
* abilities that are provided by the code rather than defined in the
* specification, such as the "artillery in the open" penalty.
*/
public class FreeColGameObjectType extends FreeColObject {
private int index = -1;
/**
* The default index of Modifiers provided by this type.
*/
private int modifierIndex = 100;
/**
* Whether the type is abstract or can be instantiated.
*/
private boolean abstractType;
/**
* Describe featureContainer here.
*/
private FeatureContainer featureContainer;
protected FreeColGameObjectType() {
// empty constructor
}
public FreeColGameObjectType(String id) {
this(id, null);
}
public FreeColGameObjectType(Specification specification) {
this(null, specification);
}
public FreeColGameObjectType(String id, Specification specification) {
setId(id);
setSpecification(specification);
featureContainer = new FeatureContainer();
}
/**
* Get the <code>FeatureContainer</code> value.
*
* @return a <code>FeatureContainer</code> value
*/
public final FeatureContainer getFeatureContainer() {
return featureContainer;
}
/**
* Set the <code>FeatureContainer</code> value.
*
* @param newFeatureContainer The new FeatureContainer value.
*/
public final void setFeatureContainer(final FeatureContainer newFeatureContainer) {
this.featureContainer = newFeatureContainer;
}
/**
* Describe <code>setIndex</code> method here.
*
* @param index an <code>int</code> value
*/
protected final void setIndex(final int index) {
this.index = index;
}
/**
* Returns the index of this FreeColGameObjectType. The index
* imposes a total ordering consistent with equals on each class
* extending FreeColGameObjectType, but this ordering is nothing
* but the order in which the objects of the respective class were
* defined. It is guaranteed to remain stable only for a
* particular revision of a particular specification.
*
* @return an <code>int</code> value
*/
protected int getIndex() {
return index;
}
public final String getNameKey() {
return getId() + ".name";
}
public final String getDescriptionKey() {
return getId() + ".description";
}
public boolean hasAbility(String id) {
return featureContainer.hasAbility(id);
}
public boolean hasAbility(String id, FreeColGameObjectType type) {
return featureContainer.hasAbility(id, type);
}
public void addAbility(Ability ability) {
featureContainer.addAbility(ability);
}
public void addModifier(Modifier modifier) {
featureContainer.addModifier(modifier);
}
public Set<Modifier> getModifierSet(String id) {
return featureContainer.getModifierSet(id);
}
/**
* Applies the difficulty level with the given ID to this
* FreeColGameObjectType. This method does nothing. If the
* behaviour of a FreeColGameObjectType depends on difficulty, it
* must override this method.
*
* @param difficulty difficulty level to apply
*/
public void applyDifficultyLevel(OptionGroup difficulty) {
// do nothing
}
/**
* Get the <code>ModifierIndex</code> value.
*
* @return an <code>int</code> value
*/
public final int getModifierIndex() {
return modifierIndex;
}
/**
* Get the index for the given Modifier.
*
* @param modifier a <code>Modifier</code> value
* @return an <code>int</code> value
*/
public int getModifierIndex(Modifier modifier) {
return modifierIndex;
}
/**
* Set the <code>ModifierIndex</code> value.
*
* @param newModifierIndex The new ModifierIndex value.
*/
public final void setModifierIndex(final int newModifierIndex) {
this.modifierIndex = newModifierIndex;
}
/**
* Get the <code>Abstract</code> value.
*
* @return a <code>boolean</code> value
*/
public final boolean isAbstractType() {
return abstractType;
}
/**
* Set the <code>Abstract</code> value.
*
* @param newAbstract The new Abstract value.
*/
public final void setAbstractType(final boolean newAbstract) {
this.abstractType = newAbstract;
}
protected void toXMLImpl(XMLStreamWriter out) throws XMLStreamException {
// don't use this
}
/**
* This method writes an XML-representation of this object to
* the given stream.
*
* @param out The target stream.
* @exception XMLStreamException if there are any problems writing
* to the stream.
*/
protected void toXMLImpl(XMLStreamWriter out, String tag)
throws XMLStreamException {
super.toXML(out, tag);
}
/**
* Write the children of this object to a stream.
*
* @param out The target stream.
* @throws XMLStreamException if there are any problems writing
* to the stream.
*/
@Override
protected void writeChildren(XMLStreamWriter out)
throws XMLStreamException {
super.writeChildren(out);
if (featureContainer != null) {
for (Ability ability: featureContainer.getAbilities()) {
ability.toXMLImpl(out);
}
for (Modifier modifier: featureContainer.getModifiers()) {
modifier.toXMLImpl(out);
}
}
}
/**
* Reads the attributes of this object from an XML stream.
*
* @param in The XML input stream.
* @throws XMLStreamException if a problem was encountered
* during parsing.
*/
@Override
protected void readAttributes(XMLStreamReader in)
throws XMLStreamException {
super.readAttributes(in);
setAbstractType(getAttribute(in, "abstract", false));
}
/**
* Reads the children of this object from an XML stream.
*
* @param in The XML input stream.
* @exception XMLStreamException if a problem was encountered
* during parsing.
*/
@Override
protected void readChildren(XMLStreamReader in) throws XMLStreamException {
while (in.nextTag() != XMLStreamConstants.END_ELEMENT) {
readChild(in);
}
}
/**
* Reads a common child object, i.e. an Ability or Modifier.
*
* @param in The XML input stream.
* @exception XMLStreamException if an error occurs
*/
protected void readChild(XMLStreamReader in) throws XMLStreamException {
String childName = in.getLocalName();
if (Ability.getXMLElementTagName().equals(childName)) {
if (getAttribute(in, "delete", false)) {
String id = in.getAttributeValue(null, ID_ATTRIBUTE_TAG);
featureContainer.removeAbilities(id);
in.nextTag();
} else {
Ability ability = new Ability(in, getSpecification());
if (ability.getSource() == null) {
ability.setSource(this);
}
addAbility(ability); // Ability close the element
getSpecification().addAbility(ability);
}
} else if (Modifier.getXMLElementTagName().equals(childName)) {
if (getAttribute(in, "delete", false)) {
String id = in.getAttributeValue(null, ID_ATTRIBUTE_TAG);
featureContainer.removeModifiers(id);
in.nextTag();
} else {
Modifier modifier = new Modifier(in, getSpecification());
if (modifier.getSource() == null) {
modifier.setSource(this);
}
if (modifier.getIndex() < 0) {
modifier.setIndex(getModifierIndex(modifier));
}
addModifier(modifier); // Modifier close the element
getSpecification().addModifier(modifier);
}
} else {
logger.warning("Parsing of " + childName
+ " is not implemented yet");
while (in.nextTag() != XMLStreamConstants.END_ELEMENT
|| !in.getLocalName().equals(childName)) {
in.nextTag();
}
}
}
/**
* Use only for debugging purposes! A human-readable and localized name is
* returned by getName().
*/
@Override
public String toString() {
return getId();
}
}