/*
* Copyright 2010 (C) Thomas Parker <thpr@users.sourceforge.net>
*
* 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
*/
package pcgen.rules.persistence.token;
import java.util.Collection;
import java.util.List;
import java.util.StringTokenizer;
import pcgen.base.formula.Formula;
import pcgen.cdom.base.CDOMList;
import pcgen.cdom.base.CDOMReference;
import pcgen.cdom.base.Converter;
import pcgen.cdom.base.FormulaFactory;
import pcgen.cdom.base.PrimitiveFilter;
import pcgen.core.Globals;
import pcgen.core.PCClass;
import pcgen.core.PlayerCharacter;
import pcgen.core.character.CharacterSpell;
import pcgen.core.spell.Spell;
import pcgen.rules.context.LoadContext;
import pcgen.util.Logging;
public abstract class AbstractRestrictedSpellPrimitive implements
PrimitiveToken<Spell>, PrimitiveFilter<Spell>
{
private static final Class<Spell> SPELL_CLASS = Spell.class;
private Restriction restriction;
private CDOMReference<Spell> allSpells;
public boolean initialize(LoadContext context, String args)
{
allSpells = context.getReferenceContext().getCDOMAllReference(SPELL_CLASS);
if (args != null)
{
restriction = getRestriction(args);
return restriction != null;
}
return true;
}
private Restriction getRestriction(String restrString)
{
StringTokenizer restr = new StringTokenizer(restrString, ";");
Formula levelMax = null;
Formula levelMin = null;
Boolean known = null;
while (restr.hasMoreTokens())
{
String tok = restr.nextToken();
if (tok.startsWith("LEVELMAX="))
{
levelMax = FormulaFactory.getFormulaFor(tok.substring(9));
if (!levelMax.isValid())
{
Logging.errorPrint("LEVELMAX Formula in " + getTokenName()
+ " was not valid: " + levelMax.toString());
return null;
}
}
else if (tok.startsWith("LEVELMIN="))
{
levelMin = FormulaFactory.getFormulaFor(tok.substring(9));
if (!levelMin.isValid())
{
Logging.errorPrint("LEVELMIN Formula in " + getTokenName()
+ " was not valid: " + levelMin.toString());
return null;
}
}
else if ("KNOWN=YES".equals(tok))
{
known = Boolean.TRUE;
}
else if ("KNOWN=NO".equals(tok))
{
known = Boolean.FALSE;
}
else
{
Logging.errorPrint("Unknown restriction: " + tok
+ " in CHOOSE:SPELLS");
return null;
}
}
return new Restriction(levelMin, levelMax, known);
}
private static class Restriction
{
public final Formula minLevel;
public final Formula maxLevel;
public final Boolean knownRequired;
public Restriction(Formula levelMin, Formula levelMax, Boolean known)
{
minLevel = levelMin;
maxLevel = levelMax;
knownRequired = known;
}
public String getLSTformat()
{
StringBuilder sb = new StringBuilder();
if (knownRequired != null)
{
sb.append("KNOWN=");
sb.append(knownRequired.booleanValue() ? "YES" : "NO");
}
if (maxLevel != null)
{
if (sb.length() > 0)
{
sb.append(';');
}
sb.append("LEVELMAX=");
sb.append(maxLevel);
}
if (minLevel != null)
{
if (sb.length() > 0)
{
sb.append(';');
}
sb.append("LEVELMIN=");
sb.append(minLevel);
}
return sb.toString();
}
@Override
public int hashCode()
{
int prime = 31;
int result = 1;
result =
prime
* result
+ ((knownRequired == null) ? 0 : knownRequired
.hashCode());
result =
prime * result
+ ((maxLevel == null) ? 0 : maxLevel.hashCode());
result =
prime * result
+ ((minLevel == null) ? 0 : minLevel.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
Restriction other = (Restriction) obj;
if (knownRequired == null)
{
if (other.knownRequired != null)
{
return false;
}
}
else if (!knownRequired.equals(other.knownRequired))
{
return false;
}
if (maxLevel == null)
{
if (other.maxLevel != null)
{
return false;
}
}
else if (!maxLevel.equals(other.maxLevel))
{
return false;
}
if (minLevel == null)
{
if (other.minLevel != null)
{
return false;
}
}
else if (!minLevel.equals(other.minLevel))
{
return false;
}
return true;
}
}
@Override
public Class<Spell> getReferenceClass()
{
return SPELL_CLASS;
}
@Override
public String getLSTformat(boolean useAny)
{
StringBuilder sb = new StringBuilder();
sb.append(getPrimitiveLST());
return sb.toString();
}
public abstract CharSequence getPrimitiveLST();
public boolean allow(PlayerCharacter pc, int level, String source,
Spell spell, CDOMList<Spell> optionalList)
{
if (restriction != null)
{
Formula maxLevel = restriction.maxLevel;
if (maxLevel != null
&& (level > maxLevel.resolve(pc, source).intValue()))
{
return false;
}
Formula minLevel = restriction.minLevel;
if (minLevel != null
&& (level < minLevel.resolve(pc, source).intValue()))
{
return false;
}
if (restriction.knownRequired != null)
{
String defaultbook = Globals.getDefaultSpellBook();
boolean known = restriction.knownRequired.booleanValue();
boolean found = false;
for (PCClass cl : pc.getClassSet())
{
if (optionalList != null)
{
/*
* This may not be a precise test of intent, but given
* the weirdness we have on lists and the use of
* SPELLLIST tag in data to share lists between classes,
* this is probably the closest we can get
*/
if (!pc.hasSpellList(cl, optionalList))
{
continue;
}
}
List<CharacterSpell> csl = pc.getCharacterSpells(cl, spell,
defaultbook, -1);
if (csl != null && !csl.isEmpty())
{
/*
* Going to assume here that the level doesn't need to
* be rechecked... ?? - thpr Feb 26, 08
*/
found = true;
}
}
if (found != known)
{
return false;
}
}
}
return true;
}
public boolean equalsRestrictedPrimitive(
AbstractRestrictedSpellPrimitive other)
{
if (other == this)
{
return true;
}
if (restriction == null)
{
return other.restriction == null;
}
return restriction.equals(other.restriction);
}
public boolean hasRestriction()
{
return restriction != null;
}
public String getRestrictionLST()
{
return restriction == null ? ""
: ('[' + restriction.getLSTformat() + ']');
}
@Override
public <R> Collection<? extends R> getCollection(PlayerCharacter pc,
Converter<Spell, R> c)
{
return c.convert(allSpells, this);
}
}