/* * 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.base; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import pcgen.cdom.enumeration.CharID; import pcgen.cdom.facet.event.DataFacetChangeEvent; import pcgen.cdom.facet.event.DataFacetChangeListener; import pcgen.cdom.helper.CNAbilitySelection; import pcgen.cdom.helper.CNAbilitySelectionUtilities; public class AbstractCNASEnforcingFacet extends AbstractDataFacet<CharID, CNAbilitySelection> implements DataFacetChangeListener<CharID, CNAbilitySelection> { public boolean isEmpty(CharID id) { List<List<SourcedCNAS>> list = getList(id); return (list == null) || list.isEmpty(); } public boolean add(CharID id, CNAbilitySelection cnas, Object source) { if (cnas == null) { throw new IllegalArgumentException("Attempt to add null to list"); } if (source == null) { throw new IllegalArgumentException( "Attempt to add object with null source to list"); } List<List<SourcedCNAS>> list = getConstructingList(id); for (List<SourcedCNAS> slist : list) { CNAbilitySelection main = slist.get(0).cnas; if (!CNAbilitySelectionUtilities.canCoExist(main, cnas)) { slist.add(new SourcedCNAS(cnas, source)); return false; } } List<SourcedCNAS> newList = new ArrayList<>(1); newList.add(new SourcedCNAS(cnas, source)); list.add(newList); fireDataFacetChangeEvent(id, cnas, DataFacetChangeEvent.DATA_ADDED); return true; } public boolean remove(CharID id, CNAbilitySelection cnas, Object source) { if (cnas == null) { throw new IllegalArgumentException( "Attempt to remove null from list"); } if (source == null) { throw new IllegalArgumentException( "Attempt to remove object with null source from list"); } List<List<SourcedCNAS>> list = getList(id); if (list == null) { return false; } for (Iterator<List<SourcedCNAS>> listIT = list.iterator(); listIT.hasNext();) { List<SourcedCNAS> array = listIT.next(); int length = array.size(); //Iterate backwards, so that we remove harmless items first for (int j = length - 1; j >= 0; j--) { SourcedCNAS sc = array.get(j); if (cnas.equals(sc.cnas) && source.equals(sc.source)) { //fix the array here if ((j == 0) && (length == 1)) { //There is no alternative, remove the array from the list; listIT.remove(); fireDataFacetChangeEvent(id, cnas, DataFacetChangeEvent.DATA_REMOVED); return true; } else { array.remove(j); CNAbilitySelection newPrimary = array.get(0).cnas; //Only fire if the CNAS differs to avoid churn if (!cnas.equals(newPrimary) && (j == 0)) { fireDataFacetChangeEvent(id, cnas, DataFacetChangeEvent.DATA_REMOVED); fireDataFacetChangeEvent(id, newPrimary, DataFacetChangeEvent.DATA_ADDED); return true; } return false; } } } } return false; } public Collection<CNAbilitySelection> getSet(CharID id) { List<List<SourcedCNAS>> list = getList(id); if (list == null) { return Collections.emptyList(); } List<CNAbilitySelection> returnList = new ArrayList<>(); for (List<SourcedCNAS> array : list) { returnList.add(array.get(0).cnas); } return returnList; } protected List<List<SourcedCNAS>> getList(CharID id) { return (List<List<SourcedCNAS>>) this.getCache(id); } private List<List<SourcedCNAS>> getConstructingList(CharID id) { List<List<SourcedCNAS>> list = getList(id); if (list == null) { list = new ArrayList<>(); setCache(id, list); } return list; } @Override public void copyContents(CharID source, CharID copy) { List<List<SourcedCNAS>> list = getList(source); if (list != null) { List<List<SourcedCNAS>> constructingList = getConstructingList(copy); for (List<SourcedCNAS> orig : list) { List<SourcedCNAS> newCnasList = new ArrayList<>( orig); constructingList.add(newCnasList); } } } public int getCount(CharID id) { List<List<SourcedCNAS>> list = getList(id); return (list == null) ? 0 : list.size(); } @Override public void dataAdded(DataFacetChangeEvent<CharID, CNAbilitySelection> dfce) { add(dfce.getCharID(), dfce.getCDOMObject(), dfce.getSource()); } @Override public void dataRemoved( DataFacetChangeEvent<CharID, CNAbilitySelection> dfce) { remove(dfce.getCharID(), dfce.getCDOMObject(), dfce.getSource()); } protected static class SourcedCNAS { public final CNAbilitySelection cnas; public final Object source; public SourcedCNAS(CNAbilitySelection cnas, Object source) { this.cnas = cnas; this.source = source; } @Override public String toString() { return cnas + " (src: " + source + ")"; } @Override public int hashCode() { return source.hashCode() ^ cnas.hashCode(); } @Override public boolean equals(Object o) { if (o == this) { return true; } if (o instanceof SourcedCNAS) { SourcedCNAS other = (SourcedCNAS) o; return cnas.equals(other.cnas) && source.equals(other.source); } return false; } } }