/*
* Copyright 2013 (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
*/
package plugin.lsttokens;
import java.util.TreeSet;
import org.apache.commons.lang3.StringUtils;
import pcgen.base.formula.Formula;
import pcgen.base.text.ParsingSeparator;
import pcgen.cdom.base.CDOMObject;
import pcgen.cdom.base.Constants;
import pcgen.cdom.base.FormulaFactory;
import pcgen.cdom.base.Ungranted;
import pcgen.cdom.enumeration.ListKey;
import pcgen.cdom.helper.StatLock;
import pcgen.cdom.reference.CDOMSingleRef;
import pcgen.core.PCStat;
import pcgen.rules.context.Changes;
import pcgen.rules.context.LoadContext;
import pcgen.rules.persistence.token.CDOMPrimaryToken;
import pcgen.rules.persistence.token.ParseResult;
/**
* The Class {@code DefineStatLst} parses the DEFINESTAT tag. Valid sub tags are:
* <p>
* DEFINESTAT:LOCK|stat|value <br>
* DEFINESTAT:UNLOCK|stat <br>
* DEFINESTAT:NONSTAT|stat <br>
* DEFINESTAT:STAT|stat <br>
* DEFINESTAT:MINVALUE|stat|value
*
* <br>
*
* @author James Dempsey <jdempsey@users.sourceforge.net>
*/
public class DefineStatLst implements CDOMPrimaryToken<CDOMObject>
{
private static final Class<PCStat> PCSTAT_CLASS = PCStat.class;
public enum DefineStatSubToken
{
LOCK, UNLOCK, NONSTAT, STAT, MINVALUE, MAXVALUE;
}
@Override
public String getTokenName()
{
return "DEFINESTAT";
}
@Override
public ParseResult parseToken(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);
}
ParsingSeparator sep = new ParsingSeparator(value, '|');
sep.addGroupingPair('[', ']');
sep.addGroupingPair('(', ')');
if (!sep.hasNext())
{
return new ParseResult.Fail(getTokenName() + " may not be empty", context);
}
String firstItem = sep.next();
DefineStatSubToken subToken;
try
{
subToken = DefineStatSubToken.valueOf(firstItem);
}
catch (IllegalArgumentException e1)
{
return new ParseResult.Fail("Found unexpected sub tag " + firstItem + " in "
+ getTokenName() + Constants.COLON + value + ". Must be one of "
+ StringUtils.join(DefineStatSubToken.values(), ", ") + Constants.DOT,
context);
}
if (!sep.hasNext())
{
return new ParseResult.Fail(getTokenName()
+ Constants.COLON+subToken+"| must be followed by a stat.", context);
}
String statKey = sep.next();
CDOMSingleRef<PCStat> stat =
context.getReferenceContext().getCDOMReference(PCSTAT_CLASS,
statKey);
Formula f = null;
if (subToken == DefineStatSubToken.LOCK
|| subToken == DefineStatSubToken.MINVALUE
|| subToken == DefineStatSubToken.MAXVALUE)
{
if (!sep.hasNext())
{
return new ParseResult.Fail(getTokenName() + Constants.COLON + subToken
+ "| must be followed by both a stat and a value.", context);
}
String formula = sep.next();
f = FormulaFactory.getFormulaFor(formula);
if (!f.isValid())
{
return new ParseResult.Fail("Formula in " + getTokenName()
+ " was not valid: " + f.toString(), context);
}
}
if (sep.hasNext())
{
return new ParseResult.Fail(getTokenName() + Constants.COLON + value
+ " has too many pipe separated item.", context);
}
switch (subToken)
{
case LOCK:
context.getObjectContext().addToList(obj, ListKey.STAT_LOCKS,
new StatLock(stat, f));
break;
case UNLOCK:
context.getObjectContext().addToList(obj, ListKey.UNLOCKED_STATS, stat);
break;
case NONSTAT:
context.getObjectContext().addToList(obj, ListKey.NONSTAT_STATS, stat);
break;
case STAT:
context.getObjectContext().addToList(obj, ListKey.NONSTAT_TO_STAT_STATS, stat);
break;
case MINVALUE:
context.getObjectContext().addToList(obj, ListKey.STAT_MINVALUE,
new StatLock(stat, f));
break;
case MAXVALUE:
context.getObjectContext().addToList(obj, ListKey.STAT_MAXVALUE,
new StatLock(stat, f));
break;
}
return ParseResult.SUCCESS;
}
@Override
public String[] unparse(LoadContext context, CDOMObject obj)
{
Changes<StatLock> lockChanges = context.getObjectContext().getListChanges(
obj, ListKey.STAT_LOCKS);
Changes<CDOMSingleRef<PCStat>> ulchanges = context.getObjectContext().getListChanges(
obj, ListKey.UNLOCKED_STATS);
Changes<CDOMSingleRef<PCStat>> nonStatChanges = context.getObjectContext().getListChanges(
obj, ListKey.NONSTAT_STATS);
Changes<CDOMSingleRef<PCStat>> nonStatToStatChanges = context.getObjectContext().getListChanges(
obj, ListKey.NONSTAT_TO_STAT_STATS);
Changes<StatLock> minValueChanges = context.getObjectContext().getListChanges(
obj, ListKey.STAT_MINVALUE);
Changes<StatLock> maxValueChanges = context.getObjectContext().getListChanges(
obj, ListKey.STAT_MAXVALUE);
TreeSet<String> set = new TreeSet<>();
if (lockChanges != null && !lockChanges.isEmpty())
{
if (lockChanges.includesGlobalClear())
{
context.addWriteMessage("DEFINE:LOCK does not support .CLEAR");
return null;
}
if (lockChanges.hasAddedItems())
{
for (StatLock sl : lockChanges.getAdded())
{
set.add("LOCK|" + sl.getLSTformat() + Constants.PIPE
+ sl.getLockValue());
}
}
}
if (ulchanges != null && !ulchanges.isEmpty())
{
if (ulchanges.includesGlobalClear())
{
context.addWriteMessage("DEFINE:UNLOCK "
+ "does not support .CLEAR");
return null;
}
if (ulchanges.hasAddedItems())
{
for (CDOMSingleRef<PCStat> st : ulchanges.getAdded())
{
set.add("UNLOCK|" + st.getLSTformat(false));
}
}
}
if (nonStatChanges != null && !nonStatChanges.isEmpty())
{
if (nonStatChanges.hasAddedItems())
{
for (CDOMSingleRef<PCStat> st : nonStatChanges.getAdded())
{
set.add("NONSTAT|" + st.getLSTformat(false));
}
}
}
if (nonStatToStatChanges != null && !nonStatToStatChanges.isEmpty())
{
if (nonStatToStatChanges.hasAddedItems())
{
for (CDOMSingleRef<PCStat> st : nonStatToStatChanges.getAdded())
{
set.add("STAT|" + st.getLSTformat(false));
}
}
}
if (minValueChanges != null && !minValueChanges.isEmpty())
{
if (minValueChanges.hasAddedItems())
{
for (StatLock sl : minValueChanges.getAdded())
{
set.add("MINVALUE|" + sl.getLSTformat() + Constants.PIPE
+ sl.getLockValue());
}
}
}
if (maxValueChanges != null && !maxValueChanges.isEmpty())
{
if (maxValueChanges.hasAddedItems())
{
for (StatLock sl : maxValueChanges.getAdded())
{
set.add("MAXVALUE|" + sl.getLSTformat() + Constants.PIPE
+ sl.getLockValue());
}
}
}
if (set.isEmpty())
{
return null;
}
return set.toArray(new String[set.size()]);
}
@Override
public Class<CDOMObject> getTokenClass()
{
return CDOMObject.class;
}
}