/*
* AspectToken.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 16/08/2008 18:13:11
*
* $Id: $
*/
package plugin.lsttokens.ability;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;
import pcgen.cdom.base.Constants;
import pcgen.cdom.enumeration.AspectName;
import pcgen.cdom.enumeration.MapKey;
import pcgen.cdom.helper.Aspect;
import pcgen.core.Ability;
import pcgen.core.prereq.Prerequisite;
import pcgen.io.EntityEncoder;
import pcgen.persistence.lst.prereq.PreParserFactory;
import pcgen.rules.context.LoadContext;
import pcgen.rules.context.MapChanges;
import pcgen.rules.persistence.token.AbstractNonEmptyToken;
import pcgen.rules.persistence.token.CDOMPrimaryToken;
import pcgen.rules.persistence.token.ParseResult;
import pcgen.util.Logging;
/**
* The Class {@code AspectToken} parses a generic detail field for
* abilities. It is a name/value characteristic allowing substitution of values.
*
* <p>
* Variable substitution is performed by replacing a placeholder indicated by %#
* with the #th variable in the variable list. For example, the string <br>
* {@code "This is %1 variable %3 %2"} <br>
* would be replaced with the string "This is a variable substitution
* string" if the variable list was "a","string",
* "substitution".
*
*
* @author James Dempsey <jdempsey@users.sourceforge.net>
*/
public class AspectToken extends AbstractNonEmptyToken<Ability> implements
CDOMPrimaryToken<Ability>
{
/**
* @see pcgen.persistence.lst.LstToken#getTokenName()
*/
@Override
public String getTokenName()
{
return "ASPECT"; //$NON-NLS-1$
}
@Override
protected ParseResult parseNonEmptyToken(LoadContext context, Ability ability,
String value)
{
int pipeLoc = value.indexOf(Constants.PIPE);
if (pipeLoc == -1)
{
return new ParseResult.Fail(getTokenName()
+ " expecting '|', format is: "
+ "AspectName|Aspect value|Variable|... was: " + value, context);
}
String key = value.substring(0, pipeLoc);
if (key.isEmpty())
{
return new ParseResult.Fail(getTokenName()
+ " expecting non-empty type, "
+ "format is: AspectName|Aspect value|Variable|... was: "
+ value, context);
}
String val = value.substring(pipeLoc + 1);
if (val.isEmpty())
{
return new ParseResult.Fail(getTokenName()
+ " expecting non-empty value, "
+ "format is: AspectName|Aspect value|Variable|... was: "
+ value, context);
}
if (val.startsWith(Constants.PIPE))
{
return new ParseResult.Fail(getTokenName()
+ " expecting non-empty value, "
+ "format is: AspectName|Aspect value|Variable|... was: "
+ value, context);
}
Aspect a = parseAspect(key, val);
MapChanges<AspectName, List<Aspect>> mc =
context.getObjectContext().getMapChanges(ability, MapKey.ASPECT);
Map<AspectName, List<Aspect>> fullMap = mc.getAdded();
List<Aspect> aspects = fullMap.get(a.getKey());
if (aspects == null)
{
aspects = new ArrayList<>();
}
aspects.add(a);
context.getObjectContext().put(ability, MapKey.ASPECT, a.getKey(), aspects);
return ParseResult.SUCCESS;
}
/**
* Parses the ASPECT tag into a Aspect object.
*
* @param aspectDef
* The LST tag
* @return A <tt>Aspect</tt> object
*/
public Aspect parseAspect(final String name, final String aspectDef)
{
final StringTokenizer tok = new StringTokenizer(aspectDef,
Constants.PIPE);
String firstToken = tok.nextToken();
/*if (PreParserFactory.isPreReqString(firstToken))
{
Logging.errorPrint("Invalid " + getTokenName() + ": " + name);
Logging.errorPrint(" PRExxx can not be only value");
return null;
}*/
final Aspect aspect = new Aspect(name, EntityEncoder.decode(firstToken));
boolean isPre = false;
while (tok.hasMoreTokens())
{
final String token = tok.nextToken();
if (PreParserFactory.isPreReqString(token))
{
Prerequisite prereq = getPrerequisite(token);
if (prereq == null)
{
Logging.errorPrint(getTokenName()
+ " had invalid prerequisite : " + token);
return null;
}
aspect.addPrerequisite(prereq);
isPre = true;
}
else
{
if (isPre)
{
Logging.errorPrint("Invalid " + getTokenName() + ": "
+ name);
Logging
.errorPrint(" PRExxx must be at the END of the Token");
return null;
}
aspect.addVariable(token);
}
}
return aspect;
}
/*
* (non-Javadoc)
*
* @see pcgen.rules.persistence.token.CDOMPrimaryParserToken#unparse(pcgen.rules.context.LoadContext,
* java.lang.Object)
*/
@Override
public String[] unparse(LoadContext context, Ability ability)
{
MapChanges<AspectName, List<Aspect>> changes =
context.getObjectContext().getMapChanges(ability, MapKey.ASPECT);
if (changes == null || changes.isEmpty())
{
return null;
}
Set<String> set = new TreeSet<>();
Set<AspectName> keys = changes.getAdded().keySet();
for (AspectName an : keys)
{
List<Aspect> aspects = changes.getAdded().get(an);
for(int i = 0; i < aspects.size(); i++)
{
Aspect q = aspects.get(i);
set.add(new StringBuilder().append(q.getName()).append(Constants.PIPE)
.append(q.getPCCText()).toString());
}
}
return set.toArray(new String[set.size()]);
}
/*
* (non-Javadoc)
*
* @see pcgen.rules.persistence.token.CDOMToken#getTokenClass()
*/
@Override
public Class<Ability> getTokenClass()
{
return Ability.class;
}
}