/*
* AbilityListToken.java
* Copyright 2006 (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 21/11/2006
*
* $Id$
*/
package pcgen.io.exporttoken;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.StringTokenizer;
import pcgen.base.util.HashMapToList;
import pcgen.base.util.MapToList;
import pcgen.cdom.content.CNAbility;
import pcgen.cdom.enumeration.Nature;
import pcgen.core.Ability;
import pcgen.core.AbilityCategory;
import pcgen.core.PlayerCharacter;
import pcgen.core.SettingsHandler;
import pcgen.core.analysis.QualifiedName;
import pcgen.io.ExportHandler;
import pcgen.util.enumeration.View;
/**
* {@code AbilityListToken} handles the output of a comma separated
* list of ability information.
*
* The format is ABILITYLIST.y.z where
* y is the category (FEAT, FIGHTER etc, or ALL)
* z is an option list of {@literal TYPE=<type>} - type filter - may be negated
*
*
* @author James Dempsey <jdempsey@users.sourceforge.net>
*/
public class AbilityListToken extends Token
{
private static final String DELIM = ", ";
//TODO: Should these be static to enable the caching?
private MapToList<Ability, CNAbility> abilityMap = null;
private PlayerCharacter lastPC = null;
private int lastPCSerial;
private String lastType = "";
private AbilityCategory lastCategory = null;
/** Token Name */
public static final String TOKENNAME = "ABILITYLIST";
/**
* Get the TOKENNAME
* @return TOKENNAME
*/
@Override
public String getTokenName()
{
return TOKENNAME;
}
/**
* @see pcgen.io.exporttoken.Token#getToken(java.lang.String, pcgen.core.PlayerCharacter, pcgen.io.ExportHandler)
*/
@Override
public String getToken(String tokenSource, PlayerCharacter pc,
ExportHandler eh)
{
final StringTokenizer aTok = new StringTokenizer(tokenSource, ".");
// Skip the ABILITYLIST token itself
final String tokenString = aTok.nextToken();
final String catString = aTok.nextToken();
final AbilityCategory aCategory =
SettingsHandler.getGame().getAbilityCategory(catString);
return getTokenForCategory(pc, aTok, tokenString, aCategory);
}
/**
* Produce the ABILITY token output for a specific ability
* category.
*
* @param pc The character being processed.
* @param aTok The tokenised request, already past the category.
* @param tokenString The output token requested
* @param aCategory The ability category being output.
* @return The token value.
*/
protected String getTokenForCategory(PlayerCharacter pc,
final StringTokenizer aTok, final String tokenString,
final AbilityCategory aCategory)
{
if (aCategory == null)
{
return "";
}
StringBuilder retString = new StringBuilder();
// If we haven't cached some of the processign data, then do so, this is so that
// if the Output Sheet loops over this token we don't process one-off stuff more than
// once
if (lastPC != pc || !aCategory.equals(lastCategory)
|| lastPCSerial != pc.getSerial() || !tokenString.equals(lastType))
{
abilityMap = getAbilityList(pc, aCategory);
lastPC = pc;
lastCategory = aCategory;
lastPCSerial = pc.getSerial();
lastType = tokenString;
}
// Default values
List<String> types = new ArrayList<>();
List<String> negate = new ArrayList<>();
String aspect = null;
while (aTok.hasMoreTokens())
{
final String typeStr = aTok.nextToken();
int typeInd = typeStr.indexOf("TYPE=");
if (typeInd != -1 && typeStr.length() > 5)
{
if (typeInd > 0)
{
negate.add(typeStr.substring(typeInd + 5));
}
else
{
types.add(typeStr.substring(typeInd + 5));
}
}
int aspectInd = typeStr.indexOf("ASPECT=");
if (aspectInd != -1 && typeStr.length() > 7)
{
aspect = typeStr.substring(aspectInd + 7);
}
}
MapToList<Ability, CNAbility> aList =
AbilityToken.buildAbilityList(types, negate, null,
View.VISIBLE_EXPORT, aspect, abilityMap);
boolean needComma = false;
for (Ability ability : aList.getKeySet())
{
if (needComma)
{
retString.append(DELIM);
}
needComma = true;
retString.append(QualifiedName.qualifiedName(pc, aList.getListFor(ability)));
}
return retString.toString();
}
/**
* Returns the correct list of abilities of a particular category for the character.
* This method is overridden in subclasses if they need to change the list
* of abilities looked at.
*
* @param pc the character who's feats we are retrieving.
* @param aCategory The category of ability required.
* @return List of feats.
*/
protected MapToList<Ability, CNAbility> getAbilityList(PlayerCharacter pc,
final AbilityCategory aCategory)
{
final MapToList<Ability, CNAbility> listOfAbilities = new HashMapToList<>();
Collection<AbilityCategory> allCats =
SettingsHandler.getGame().getAllAbilityCategories();
for (AbilityCategory aCat : allCats)
{
if (AbilityCategory.ANY.equals(aCategory) || aCat.getParentCategory().equals(aCategory))
{
for (CNAbility cna : pc.getPoolAbilities(aCat, Nature.NORMAL))
{
listOfAbilities.addToListFor(cna.getAbility(), cna);
}
}
}
return listOfAbilities;
}
}