/*
* Prerequisite.java Copyright 2003 (C) Frugal <frugal@purplewombat.co.uk>
*
* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General
* Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library 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 Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Created on September 16, 2002, 3:30 PM
*
* Current Ver: $Revision$
*
*/
package pcgen.core.prereq;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
import pcgen.cdom.base.Constants;
import pcgen.system.LanguageBundle;
/**
* The Class {@code Prerequisite} is the storage format for all
* prerequisites. It is populated by a parser, written out by a writer
* and tested by a Tester class. Each kind of prerequisite will have
* one of each of these three classes that is responsible for managing
* its lifecycle.
*/
public class Prerequisite implements Cloneable
{
private static final String PERCENT_CHOICE_PATTERN = Pattern.quote(Constants.LST_PERCENT_CHOICE);
/** Kind to be used for a clear prerequisite request. */
public static final String APPLY_KIND = "APPLY";
private String kind;
private String key = null;
private String subKey = null;
private List<Prerequisite> prerequisites;
private PrerequisiteOperator operator = PrerequisiteOperator.GTEQ;
private String operand = "1"; //$NON-NLS-1$
/** Indicates that the total of skill ranks, class levels etc should be
* added together when checking for a value.
*/
private boolean totalValues;
/** Is a character required to test this prereq against?. */
private boolean characterRequired = true;
/** Indicates that the number of qualifying objects should be tallied when checking for a value. */
private boolean countMultiples;
private boolean overrideQualify = false;
/** Used for abilities only - the category to restrict matches to. */
private String categoryName;
/**
* Instantiates a new prerequisite.
*/
public Prerequisite()
{
// Empty Constructor
}
/**
* @return Returns the totalValues.
*/
public final boolean isTotalValues()
{
return totalValues;
}
/**
* Sets the totalValues attribute.
* @param val The value to set TotalValues to.
*/
public final void setTotalValues(final boolean val)
{
this.totalValues = val;
}
/**
* Sets the countMultiples attribute.
* @param val
* The value to set countMultiples to.
*/
public void setCountMultiples(final boolean val)
{
this.countMultiples = val;
}
/**
* @return Returns the countMultiples.
*/
public boolean isCountMultiples()
{
return countMultiples;
}
/**
* Set the key.
* @param val the Key to set.
*/
public void setKey(final String val)
{
this.key = val;
}
/**
* Get the key.
* @return the prerequisite's key.
*/
public String getKey()
{
return key;
}
/**
* Set the kind attribute.
* @param val
* The value to set kind to.
*/
public void setKind(final String val)
{
this.kind = val;
}
/**
* @return Returns the kind.
*/
public String getKind()
{
return kind;
}
/**
* Set the operand attribute.
* @param val
* The value to set the operand to.
*/
public void setOperand(final String val)
{
this.operand = val;
}
/**
* @return Returns the operand.
*/
public String getOperand()
{
return operand;
}
/**
* Sets an operator attribute from the name of the operator.
* @param operator
* The name of the operator to set in the object.
* @throws PrerequisiteException throws an exception if it can't locate the operator.
*/
public void setOperator(final String operator) throws PrerequisiteException
{
this.operator = PrerequisiteOperator.getOperatorByName(operator);
}
/**
* @param operator The operator to set.
*/
public void setOperator(final PrerequisiteOperator operator)
{
this.operator = operator;
}
/**
* @return Returns the operator.
*/
public PrerequisiteOperator getOperator()
{
return operator;
}
public void addPrerequisite(final Prerequisite prereq)
{
if (prerequisites == null)
{
prerequisites = new ArrayList<>();
}
prerequisites.add(prereq);
}
public List<Prerequisite> getPrerequisites()
{
if (prerequisites == null)
{
return Collections.emptyList();
}
return Collections.unmodifiableList(prerequisites);
}
/**
* @param subKey
* The subKey to set.
*/
public void setSubKey(final String subKey)
{
this.subKey = subKey;
}
/**
* @return Returns the subKey.
*/
public String getSubKey()
{
return subKey;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
final StringBuilder buf = new StringBuilder(250);
buf.append("<"); //$NON-NLS-1$
buf.append(LanguageBundle.getString("Prerequisite.prereq_tag")); //$NON-NLS-1$
buf.append(" "); //$NON-NLS-1$
if (kind != null)
{
buf.append(LanguageBundle.getString("Prerequisite.kind")); //$NON-NLS-1$
buf.append("=\""); //$NON-NLS-1$
buf.append(kind);
buf.append("\" "); //$NON-NLS-1$
}
if (countMultiples)
{
buf.append(LanguageBundle.getString("Prerequisite.count-multiples")); //$NON-NLS-1$
}
if (totalValues)
{
buf.append(LanguageBundle.getString("Prerequisite.total-values")); //$NON-NLS-1$
}
if (categoryName != null)
{
buf.append(LanguageBundle.getString("Prerequisite.category")); //$NON-NLS-1$
buf.append("=\""); //$NON-NLS-1$
buf.append(categoryName);
buf.append("\" "); //$NON-NLS-1$
}
if (key != null)
{
buf.append(LanguageBundle.getString("Prerequisite.key")); //$NON-NLS-1$
buf.append("=\""); //$NON-NLS-1$
buf.append(key);
buf.append("\" "); //$NON-NLS-1$
}
if ((subKey != null) && !subKey.equals("")) //$NON-NLS-1$
{
buf.append(LanguageBundle.getString("Prerequisite.sub-key")); //$NON-NLS-1$
buf.append("=\""); //$NON-NLS-1$
buf.append(subKey);
buf.append("\" "); //$NON-NLS-1$
}
buf.append(LanguageBundle.getString("Prerequisite.operator")); //$NON-NLS-1$
buf.append("=\""); //$NON-NLS-1$
buf.append(operator);
buf.append("\" "); //$NON-NLS-1$
if (operand != null)
{
buf.append(LanguageBundle.getString("Prerequisite.operand")); //$NON-NLS-1$
buf.append("=\""); //$NON-NLS-1$
buf.append(operand);
buf.append("\" "); //$NON-NLS-1$
}
if (isOverrideQualify())
{
buf.append(LanguageBundle.getString("Prerequisite.override-qualify")); //$NON-NLS-1$
}
buf.append(">\n"); //$NON-NLS-1$
if (prerequisites != null)
{
for ( Prerequisite prereq : prerequisites )
{
buf.append(prereq.toString());
}
}
buf.append("</"); //$NON-NLS-1$
buf.append(LanguageBundle.getString("Prerequisite.prereq_tag")); //$NON-NLS-1$
buf.append(">\n"); //$NON-NLS-1$
return buf.toString();
}
/**
* @return Returns the overrideQualify.
*/
public boolean isOverrideQualify()
{
return overrideQualify;
}
/**
* Setter for the overrideQualify field.
* @param override
* Whether to override the qualifications.
*/
public void setOverrideQualify(final boolean override)
{
this.overrideQualify = override;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#clone()
*/
@Override
public Prerequisite clone() throws CloneNotSupportedException
{
final Prerequisite copy = (Prerequisite) super.clone();
if (prerequisites != null)
{
copy.prerequisites = new ArrayList<>();
for ( Prerequisite subreq : prerequisites )
{
copy.prerequisites.add(subreq.clone());
}
}
return copy;
}
/**
* Retrieve the description of the prerequisite. This can either be
* in long form 'skill TUMBLE gteq 5' or in short form 'TUMBLE'.
*
* @param shortForm True if the abbreviated form should be used.
*
* @return The description of the prerequisite
*/
public String getDescription(final boolean shortForm)
{
final StringBuilder buf = new StringBuilder(250);
if (categoryName != null && !shortForm)
{
buf.append("of category ");
buf.append(categoryName);
buf.append(":");
buf.append(' '); //$NON-NLS-1$
}
if (kind != null && !shortForm)
{
buf.append(kind);
buf.append(' '); //$NON-NLS-1$
}
if (key != null)
{
buf.append(key);
if (!shortForm)
{
buf.append(' '); //$NON-NLS-1$
}
}
if ((subKey != null) && !subKey.equals("")) //$NON-NLS-1$
{
buf.append('('); //$NON-NLS-1$
buf.append(subKey);
buf.append(')'); //$NON-NLS-1$
if (!shortForm)
{
buf.append(' '); //$NON-NLS-1$
}
}
if (!shortForm)
{
buf.append(operator);
buf.append(' '); //$NON-NLS-1$
}
if (operand != null && !shortForm)
{
buf.append(operand);
}
if (prerequisites != null && !prerequisites.isEmpty() && !shortForm)
{
buf.append(" ("); //$NON-NLS-1$
for ( Prerequisite subreq : prerequisites )
{
buf.append(subreq.getDescription(shortForm));
}
buf.append(')'); //$NON-NLS-1$
}
return buf.toString();
}
/**
* @return the categoryName
*/
public String getCategoryName()
{
return categoryName;
}
/**
* @param categoryName the categoryName to set
*/
public void setCategoryName(String categoryName)
{
this.categoryName = categoryName;
}
@Override
public int hashCode()
{
return (kind == null ? -1 : kind.hashCode())
^ (key == null ? 0 : key.hashCode());
}
@Override
public boolean equals(Object o)
{
if (o == this)
{
return true;
}
if (!(o instanceof Prerequisite))
{
return false;
}
Prerequisite other = (Prerequisite) o;
if (kind == null)
{
if (other.kind != null)
{
return false;
}
}
if (key == null)
{
if (other.key != null)
{
return false;
}
}
if (subKey == null)
{
if (other.subKey != null)
{
return false;
}
}
if (categoryName == null)
{
if (other.categoryName != null)
{
return false;
}
}
boolean iHave = prerequisites != null && !prerequisites.isEmpty();
boolean otherHas =
other.prerequisites != null && !other.prerequisites.isEmpty();
if (iHave)
{
if (!otherHas)
{
return false;
}
List<Prerequisite> otherPRL = other.prerequisites;
if (otherPRL.size() != prerequisites.size())
{
return false;
}
ArrayList<Prerequisite> removed =
new ArrayList<>(prerequisites);
removed.removeAll(otherPRL);
if (!removed.isEmpty())
{
return false;
}
}
else if (otherHas)
{
return false;
}
return countMultiples == other.countMultiples
&& overrideQualify == other.overrideQualify
&& operator == other.operator
&& (kind == null || kind.equals(other.kind))
&& (key == null || key.equals(other.key))
&& (subKey == null || subKey.equals(other.subKey))
&& operand.equals(other.operand)
&& (categoryName == null || categoryName.equals(other.categoryName));
}
/**
* Checks if a character is required to test this prerequisite.
*
* @return true, if a character required
*/
public boolean isCharacterRequired()
{
return characterRequired;
}
/**
* Sets whether a character is required.
*
* @param characterRequired is a character required
*/
public void setCharacterRequired(boolean characterRequired)
{
this.characterRequired = characterRequired;
}
private boolean nativeCheckMult = false;
public void setOriginalCheckmult(boolean b)
{
nativeCheckMult = b;
}
public boolean isOriginalCheckMult()
{
return nativeCheckMult;
}
public Prerequisite specify(String assoc) throws CloneNotSupportedException
{
final Prerequisite copy = (Prerequisite) super.clone();
//PREMULT has no key or operand
if (copy.key != null)
{
copy.key = copy.key.replaceAll(PERCENT_CHOICE_PATTERN, assoc);
}
if (copy.operand != null)
{
copy.operand =
copy.operand.replaceAll(PERCENT_CHOICE_PATTERN, assoc);
}
if (prerequisites != null)
{
copy.prerequisites = new ArrayList<>();
for ( Prerequisite subreq : prerequisites )
{
copy.prerequisites.add(subreq.specify(assoc));
}
}
return copy;
}
public int getPrerequisiteCount()
{
return prerequisites == null ? 0 : prerequisites.size();
}
public void removePrerequisite(Prerequisite p)
{
if (prerequisites != null)
{
prerequisites.remove(p);
}
}
}