/* * SpellknownLst.java * Copyright 2008 (C) James Dempsey * * 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 31/12/2008 12:35:22 PM * * $Id: $ */ package plugin.lsttokens; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Set; import java.util.StringTokenizer; import java.util.TreeSet; import pcgen.base.util.TripleKeyMapToList; import pcgen.cdom.base.AssociatedPrereqObject; import pcgen.cdom.base.CDOMList; import pcgen.cdom.base.CDOMObject; import pcgen.cdom.base.CDOMReference; import pcgen.cdom.base.Constants; import pcgen.cdom.base.Loadable; import pcgen.cdom.base.Ungranted; import pcgen.cdom.enumeration.AssociationKey; import pcgen.cdom.list.ClassSpellList; import pcgen.core.prereq.Prerequisite; import pcgen.core.spell.Spell; import pcgen.rules.context.LoadContext; import pcgen.rules.persistence.token.AbstractSpellListToken; import pcgen.rules.persistence.token.CDOMPrimaryToken; import pcgen.rules.persistence.token.ParseResult; import pcgen.util.Logging; /** * The Class {@code SpellknownLst} is responsible for parsing and * unparsing the SPELLKNOWN tag. This class is heavily based on the * SpelllevelLst class. <p> * Syntax is: * <pre> * SPELLKNOWN:CLASS|Name1,Name2=Level1|Spell1,Spell2,Spell3|Name3=Level2|Spell4,Spell5|PRExxx|PRExxx * </pre> * * * @author James Dempsey <jdempsey@users.sourceforge.net> */ public class SpellknownLst extends AbstractSpellListToken implements CDOMPrimaryToken<CDOMObject> { /* (non-Javadoc) * @see pcgen.rules.persistence.token.AbstractToken#getTokenName() */ @Override public String getTokenName() { return "SPELLKNOWN"; } @Override protected ParseResult parseTokenWithSeparator(LoadContext context, CDOMObject obj, String value) { if (obj instanceof Ungranted) { return new ParseResult.Fail("Cannot use " + getTokenName() + " on an Ungranted object type: " + obj.getClass().getSimpleName(), context); } String workingValue = value; List<Prerequisite> prereqs = new ArrayList<>(); while (true) { int lastPipeLoc = workingValue.lastIndexOf('|'); if (lastPipeLoc == -1) { return new ParseResult.Fail("Invalid " + getTokenName() + " not enough tokens: " + value, context); } String lastToken = workingValue.substring(lastPipeLoc + 1); if (looksLikeAPrerequisite(lastToken)) { workingValue = workingValue.substring(0, lastPipeLoc); Prerequisite prerequisite = getPrerequisite(lastToken); if (prerequisite == null) { return new ParseResult.Fail("Invalid prerequisite " + lastToken + " in " + getTokenName() + " tag: " + value, context); } prereqs.add(prerequisite); } else { break; } } StringTokenizer tok = new StringTokenizer(workingValue, Constants.PIPE); if (tok.countTokens() < 3) { return new ParseResult.Fail("Insufficient values in SPELLKNOWN tag: " + value, context); } String tagType = tok.nextToken(); // CLASS only while (tok.hasMoreTokens()) { String tokString = tok.nextToken(); String spellString = tok.nextToken(); if (tagType.equalsIgnoreCase("CLASS")) { if (!subParse(context, obj, ClassSpellList.class, tokString, spellString, prereqs)) { return ParseResult.INTERNAL_ERROR; //return new ParseResult.Fail(" " + getTokenName() // + " error - entire token was " + value, context); } } else { return new ParseResult.Fail("First token of " + getTokenName() + " must be CLASS: " + value, context); } } return ParseResult.SUCCESS; } /** * Parse the tag contents after the SPELLKNOWN:CLASS| section. * * @param context the context under which the tag is being parsed. * @param obj the obj The object owning the tag. * @param tagType the type of object the tag creates * @param tokString the tok string The string defining the caster type/class and spell level. * @param spellString the spell string The string containing the spell name(s) * @param prereqs the prereqs The prerequisites to be applied. * * @return true, if successful */ private <CL extends Loadable & CDOMList<Spell>> boolean subParse( LoadContext context, CDOMObject obj, Class<CL> tagType, String tokString, String spellString, List<Prerequisite> prereqs) { int equalLoc = tokString.indexOf(Constants.EQUALS); if (equalLoc == -1) { Logging.errorPrint("Expected an = in SPELLKNOWN " + "definition: " + tokString); return false; } String casterString = tokString.substring(0, equalLoc); String spellLevel = tokString.substring(equalLoc + 1); Integer splLevel; try { splLevel = Integer.decode(spellLevel); } catch (NumberFormatException nfe) { Logging.errorPrint("Expected a number for SPELLKNOWN, found: " + spellLevel); return false; } if (isEmpty(casterString) || hasIllegalSeparator(',', casterString)) { return false; } StringTokenizer clTok = new StringTokenizer(casterString, Constants.COMMA); List<CDOMReference<? extends CDOMList<Spell>>> slList = new ArrayList<>(); while (clTok.hasMoreTokens()) { String classString = clTok.nextToken(); CDOMReference<CL> ref; if (classString.startsWith("SPELLCASTER.")) { /* * This is actually a TYPE */ ref = context.getReferenceContext().getCDOMTypeReference(tagType, classString .substring(12)); } else { ref = context.getReferenceContext().getCDOMReference(tagType, classString); } slList.add(ref); } if (hasIllegalSeparator(',', spellString)) { return false; } StringTokenizer spTok = new StringTokenizer(spellString, ","); while (spTok.hasMoreTokens()) { String spellName = spTok.nextToken(); CDOMReference<Spell> sp = context.getReferenceContext().getCDOMReference(Spell.class, spellName); for (CDOMReference<? extends CDOMList<Spell>> sl : slList) { AssociatedPrereqObject tpr = context.getListContext() .addToList(getTokenName(), obj, sl, sp); tpr.setAssociation(AssociationKey.SPELL_LEVEL, splLevel); tpr.setAssociation(AssociationKey.KNOWN, Boolean.TRUE); tpr.addAllPrerequisites(prereqs); } } return true; } /* (non-Javadoc) * @see pcgen.rules.persistence.token.CDOMPrimaryToken#unparse(pcgen.rules.context.LoadContext, java.lang.Object) */ @Override public String[] unparse(LoadContext context, CDOMObject obj) { Set<String> set = new TreeSet<>(); Collection<CDOMReference<? extends CDOMList<?>>> changedClassLists = context .getListContext().getChangedLists(obj, ClassSpellList.class); TripleKeyMapToList<String, Integer, CDOMReference<? extends CDOMList<?>>, CDOMReference<Spell>> classMap = getMap(context, obj, changedClassLists, true); for (String prereqs : classMap.getKeySet()) { set.add(processUnparse("CLASS", classMap, prereqs).toString()); } if (set.isEmpty()) { return null; } return set.toArray(new String[set.size()]); } /* (non-Javadoc) * @see pcgen.rules.persistence.token.CDOMToken#getTokenClass() */ @Override public Class<CDOMObject> getTokenClass() { return CDOMObject.class; } }