/* * Copyright (c) Thomas Parker, 2009. * * 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.Collections; import java.util.LinkedHashMap; import java.util.Map; import pcgen.cdom.base.Constants; import pcgen.cdom.enumeration.CharID; import pcgen.cdom.facet.base.AbstractStorageFacet; import pcgen.cdom.facet.event.DataFacetChangeEvent; import pcgen.cdom.facet.event.DataFacetChangeListener; import pcgen.core.Equipment; import pcgen.core.character.SpellBook; /** * SpellBookFacet is a Facet that tracks the SpellBooks possessed by a Player * Character. * * @author Thomas Parker (thpr [at] yahoo.com) */ public class SpellBookFacet extends AbstractStorageFacet<CharID> implements DataFacetChangeListener<CharID, Equipment> { private EquipmentFacet equipmentFacet; /** * Adds a SpellBook to this facet if the Equipment added to a Player * Character was a SpellBook. * * Triggered when one of the Facets to which SpellBookFacet listens fires a * DataFacetChangeEvent to indicate a piece of Equipment 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, Equipment> dfce) { Equipment eq = dfce.getCDOMObject(); if (eq.isType(Constants.TYPE_SPELLBOOK)) { CharID id = dfce.getCharID(); String baseBookname = eq.getName(); String bookName = eq.getName(); int qty = (int) eq.qty(); for (int i = 0; i < qty; i++) { if (i > 0) { bookName = baseBookname + " #" + (i + 1); } SpellBook book = getBookNamed(id, bookName); if (book == null) { book = new SpellBook(bookName, SpellBook.TYPE_SPELL_BOOK); } book.setEquip(eq); if (!containsBookNamed(id, book.getName())) { add(id, book); } } } } /** * Triggered when one of the Facets to which SpellBookFacet listens fires a * DataFacetChangeEvent to indicate a piece of Equipment was removed from 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, Equipment> dfce) { //Ignore - for now this is one in PlayerCharacter... /* * TODO This method should eventually be symmetric with dataAdded */ } /** * Adds all of the SpellBooks in the given Collection to the list of * SpellBooks stored in this SpellBookFacet for the Player Character * represented by the given CharID. * * @param id * The CharID representing the Player Character for which the * given SpellBooks should be added * @param list * The Collection of SpellBooks to be added to the list of * SpellBooks stored in this SpellBookFacet for the Player * Character represented by the given CharID * @throws NullPointerException * if the given Collection is null */ public void addAll(CharID id, Collection<SpellBook> list) { for (SpellBook sb : list) { add(id, sb); } } /** * Add the given SpellBook to the list of SpellBooks stored in this * SpellBookFacet for the Player Character represented by the given CharID. * * @param id * The CharID representing the Player Character for which the * given item should be added * @param sb * The SpellBook to be added to the list of SpellBooks stored in * this SpellBookFacet for the Player Character represented by * the given CharID */ public void add(CharID id, SpellBook sb) { if (sb == null) { throw new IllegalArgumentException("Object to add may not be null"); } Map<String, SpellBook> sbMap = getConstructingCachedMap(id); String name = sb.getName(); sbMap.put(name, sb); } /** * Removes all of the SpellBooks in the given Collection from the list of * SpellBooks stored in this SpellBookFacet for the Player Character * represented by the given CharID. * * @param id * The CharID representing the Player Character from which the * given SpellBooks should be removed * @throws NullPointerException * if the given Collection is null */ public void removeAll(CharID id) { removeCache(id); } /** * Returns the type-safe Map for this SpellBookFacet and the given CharID. * May return null if no information has been set in this SpellBookFacet for * the given CharID. * * Note that this method SHOULD NOT be public. The Map is owned by * SpellBookFacet, and since it can be modified, a reference to that object * should not be exposed to any object other than SpellBookFacet. * * @param id * The CharID for which the Set should be returned * @return The Set for the Player Character represented by the given CharID; * null if no information has been set in this * AbstractSourcedListFacet for the Player Character. */ private Map<String, SpellBook> getCachedMap(CharID id) { return (Map<String, SpellBook>) getCache(id); } /** * Returns a type-safe Map for this SpellBookFacet and the given CharID. * Will return a new, empty Map if no information has been set in this * SpellBookFacet for the given CharID. Will not return null. * * Note that this method SHOULD NOT be public. The Map object is owned by * SpellBookFacet, and since it can be modified, a reference to that object * should not be exposed to any object other than SpellBookFacet. * * @param id * The CharID for which the Map should be returned * @return The Map for the Player Character represented by the given CharID. */ private Map<String, SpellBook> getConstructingCachedMap(CharID id) { Map<String, SpellBook> componentMap = getCachedMap(id); if (componentMap == null) { componentMap = new LinkedHashMap<>(); setCache(id, componentMap); } return componentMap; } /** * Returns the SpellBook for the given SpellBook name and the Player * Character identified by the given CharID. * * @param id * The CharID identifying the PlayerCharacter for which the * SpellBook for the given name should be returned * @param name * The name of the SpellBook to be returned * @return The SpellBook for the given SpellBook name and the Player * Character identified by the given CharID */ public SpellBook getBookNamed(CharID id, String name) { Map<String, SpellBook> componentMap = getCachedMap(id); if (componentMap == null) { return null; } return componentMap.get(name); } /** * Returns a non-null Collection of SpellBook names in this SpellBookFacet * for the Player Character represented by the given CharID. This method * returns an empty Set if no SpellBooks are in this SpellBookFacet for the * Player Character identified by the given CharID. * * This method is value-semantic in that ownership of the returned * Collection is transferred to the class calling this method. Modification * of the returned Collection will not modify this SpellBookFacet and * modification of this SpellBookFacet will not modify the returned * Collection. Modifications to the returned Collection will also not modify * any future or previous objects returned by this (or other) methods on * SpellBookFacet. If you wish to modify the information stored in this * SpellBookFacet, you must use the add*() and remove*() methods of * SpellBookFacet. * * @param id * The CharID representing the Player Character for which a copy * of the SpellBooks in this SpellBookFacet should be returned. * @return A non-null Collection of SpellBooks in this SpellBookFacet for * the Player Character represented by the given CharID */ public Collection<String> getBookNames(CharID id) { Map<String, SpellBook> componentMap = getCachedMap(id); if (componentMap == null) { return Collections.emptySet(); } return Collections.unmodifiableSet(componentMap.keySet()); } /** * Returns a non-null copy of the Collection of SpellBooks in this * SpellBookFacet for the Player Character represented by the given CharID. * This method returns an empty Set if no SpellBooks are in this * SpellBookFacet for the Player Character identified by the given CharID. * * This method is value-semantic in that ownership of the returned * Collection is transferred to the class calling this method. Modification * of the returned Collection will not modify this SpellBookFacet and * modification of this SpellBookFacet will not modify the returned * Collection. Modifications to the returned Collection will also not modify * any future or previous objects returned by this (or other) methods on * SpellBookFacet. If you wish to modify the information stored in this * SpellBookFacet, you must use the add*() and remove*() methods of * SpellBookFacet. * * @param id * The CharID representing the Player Character for which a copy * of the SpellBooks in this SpellBookFacet should be returned. * @return A non-null Collection of SpellBooks in this SpellBookFacet for * the Player Character represented by the given CharID */ public Collection<SpellBook> getBooks(CharID id) { Map<String, SpellBook> componentMap = getCachedMap(id); if (componentMap == null) { return Collections.emptySet(); } return Collections.unmodifiableCollection(componentMap.values()); } /** * Returns true if this SpellBookFacet contains a SpellBook of the given * name in the list of SpellBooks for the Player Character represented by * the given CharID. * * @param id * The CharID representing the Player Character used for testing * @param name * The SpellBook name to test if this SpellBookFacet contains a * SpellBook by that name for the Player Character represented by * the given CharID * @return true if this SpellBookFacet contains a SpellBook with the given * name for the Player Character represented by the given CharID; * false otherwise */ public boolean containsBookNamed(CharID id, String name) { Map<String, SpellBook> componentMap = getCachedMap(id); return (componentMap != null) && componentMap.containsKey(name); } /** * Returns the count of SpellBooks in this SpellBookFacet for the Player * Character represented by the given CharID. * * @param id * The CharID representing the Player Character for which the * count of SpellBooks should be returned * @return The count of SpellBooks in this SpellBookFacet for the Player * Character represented by the given CharID */ public int getCount(CharID id) { Map<String, SpellBook> componentMap = getCachedMap(id); return (componentMap == null) ? 0 : componentMap.size(); } /** * Removes the SpellBook with the given name from the list of SpellBooks * stored in this SpellBookFacet for the Player Character represented by the * given CharID. * * @param id * The CharID representing the Player Character from which the * SpellBook with the given name should be removed * @param name * The name of the SpellBook to be removed from the list of * SpellBooks stored in this SpellBookFacet for the Player * Character represented by the given CharID */ public void removeBookNamed(CharID id, String name) { Map<String, SpellBook> componentMap = getCachedMap(id); if (componentMap != null) { componentMap.remove(name); } } public void setEquipmentFacet(EquipmentFacet equipmentFacet) { this.equipmentFacet = equipmentFacet; } /** * Initializes the connections for SpellBookFacet to other facets. * * This method is automatically called by the Spring framework during * initialization of the SpellBookFacet. */ public void init() { equipmentFacet.addDataFacetChangeListener(this); } /** * Copies the contents of the SpellBookFacet from one Player Character to * another Player Character, based on the given CharIDs representing those * Player Characters. * * This is a method in SpellBookFacet in order to avoid exposing the mutable * Map object to other classes. This should not be inlined, as the Map is * internal information to SpellBookFacet and should not be exposed to other * classes. * * Note also the copy is a one-time event and no SpellBook references are * maintained between the Player Characters represented by the given CharIDs * (meaning once this copy takes place, any change to the SpellBook will * only impact the Player Character where the SpellBook 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) { Map<String, SpellBook> map = getCachedMap(source); if (map != null) { addAll(copy, map.values()); } } }