/**
* 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.lang.reflect.Method;
import org.freecolandroid.xml.stream.XMLStreamException;
import org.freecolandroid.xml.stream.XMLStreamReader;
import org.freecolandroid.xml.stream.XMLStreamWriter;
/**
* The <code>Scope</code> class determines whether a given
* <code>FreeColGameObjectType</code> fulfills certain requirements.
*/
public class Scope extends FreeColObject implements Cloneable {
/**
* The ID of a <code>FreeColGameObjectType</code>, or <code>Option</code>.
*/
private String type;
/**
* The ID of an <code>Ability</code>.
*/
private String abilityID;
/**
* The value of an <code>Ability</code>.
*/
private boolean abilityValue = true;
/**
* The name of an <code>Method</code>.
*/
private String methodName;
/**
* The <code>String</code> representation of the value of an
* <code>Method</code>.
*/
private String methodValue;
/**
* True if the scope applies to a null object.
*/
private boolean matchesNull = true;
/**
* Whether the match is negated.
*/
private boolean matchNegated = false;
/**
* Creates a new <code>Scope</code> instance.
*
*/
public Scope() {}
/**
* Creates a new <code>Scope</code> instance.
*
* @param in a <code>XMLStreamReader</code> value
* @exception XMLStreamException if an error occurs
*/
public Scope(XMLStreamReader in) throws XMLStreamException {
readFromXMLImpl(in);
}
/**
* Get the <code>MatchesNull</code> value.
*
* @return a <code>boolean</code> value
*/
public boolean isMatchesNull() {
return matchesNull;
}
/**
* Set the <code>MatchesNull</code> value.
*
* @param newMatchesNull The new MatchesNull value.
*/
public void setMatchesNull(final boolean newMatchesNull) {
this.matchesNull = newMatchesNull;
}
/**
* Get the <code>MatchNegated</code> value.
*
* @return a <code>boolean</code> value
*/
public boolean isMatchNegated() {
return matchNegated;
}
/**
* Set the <code>MatchNegated</code> value.
*
* @param newMatchNegated The new MatchNegated value.
*/
public void setMatchNegated(final boolean newMatchNegated) {
this.matchNegated = newMatchNegated;
}
/**
* Get the <code>Type</code> value.
*
* @return a <code>String</code> value
*/
public String getType() {
return type;
}
/**
* Set the <code>Type</code> value.
*
* @param newType The new Type value.
*/
public void setType(final String newType) {
this.type = newType;
}
/**
* Get the <code>AbilityID</code> value.
*
* @return a <code>String</code> value
*/
public String getAbilityID() {
return abilityID;
}
/**
* Set the <code>AbilityID</code> value.
*
* @param newAbilityID The new AbilityID value.
*/
public void setAbilityID(final String newAbilityID) {
this.abilityID = newAbilityID;
}
/**
* Get the <code>AbilityValue</code> value.
*
* @return a <code>boolean</code> value
*/
public boolean isAbilityValue() {
return abilityValue;
}
/**
* Set the <code>AbilityValue</code> value.
*
* @param newAbilityValue The new AbilityValue value.
*/
public void setAbilityValue(final boolean newAbilityValue) {
this.abilityValue = newAbilityValue;
}
/**
* Get the <code>MethodName</code> value.
*
* @return a <code>String</code> value
*/
public String getMethodName() {
return methodName;
}
/**
* Set the <code>MethodName</code> value.
*
* @param newMethodName The new MethodName value.
*/
public void setMethodName(final String newMethodName) {
this.methodName = newMethodName;
}
/**
* Get the <code>MethodValue</code> value.
*
* @return an <code>String</code> value
*/
public String getMethodValue() {
return methodValue;
}
/**
* Set the <code>MethodValue</code> value.
*
* @param newMethodValue The new MethodValue value.
*/
public void setMethodValue(final String newMethodValue) {
this.methodValue = newMethodValue;
}
/**
* Describe <code>appliesTo</code> method here.
*
* @param object a <code>FreeColGameObjectType</code> value
* @return a <code>boolean</code> value
*/
public boolean appliesTo(FreeColObject object) {
if (object == null) {
return matchesNull;
}
if (type != null) {
if (object instanceof FreeColGameObjectType) {
if (!type.equals(object.getId())) {
return matchNegated;
}
} else if (object instanceof FreeColGameObject) {
try {
Method method = object.getClass().getMethod("getType");
if (method != null
&& FreeColGameObjectType.class.isAssignableFrom(method.getReturnType())) {
FreeColGameObjectType objectType =
(FreeColGameObjectType) method.invoke(object);
if (!type.equals(objectType.getId())) {
return matchNegated;
}
} else {
return matchNegated;
}
} catch(Exception e) {
return matchNegated;
}
} else {
return matchNegated;
}
}
if (abilityID != null && object.hasAbility(abilityID) != abilityValue) {
return matchNegated;
}
if (methodName != null) {
try {
Method method = object.getClass().getMethod(methodName);
if (method != null
&& !String.valueOf(method.invoke(object)).equals(methodValue)) {
return matchNegated;
}
} catch(Exception e) {
return matchNegated;
}
}
return !matchNegated;
}
public int hashCode() {
int hash = 7;
hash += 31 * hash + (type == null ? 0 : type.hashCode());
hash += 31 * hash + (abilityID == null ? 0 : abilityID.hashCode());
hash += 31 * hash + (abilityValue ? 1 : 0);
hash += 31 * hash + (methodName == null ? 0 : methodName.hashCode());
hash += 31 * hash + (methodValue == null ? 0 : methodValue.hashCode());
hash += 31 * hash + (matchesNull ? 1 : 0);
hash += 31 * hash + (matchNegated ? 1 : 0);
return hash;
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (o instanceof Scope) {
Scope otherScope = (Scope) o;
if (matchNegated != otherScope.matchNegated) {
return false;
}
if (matchesNull != otherScope.matchesNull) {
return false;
}
if (type == null) {
if (otherScope.getType() != type) {
return false;
}
} else if (!type.equals(otherScope.getType())) {
return false;
}
if (abilityID == null) {
if (otherScope.getAbilityID() != abilityID) {
return false;
}
} else if (!abilityID.equals(otherScope.getAbilityID())) {
return false;
}
if (abilityValue != otherScope.isAbilityValue()) {
return false;
}
if (methodName == null) {
if (otherScope.getMethodName() != methodName) {
return false;
}
} else if (!methodName.equals(otherScope.getMethodName())) {
return false;
}
if (methodValue == null) {
if (otherScope.getMethodValue() != methodValue) {
return false;
}
} else if (!methodValue.equals(otherScope.getMethodValue())) {
return false;
}
return true;
} else {
return false;
}
}
/**
* 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.
*/
public void toXMLImpl(XMLStreamWriter out) throws XMLStreamException {
out.writeStartElement(getXMLElementTagName());
writeAttributes(out);
out.writeEndElement();
}
/**
* Write the attributes 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 writeAttributes(XMLStreamWriter out)
throws XMLStreamException {
out.writeAttribute("matchNegated", Boolean.toString(matchNegated));
out.writeAttribute("matchesNull", Boolean.toString(matchesNull));
if (type != null) {
out.writeAttribute("type", type);
}
if (abilityID != null) {
out.writeAttribute("ability-id", abilityID);
out.writeAttribute("ability-value", Boolean.toString(abilityValue));
}
if (methodName != null) {
out.writeAttribute("method-name", methodName);
// method value may be null in the Operand sub-class
if (methodValue != null) {
out.writeAttribute("method-value", methodValue);
}
}
}
/**
* 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 {
matchNegated = getAttribute(in, "matchNegated", false);
matchesNull = getAttribute(in, "matchesNull", true);
type = in.getAttributeValue(null, "type");
abilityID = in.getAttributeValue(null, "ability-id");
abilityValue = getAttribute(in, "ability-value", true);
methodName = in.getAttributeValue(null, "method-name");
methodValue = in.getAttributeValue(null, "method-value");
}
/**
* Gets the tag name of the root element representing this object.
*
* @return "scope".
*/
public static String getXMLElementTagName() {
return "scope";
}
}