/* * Copyright (c) Thomas Parker, 2010. * * 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 pcgen.cdom.facet; import java.util.Collection; import java.util.List; import pcgen.base.util.HashMapToList; import pcgen.cdom.base.TransitionChoice; import pcgen.cdom.enumeration.CharID; import pcgen.cdom.facet.analysis.AgeSetFacet; import pcgen.cdom.facet.base.AbstractStorageFacet; import pcgen.cdom.facet.event.DataFacetChangeEvent; import pcgen.cdom.facet.event.DataFacetChangeListener; import pcgen.cdom.facet.fact.AgeFacet; import pcgen.cdom.facet.model.BioSetFacet; import pcgen.core.AgeSet; import pcgen.core.BioSet; import pcgen.core.Kit; import pcgen.core.PlayerCharacter; /** * AgeSetKitFacet stores * * @author Tom Parker (thpr [at] yahoo.com) */ public class AgeSetKitFacet extends AbstractStorageFacet<CharID> implements DataFacetChangeListener<CharID, Integer> { private final PlayerCharacterTrackingFacet trackingFacet = FacetLibrary .getFacet(PlayerCharacterTrackingFacet.class); private AgeFacet ageFacet; private AgeSetFacet ageSetFacet; private BioSetFacet bioSetFacet; /** * Drives the selection of the AgeSet Kit for a Player Character when * relevant changes (change to an AgeSet) are made to a Player Character. * * Triggered when one of the Facets to which AgeSetKitFacet listens fires a * DataFacetChangeEvent to indicate a CDOMObject was added to a Player * Character. * * @param dfce * The DataFacetChangeEvent containing the information about the * change * * @see pcgen.cdom.facet.event.DataFacetChangeListener#dataAdded(pcgen.cdom.facet.event.DataFacetChangeEvent) */ @Override public void dataAdded(DataFacetChangeEvent<CharID, Integer> dfce) { CharID id = dfce.getCharID(); AgeSet ageSet = ageSetFacet.get(id); PlayerCharacter pc = trackingFacet.getPC(id); // TODO Is ageSet null check necessary? if (ageSet == null || pc.isImporting()) { return; } int ageSetIndex = ageSetFacet.getAgeSetIndex(id); /* * TODO The method of storing what AgeSets have had kit selections made * should be converted to store the actual AgeSet rather than the index, * in order to reduce the number of calls to ageSetFacet.getAgeSetIndex. * This (of course) drives the move of the AgeSets for which a kit * selection has been made into a Facet. It is possible that the * CacheInfo of AgeSetKitFacet is actually a good place to store that * information (or it may be implicit with the information already * stored there??) */ if (!pc.hasMadeKitSelectionForAgeSet(ageSetIndex)) { CacheInfo cache = getConstructingClassInfo(id); List<Kit> kits = cache.get(ageSet); if (kits != null) { // Need to do selection BioSet bioSet = bioSetFacet.get(id); for (TransitionChoice<Kit> kit : ageSet.getKits()) { Collection<? extends Kit> choice = kit.driveChoice(pc); cache.put(ageSet, choice); kit.act(choice, bioSet, pc); } } pc.setHasMadeKitSelectionForAgeSet(ageSetIndex, true); } } /** * Triggered when one of the Facets to which AgeSetKitFacet listens fires a * DataFacetChangeEvent to indicate a CDOMObject was added to a Player * Character. * * @param dfce * The DataFacetChangeEvent containing the information about the * change * * @see pcgen.cdom.facet.event.DataFacetChangeListener#dataRemoved(pcgen.cdom.facet.event.DataFacetChangeEvent) */ @Override public void dataRemoved(DataFacetChangeEvent<CharID, Integer> dfce) { /* * CONSIDER Kits seem to be fire & forget - so nothing? Probably not, as * if the age is changed downward, it's likely that the kits from the * "older" ages should be removed... */ } /** * Returns the Cached Info for this AgeSetKitFacet and the given CharID. May * return null if no information has been set in this AgeSetKitFacet for the * given CharID. * * Note that this method SHOULD NOT be public. The CacheInfo is owned by * AgeSetKitFacet, and since it can be modified, a reference to that object * should not be exposed to any object other than AgeSetKitFacet. * * @param id * The CharID for which the CacheInfo should be returned * @return The CacheInfo for the Player Character represented by the given * CharID; null if no information has been set in this * AgeSetKitFacet for the Player Character. */ private CacheInfo getClassInfo(CharID id) { return (CacheInfo) getCache(id); } /** * Returns a non-null CacheInfo for this AgeSetKitFacet and the given * CharID. Will return a new, empty CacheInfo if no information has been set * in this AgeSetKitFacet for the given CharID. Will not return null. * * Note that this method SHOULD NOT be public. The CacheInfo object is owned * by AgeSetKitFacet, and since it can be modified, a reference to that * object should not be exposed to any object other than AgeSetKitFacet. * * @param id * The CharID for which the CacheInfo should be returned * @return The CacheInfo for the Player Character represented by the given * CharID. */ private CacheInfo getConstructingClassInfo(CharID id) { CacheInfo info = getClassInfo(id); if (info == null) { info = new CacheInfo(); setCache(id, info); } return info; } /** * CacheInfo is the data structure used to store information in * AgeSetKitFacet. This class should not be exposed outside of * AgeSetKitFacet. * * @author thpr (thpr [at] yahoo.com) */ private static class CacheInfo { private HashMapToList<AgeSet, Kit> kitMap = new HashMapToList<>(); public List<Kit> get(AgeSet ageSet) { return kitMap.getListFor(ageSet); } public void put(AgeSet ageSet, Collection<? extends Kit> choice) { kitMap.addAllToListFor(ageSet, choice); } } public void setAgeFacet(AgeFacet ageFacet) { this.ageFacet = ageFacet; } public void setAgeSetFacet(AgeSetFacet ageSetFacet) { this.ageSetFacet = ageSetFacet; } public void setBioSetFacet(BioSetFacet bioSetFacet) { this.bioSetFacet = bioSetFacet; } /** * Initializes the connections for AgeSetKitFacet to other facets. * * This method is automatically called by the Spring framework during * initialization of the AgeSetKitFacet. */ public void init() { ageFacet.addDataFacetChangeListener(this); } /** * Copies the contents of the AgeSetKitFacet from one Player Character to * another Player Character, based on the given CharIDs representing those * Player Characters. * * This is a method in AgeSetKitFacet in order to avoid exposing the mutable * Collection object to other classes. This should not be inlined, as the * Collection is internal information to AgeSetKitFacet and should not be * exposed to other classes. * * Note also the copy is a one-time event and no references are maintained * between the Player Characters represented by the given CharIDs (meaning * once this copy takes place, any change to the AgeSetKitFacet of one * Player Character will only impact the Player Character where the * AgeSetKitFacet was changed). * * @param source * The CharID representing the Player Character from which the * information should be copied * @param copy * The CharID representing the Player Character to which the * information should be copied */ @Override public void copyContents(CharID source, CharID copy) { CacheInfo ci = getClassInfo(source); if (ci != null) { CacheInfo copyci = getConstructingClassInfo(copy); copyci.kitMap.addAllLists(ci.kitMap); } } }