/*
* Copyright 2007, 2008 (C) Tom Parker <thpr@users.sourceforge.net>
*
* 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
*/
package pcgen.cdom.choiceset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import pcgen.cdom.base.CDOMListObject;
import pcgen.cdom.base.CDOMReference;
import pcgen.cdom.base.Constants;
import pcgen.cdom.base.PrimitiveChoiceSet;
import pcgen.cdom.enumeration.GroupingState;
import pcgen.cdom.list.DomainSpellList;
import pcgen.cdom.reference.ReferenceUtilities;
import pcgen.core.PlayerCharacter;
import pcgen.core.spell.Spell;
import pcgen.util.Logging;
/**
* A SpellReferenceChoiceSet contains references to CDOMListObjects. This is a
* specialized PrimitiveChoiceSet designed for use with {@code CDOMListObject<Spell>}
* lists.
*
* The contents of a SpellReferenceChoiceSet is defined at construction of the
* SpellReferenceChoiceSet. The contents of a SpellReferenceChoiceSet is fixed,
* and will not vary by the PlayerCharacter used to resolve the
* SpellReferenceChoiceSet.
*
* This exists as a special case (from a generic PrimitiveChoiceSet) for two
* reasons: (1) getChoiceClass() is hardcoded to return CDOMListObject (vs. the
* risk of returning an inconsistent answer like ClassSpellList or
* DomainSpellList [this may contain either or both]) (2) getLSTformat needs to
* correct for DomainSpellList references having a "DOMAIN." prefix in order to
* distinguish them from ClassSpellList references/names
*/
public class SpellReferenceChoiceSet implements
PrimitiveChoiceSet<CDOMListObject<Spell>>
{
/**
* The underlying Set of CDOMReferences that contain the CDOMListObjects in
* this SpellReferenceChoiceSet
*/
private final Set<CDOMReference<? extends CDOMListObject<Spell>>> set;
/**
* Constructs a new SpellReferenceChoiceSet which contains the Set of
* CDOMListObjects contained within the given CDOMReferences. The
* CDOMReferences do not need to be resolved at the time of construction of
* the SpellReferenceChoiceSet.
*
* This constructor is both reference-semantic and value-semantic. Ownership
* of the Collection provided to this constructor is not transferred.
* Modification of the Collection (after this constructor completes) does
* not result in modifying the ReferenceChoiceSet, and the
* SpellReferenceChoiceSet will not modify the given Collection. However,
* this SpellReferenceChoiceSet will maintain hard references to the
* CDOMReference objects contained within the given Collection.
*
* @param listRefCollection
* A Collection of CDOMReferences which define the Set of
* CDOMListObjects contained within the SpellReferenceChoiceSet
* @throws IllegalArgumentException
* if the given Collection is null or empty.
*/
public SpellReferenceChoiceSet(
Collection<CDOMReference<? extends CDOMListObject<Spell>>> listRefCollection)
{
if (listRefCollection == null)
{
throw new IllegalArgumentException(
"Choice Collection cannot be null");
}
if (listRefCollection.isEmpty())
{
throw new IllegalArgumentException(
"Choice Collection cannot be empty");
}
set = new HashSet<>(
listRefCollection);
if (set.size() != listRefCollection.size())
{
if (Logging.isLoggable(Level.WARNING))
{
Logging.log(Level.WARNING, "Found duplicate item in " + listRefCollection);
}
//TODO need to trigger a bad GroupingState...
}
}
/**
* Returns a representation of this SpellReferenceChoiceSet, suitable for
* storing in an LST file.
*
* @param useAny
* use "ANY" for the global "ALL" reference when creating the LST
* format
* @return A representation of this SpellReferenceChoiceSet, suitable for
* storing in an LST file.
*/
@Override
public String getLSTformat(boolean useAny)
{
Set<CDOMReference<?>> sortedSet = new TreeSet<>(
ReferenceUtilities.REFERENCE_SORTER);
sortedSet.addAll(set);
StringBuilder sb = new StringBuilder();
List<CDOMReference<?>> domainList = new ArrayList<>();
boolean needComma = false;
for (CDOMReference<?> ref : sortedSet)
{
if (DomainSpellList.class.equals(ref.getReferenceClass()))
{
domainList.add(ref);
}
else
{
if (needComma)
{
sb.append(Constants.COMMA);
}
sb.append(ref.getLSTformat(false));
needComma = true;
}
}
for (CDOMReference<?> ref : domainList)
{
if (needComma)
{
sb.append(Constants.COMMA);
}
sb.append("DOMAIN.");
sb.append(ref.getLSTformat(false));
needComma = true;
}
return sb.toString();
}
/**
* The class of object this SpellReferenceChoiceSet contains.
*
* @return The class of object this SpellReferenceChoiceSet contains.
*/
@Override
public Class<CDOMListObject> getChoiceClass()
{
return CDOMListObject.class;
}
/**
* Returns a Set containing the CDOMListObjects which this
* SpellReferenceChoiceSet contains. The contents of a
* SpellReferenceChoiceSet is fixed, and will not vary by the
* PlayerCharacter used to resolve the SpellReferenceChoiceSet.
*
* The behavior of this method is undefined if the CDOMReference objects
* provided during the construction of this SpellReferenceChoiceSet are not
* yet resolved.
*
* This method is value-semantic, meaning that ownership of the Set returned
* by this method will be transferred to the calling object. Modification of
* the returned Set should not result in modifying the
* SpellReferenceChoiceSet, and modifying the SpellReferenceChoiceSet after
* the Set is returned should not modify the Set.
*
* @param pc
* The PlayerCharacter for which the choices in this
* SpellReferenceChoiceSet should be returned.
* @return A Set containing the CDOMListObjects which this
* SpellReferenceChoiceSet contains.
*/
@Override
public Set<CDOMListObject<Spell>> getSet(PlayerCharacter pc)
{
Set<CDOMListObject<Spell>> returnSet = new HashSet<>();
for (CDOMReference<? extends CDOMListObject<Spell>> ref : set)
{
returnSet.addAll(ref.getContainedObjects());
}
return returnSet;
}
/**
* Returns the consistent-with-equals hashCode for this
* SpellReferenceChoiceSet
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode()
{
return set.size();
}
/**
* Returns true if this SpellReferenceChoiceSet is equal to the given
* Object. Equality is defined as being another SpellReferenceChoiceSet
* object with equal underlying contents.
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj)
{
if (obj == this)
{
return true;
}
if (obj instanceof SpellReferenceChoiceSet)
{
SpellReferenceChoiceSet other = (SpellReferenceChoiceSet) obj;
return set.equals(other.set);
}
return false;
}
/**
* Returns the GroupingState for this SpellReferenceChoiceSet. The
* GroupingState indicates how this SpellReferenceChoiceSet can be combined
* with other PrimitiveChoiceSets.
*
* @return The GroupingState for this SpellReferenceChoiceSet.
*/
@Override
public GroupingState getGroupingState()
{
GroupingState state = GroupingState.EMPTY;
for (CDOMReference<? extends CDOMListObject<Spell>> listref : set)
{
state = state.add(listref.getGroupingState());
}
//TODO I think this needs state.compound(GroupingState.ALLOWS_UNION)??
return state;
}
}