/* * 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.template; import java.util.Collection; import java.util.Set; import java.util.StringTokenizer; import java.util.TreeSet; import pcgen.cdom.base.Constants; import pcgen.cdom.enumeration.IntegerKey; import pcgen.cdom.enumeration.ListKey; import pcgen.core.PCTemplate; import pcgen.persistence.PersistenceLayerException; import pcgen.rules.context.Changes; import pcgen.rules.context.LoadContext; import pcgen.rules.persistence.token.AbstractTokenWithSeparator; import pcgen.rules.persistence.token.CDOMPrimaryToken; import pcgen.rules.persistence.token.ComplexParseResult; import pcgen.rules.persistence.token.ParseResult; /** * Class deals with REPEATLEVEL Token */ public class RepeatlevelToken extends AbstractTokenWithSeparator<PCTemplate> implements CDOMPrimaryToken<PCTemplate> { @Override public String getTokenName() { return "REPEATLEVEL"; } @Override protected char separator() { return '|'; } @Override protected ParseResult parseTokenWithSeparator(LoadContext context, PCTemplate template, String value) { ParseResult pr = checkForIllegalSeparator(':', value); if (!pr.passed()) { return pr; } // // x|y|z:level:<level assigned item> // int endRepeat = value.indexOf(Constants.COLON); if (endRepeat < 0) { return new ParseResult.Fail("Malformed " + getTokenName() + " Token (No Colon): " + value, context); } int endLevel = value.indexOf(Constants.COLON, endRepeat + 1); if (endLevel < 0) { return new ParseResult.Fail("Malformed " + getTokenName() + " Token (Only One Colon): " + value, context); } int endAssignType = value.indexOf(Constants.COLON, endLevel + 1); if (endAssignType == -1) { return new ParseResult.Fail("Malformed " + getTokenName() + " Token (Only Two Colons): " + value, context); } String repeatedInfo = value.substring(0, endRepeat); StringTokenizer repeatToken = new StringTokenizer(repeatedInfo, Constants.PIPE); if (repeatToken.countTokens() != 3) { return new ParseResult.Fail("Malformed " + getTokenName() + " Token (incorrect PIPE count in repeat): " + repeatedInfo, context); } String levelIncrement = repeatToken.nextToken(); int lvlIncrement; try { lvlIncrement = Integer.parseInt(levelIncrement); } catch (NumberFormatException nfe) { return new ParseResult.Fail("Malformed " + getTokenName() + " Token (Level Increment was not an Integer): " + levelIncrement, context); } if (lvlIncrement <= 0) { return new ParseResult.Fail("Malformed " + getTokenName() + " Token (Level Increment was <= 0): " + lvlIncrement, context); } String consecutiveString = repeatToken.nextToken(); int consecutive; try { consecutive = Integer.parseInt(consecutiveString); } catch (NumberFormatException nfe) { return new ParseResult.Fail("Malformed " + getTokenName() + " Token (Consecutive Value was not an Integer): " + consecutiveString, context); } if (consecutive < 0) { return new ParseResult.Fail("Malformed " + getTokenName() + " Token (Consecutive String was <= 0): " + consecutive, context); } String maxLevelString = repeatToken.nextToken(); int maxLevel; try { maxLevel = Integer.parseInt(maxLevelString); } catch (NumberFormatException nfe) { return new ParseResult.Fail("Malformed " + getTokenName() + " Token (Max Level was not an Integer): " + maxLevelString, context); } if (maxLevel <= 0) { return new ParseResult.Fail("Malformed " + getTokenName() + " Token (Max Level was <= 0): " + maxLevel, context); } String levelString = value.substring(endRepeat + 1, endLevel); int iLevel; try { iLevel = Integer.parseInt(levelString); } catch (NumberFormatException nfe) { return new ParseResult.Fail("Malformed " + getTokenName() + " Token (Level was not a number): " + levelString, context); } if (iLevel <= 0) { return new ParseResult.Fail("Malformed " + getTokenName() + " Token (Level was <= 0): " + iLevel, context); } if (iLevel > maxLevel) { return new ParseResult.Fail("Malformed " + getTokenName() + " Token (Starting Level was > Maximum Level)", context); } if (iLevel + lvlIncrement > maxLevel) { return new ParseResult.Fail("Malformed " + getTokenName() + " Token (Does not repeat, Staring Level + Increment > Maximum Level)", context); } if (consecutive != 0 && ((maxLevel - iLevel) / lvlIncrement) < consecutive) { ComplexParseResult cpr = new ComplexParseResult(); cpr.addErrorMessage("Malformed " + getTokenName() + " Token (Does not use Skip Interval value): " + consecutive); cpr.addErrorMessage(" You should set the interval to zero"); return cpr; } String typeStr = value.substring(endLevel + 1, endAssignType); String contentStr = value.substring(endAssignType + 1); /* * typeStr and contentStr can't be null due to hasIllegalSeparator check * on colon above */ PCTemplate consolidator = new PCTemplate(); consolidator.put(IntegerKey.CONSECUTIVE, consecutive); consolidator.put(IntegerKey.MAX_LEVEL, maxLevel); consolidator.put(IntegerKey.LEVEL_INCREMENT, lvlIncrement); consolidator.put(IntegerKey.START_LEVEL, iLevel); context.getObjectContext().addToList(template, ListKey.REPEATLEVEL_TEMPLATES, consolidator); context.getReferenceContext().getManufacturer(PCTemplate.class).addDerivativeObject(consolidator); for (int count = consecutive; iLevel <= maxLevel; iLevel += lvlIncrement) { if ((consecutive == 0) || (count != 0)) { PCTemplate derivative = new PCTemplate(); derivative.put(IntegerKey.LEVEL, count); context.getReferenceContext().getManufacturer(PCTemplate.class) .addDerivativeObject(derivative); context.getObjectContext().addToList(consolidator, ListKey.LEVEL_TEMPLATES, derivative); try { if (!context.processToken(derivative, typeStr, contentStr)) { return ParseResult.INTERNAL_ERROR; } } catch (PersistenceLayerException e) { return new ParseResult.Fail(e.getMessage(), context); } } if (consecutive != 0) { if (count == 0) { count = consecutive; } else { --count; } } } return ParseResult.SUCCESS; } @Override public String[] unparse(LoadContext context, PCTemplate pct) { Changes<PCTemplate> changes = context.getObjectContext() .getListChanges(pct, ListKey.REPEATLEVEL_TEMPLATES); Collection<PCTemplate> added = changes.getAdded(); if (added == null || added.isEmpty()) { return null; } Set<String> list = new TreeSet<>(); for (PCTemplate agg : added) { StringBuilder sb = new StringBuilder(); Integer consecutive = agg.get(IntegerKey.CONSECUTIVE); Integer maxLevel = agg.get(IntegerKey.MAX_LEVEL); Integer lvlIncrement = agg.get(IntegerKey.LEVEL_INCREMENT); Integer iLevel = agg.get(IntegerKey.START_LEVEL); sb.append(lvlIncrement).append(Constants.PIPE); sb.append(consecutive).append(Constants.PIPE); sb.append(maxLevel).append(Constants.COLON); sb.append(iLevel).append(Constants.COLON); Changes<PCTemplate> subchanges = context.getObjectContext() .getListChanges(agg, ListKey.LEVEL_TEMPLATES); Collection<PCTemplate> perAddCollection = subchanges.getAdded(); if (perAddCollection == null || perAddCollection.isEmpty()) { context.addWriteMessage("Invalid Consolidator built in " + getTokenName() + ": had no subTemplates"); return null; } PCTemplate next = perAddCollection.iterator().next(); Collection<String> unparse = context.unparse(next); if (unparse != null) { int masterLength = sb.length(); for (String str : unparse) { sb.setLength(masterLength); list.add(sb.append(str).toString()); } } } if (list.isEmpty()) { return null; } return list.toArray(new String[list.size()]); } @Override public Class<PCTemplate> getTokenClass() { return PCTemplate.class; } }