/*
* Copyright (c) 2008 Tom Parker <thpr@users.sourceforge.net>
*
* This program 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 program 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
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.cdom.list.DomainSpellList;
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;
/**
* @author djones4
*
*/
public class SpelllevelLst extends AbstractSpellListToken implements
CDOMPrimaryToken<CDOMObject>
{
@Override
public String getTokenName()
{
return "SPELLLEVEL";
}
@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);
}
// SPELLLEVEL:CLASS|Name1,Name2=Level1|Spell1,Spell2,Spell3|Name3=Level2|Spell4,Spell5|PRExxx|PRExxx
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 SPELLLEVEL tag: "
+ value, context);
}
String tagType = tok.nextToken(); // CLASS or DOMAIN
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 if (tagType.equalsIgnoreCase("DOMAIN"))
{
if (!subParse(context, obj, DomainSpellList.class, tokString,
spellString, prereqs))
{
return new ParseResult.Fail(" " + getTokenName()
+ " error - entire token was " + value, context);
}
}
else
{
return new ParseResult.Fail("First token of " + getTokenName()
+ " must be CLASS or DOMAIN:" + value, context);
}
}
return ParseResult.SUCCESS;
}
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 SPELLLEVEL " + "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 SPELLLEVEL, 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.addAllPrerequisites(prereqs);
}
}
return true;
}
@Override
public String[] unparse(LoadContext context, CDOMObject obj)
{
Set<String> set = new TreeSet<>();
Collection<CDOMReference<? extends CDOMList<?>>> changedDomainLists = context
.getListContext().getChangedLists(obj, DomainSpellList.class);
TripleKeyMapToList<String, Integer, CDOMReference<? extends CDOMList<?>>, CDOMReference<Spell>> domainMap =
getMap(context, obj, changedDomainLists, false);
for (String prereqs : domainMap.getKeySet())
{
set.add(processUnparse("DOMAIN", domainMap, prereqs).toString());
}
Collection<CDOMReference<? extends CDOMList<?>>> changedClassLists = context
.getListContext().getChangedLists(obj, ClassSpellList.class);
TripleKeyMapToList<String, Integer, CDOMReference<? extends CDOMList<?>>, CDOMReference<Spell>> classMap =
getMap(context, obj, changedClassLists, false);
for (String prereqs : classMap.getKeySet())
{
set.add(processUnparse("CLASS", classMap, prereqs).toString());
}
if (set.isEmpty())
{
return null;
}
return set.toArray(new String[set.size()]);
}
@Override
public Class<CDOMObject> getTokenClass()
{
return CDOMObject.class;
}
}