/* * Copyright 2005 (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 * * Created on June 18, 2005. * * Current Ver: $Revision: 513 $ */ package pcgen.cdom.enumeration; import java.io.File; import java.lang.reflect.Field; import java.math.BigDecimal; import java.net.URI; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.Map; import pcgen.base.formula.Formula; import pcgen.base.lang.UnreachableError; import pcgen.base.util.CaseInsensitiveMap; import pcgen.base.util.DoubleKeyMapToList; import pcgen.cdom.base.CDOMList; import pcgen.cdom.base.CDOMListObject; import pcgen.cdom.base.Category; import pcgen.cdom.base.ChooseInformation; import pcgen.cdom.base.PersistentTransitionChoice; import pcgen.cdom.base.TransitionChoice; import pcgen.cdom.content.CNAbility; import pcgen.cdom.content.ChallengeRating; import pcgen.cdom.content.HitDie; import pcgen.cdom.content.LevelCommandFactory; import pcgen.cdom.content.LevelExchange; import pcgen.cdom.content.Processor; import pcgen.cdom.content.SpellResistance; import pcgen.cdom.helper.CNAbilitySelection; import pcgen.cdom.helper.Capacity; import pcgen.cdom.list.ClassSkillList; import pcgen.cdom.list.ClassSpellList; import pcgen.cdom.list.DomainSpellList; import pcgen.cdom.reference.CDOMDirectSingleRef; import pcgen.cdom.reference.CDOMSingleRef; import pcgen.core.Ability; import pcgen.core.ArmorProf; import pcgen.core.Campaign; import pcgen.core.Equipment; import pcgen.core.GameMode; import pcgen.core.Language; import pcgen.core.PCAlignment; import pcgen.core.PCClass; import pcgen.core.PCStat; import pcgen.core.QualifiedObject; import pcgen.core.ShieldProf; import pcgen.core.SizeAdjustment; import pcgen.core.SpellProhibitor; import pcgen.core.SubClass; import pcgen.core.WeaponProf; import pcgen.core.analysis.SizeUtilities; import pcgen.core.character.CompanionMod; import pcgen.core.character.WieldCategory; import pcgen.core.prereq.Prerequisite; import pcgen.core.spell.Spell; import pcgen.util.enumeration.Load; import pcgen.util.enumeration.Visibility; /** * @author Tom Parker <thpr@users.sourceforge.net> * * This is a Typesafe enumeration of legal Object Characteristics of an object. * It is designed to act as an index to a specific Objects within a * CDOMObject. * * ObjectKeys are designed to store items in a CDOMObject in a type-safe * fashion. Note that it is possible to use the ObjectKey to cast the object to * the type of object stored by the ObjectKey. (This assists with Generics) * * A "default value" (may be null) must be provided at object construction (the * default is provided when getSafe(ObjectKey) is called in CDOMObject). This * default value is especially useful for Boolean ObjectKeys. * * @param <T> * The class of object stored by this ObjectKey. */ public class ObjectKey<T> { private static CaseInsensitiveMap<ObjectKey<?>> map = null; public static final ObjectKey<Boolean> USE_UNTRAINED = new ObjectKey<>(Boolean.TRUE); public static final ObjectKey<Boolean> EXCLUSIVE = new ObjectKey<>(Boolean.FALSE); public static final ObjectKey<CDOMSingleRef<PCAlignment>> ALIGNMENT = new ObjectKey<>(null); public static final ObjectKey<Boolean> READ_ONLY = new ObjectKey<>(Boolean.FALSE); public static final ObjectKey<CDOMSingleRef<PCStat>> KEY_STAT = new ObjectKey<>(null); public static final ObjectKey<SkillArmorCheck> ARMOR_CHECK = new ObjectKey<>(SkillArmorCheck.NONE); public static final ObjectKey<Visibility> VISIBILITY = new ObjectKey<>(Visibility.DEFAULT); public static final ObjectKey<Boolean> REMOVABLE = new ObjectKey<>(Boolean.TRUE); public static final ObjectKey<SubRegion> SUBREGION = new ObjectKey<>(null); public static final ObjectKey<Region> REGION = new ObjectKey<>(null); public static final ObjectKey<Boolean> USETEMPLATENAMEFORSUBREGION = new ObjectKey<>(Boolean.FALSE); public static final ObjectKey<Boolean> USETEMPLATENAMEFORREGION = new ObjectKey<>(Boolean.FALSE); public static final ObjectKey<Gender> GENDER_LOCK = new ObjectKey<>(null); public static final ObjectKey<Boolean> USETEMPLATENAMEFORSUBRACE = new ObjectKey<>(Boolean.FALSE); public static final ObjectKey<SubRace> SUBRACE = new ObjectKey<>(null); public static final ObjectKey<BigDecimal> CR_MODIFIER = new ObjectKey<>(BigDecimal.ZERO); public static final ObjectKey<RaceType> RACETYPE = new ObjectKey<>(null); public static final ObjectKey<BigDecimal> COST = new ObjectKey<>(BigDecimal.ZERO); public static final ObjectKey<CDOMSingleRef<PCStat>> SPELL_STAT = new ObjectKey<>(null); public static final ObjectKey<Boolean> COST_DOUBLE = new ObjectKey<>(null); public static final ObjectKey<Boolean> ASSIGN_TO_ALL = new ObjectKey<>(Boolean.FALSE); public static final ObjectKey<EqModNameOpt> NAME_OPT = new ObjectKey<>(EqModNameOpt.NORMAL); public static final ObjectKey<EqModFormatCat> FORMAT = new ObjectKey<>(EqModFormatCat.PARENS); public static final ObjectKey<Boolean> ATTACKS_PROGRESS = new ObjectKey<>(Boolean.TRUE); public static final ObjectKey<WieldCategory> WIELD = new ObjectKey<>(null); public static final ObjectKey<BigDecimal> WEIGHT = new ObjectKey<>(BigDecimal.ZERO); public static final ObjectKey<BigDecimal> WEIGHT_MOD = new ObjectKey<>(BigDecimal.ZERO); public static final ObjectKey<CDOMSingleRef<WeaponProf>> WEAPON_PROF = new ObjectKey<>(null); public static final ObjectKey<CDOMSingleRef<ArmorProf>> ARMOR_PROF = new ObjectKey<>(null); public static final ObjectKey<CDOMSingleRef<ShieldProf>> SHIELD_PROF = new ObjectKey<>(null); public static final ObjectKey<EqModControl> MOD_CONTROL = new ObjectKey<>(EqModControl.YES); public static final ObjectKey<BigDecimal> CURRENT_COST = new ObjectKey<>(null); /* * This MUST Stay Object! Otherwise the code hierarchy ends up with circular * references/tangles */ public static final ObjectKey<Object> PARENT = new ObjectKey<>(null); public static final ObjectKey<Object> TOKEN_PARENT = new ObjectKey<>(null); public static final ObjectKey<Processor<HitDie>> HITDIE = new ObjectKey<>(null); public static final ObjectKey<ChallengeRating> CHALLENGE_RATING = new ObjectKey<>(ChallengeRating.ZERO); public static final ObjectKey<Boolean> USE_SPELL_SPELL_STAT = new ObjectKey<>(Boolean.FALSE); public static final ObjectKey<Boolean> CASTER_WITHOUT_SPELL_STAT = new ObjectKey<>(Boolean.FALSE); public static final ObjectKey<Boolean> SPELLBOOK = new ObjectKey<>(Boolean.FALSE); public static final ObjectKey<Boolean> MOD_TO_SKILLS = new ObjectKey<>(Boolean.TRUE); public static final ObjectKey<Boolean> MEMORIZE_SPELLS = new ObjectKey<>(Boolean.TRUE); public static final ObjectKey<Boolean> IS_MONSTER = new ObjectKey<>(null); public static final ObjectKey<Boolean> ALLOWBASECLASS = new ObjectKey<>(Boolean.TRUE); public static final ObjectKey<Boolean> HAS_BONUS_SPELL_STAT = new ObjectKey<>(null); public static final ObjectKey<CDOMSingleRef<PCStat>> BONUS_SPELL_STAT = new ObjectKey<>(null); public static final ObjectKey<HitDie> LEVEL_HITDIE = new ObjectKey<>(HitDie.ZERO); public static final ObjectKey<ClassSpellList> CLASS_SPELLLIST = new ObjectKey<>(null); public static final ObjectKey<DomainSpellList> DOMAIN_SPELLLIST = new ObjectKey<>(null); public static final ObjectKey<TransitionChoice<CDOMListObject<Spell>>> SPELLLIST_CHOICE = new ObjectKey<>(null); public static final ObjectKey<TransitionChoice<ClassSkillList>> SKILLLIST_CHOICE = new ObjectKey<>(null); public static final ObjectKey<Boolean> STACKS = new ObjectKey<>(Boolean.FALSE); public static final ObjectKey<Boolean> MULTIPLE_ALLOWED = new ObjectKey<>(Boolean.FALSE); public static final ObjectKey<BigDecimal> SELECTION_COST = new ObjectKey<>(BigDecimal.ONE); public static final ObjectKey<Boolean> NAME_PI = new ObjectKey<>(Boolean.FALSE); public static final ObjectKey<Boolean> DESC_PI = new ObjectKey<>(Boolean.FALSE); public static final ObjectKey<Category<Ability>> ABILITY_CAT = new ObjectKey<>(null); public static final ObjectKey<Load> UNENCUMBERED_LOAD = new ObjectKey<>(Load.LIGHT); public static final ObjectKey<Load> UNENCUMBERED_ARMOR = new ObjectKey<>(Load.LIGHT); public static final ObjectKey<Boolean> ANY_FAVORED_CLASS = new ObjectKey<>(Boolean.FALSE); public static final ObjectKey<LevelCommandFactory> MONSTER_CLASS = new ObjectKey<>(null); public static final ObjectKey<CDOMSingleRef<Equipment>> BASE_ITEM = new ObjectKey<>(null); public static final ObjectKey<LevelExchange> EXCHANGE_LEVEL = new ObjectKey<>(null); public static final ObjectKey<CDOMSingleRef<PCClass>> EX_CLASS = new ObjectKey<>(null); public static final ObjectKey<SpellResistance> SR = new ObjectKey<>(SpellResistance.NONE); public static final ObjectKey<QualifiedObject<Boolean>> HAS_DEITY_WEAPONPROF = new ObjectKey<>( new QualifiedObject<>(Boolean.FALSE)); public static final ObjectKey<SpellProhibitor> CHOICE = new ObjectKey<>(null); public static final ObjectKey<TransitionChoice<CNAbility>> MODIFY_CHOICE = new ObjectKey<>(null); public static final ObjectKey<Boolean> CONTAINER_CONSTANT_WEIGHT = new ObjectKey<>(Boolean.FALSE); public static final ObjectKey<BigDecimal> CONTAINER_WEIGHT_CAPACITY = new ObjectKey<>(null); public static final ObjectKey<Capacity> TOTAL_CAPACITY = new ObjectKey<>(null); public static final ObjectKey<Category<SubClass>> SUBCLASS_CATEGORY = new ObjectKey<>(null); public static final ObjectKey<Nature> ABILITY_NATURE = new ObjectKey<>(Nature.NORMAL); public static final ObjectKey<CDOMSingleRef<SizeAdjustment>> BASESIZE; public static final ObjectKey<CDOMSingleRef<SizeAdjustment>> SIZE; public static final ObjectKey<TransitionChoice<Region>> REGION_CHOICE = new ObjectKey<>(null); public static final ObjectKey<Boolean> USE_MASTER_SKILL = new ObjectKey<>(Boolean.FALSE); public static final ObjectKey<Boolean> DONTADD_HITDIE = new ObjectKey<>(null); public static final ObjectKey<Boolean> DONTADD_SKILLPOINTS = new ObjectKey<>(null); public static final ObjectKey<KitApply> APPLY_MODE = new ObjectKey<>(KitApply.PERMANENT); public static final ObjectKey<QualifiedObject<Formula>> EQUIP_BUY = new ObjectKey<>(null); public static final ObjectKey<QualifiedObject<Formula>> KIT_TOTAL_COST = new ObjectKey<>(null); public static final ObjectKey<Date> SOURCE_DATE = new ObjectKey<>(null); public static final ObjectKey<Campaign> SOURCE_CAMPAIGN = new ObjectKey<>(null); public static final ObjectKey<Boolean> IS_OGL = new ObjectKey<>(Boolean.FALSE); public static final ObjectKey<Boolean> IS_MATURE = new ObjectKey<>(Boolean.FALSE); public static final ObjectKey<Boolean> IS_LICENSED = new ObjectKey<>(Boolean.FALSE); public static final ObjectKey<Boolean> IS_D20 = new ObjectKey<>(Boolean.FALSE); public static final ObjectKey<Boolean> SHOW_IN_MENU = new ObjectKey<>(Boolean.FALSE); public static final ObjectKey<PersistentTransitionChoice<Language>> CHOOSE_LANGAUTO = new ObjectKey<>(null); public static final ObjectKey<Prerequisite> PRERACETYPE = new ObjectKey<>(null); public static final ObjectKey<File> DIRECTORY = new ObjectKey<>(null); public static final ObjectKey<File> WRITE_DIRECTORY = new ObjectKey<>(null); public static final ObjectKey<GameMode> GAME_MODE = new ObjectKey<>(null); public static final ObjectKey<PersistentTransitionChoice<CNAbilitySelection>> TEMPLATE_FEAT = new ObjectKey<>(null); public static final ObjectKey<Boolean> VALID_FOR_DEITY = new ObjectKey<>(Boolean.TRUE); public static final ObjectKey<Boolean> VALID_FOR_FOLLOWER = new ObjectKey<>(Boolean.TRUE); public static final ObjectKey<Boolean> IS_DEFAULT_SIZE = new ObjectKey<>(Boolean.FALSE); public static final ObjectKey<Boolean> ROLLED = new ObjectKey<>(Boolean.TRUE); public static final ObjectKey<ChooseInformation<?>> CHOOSE_INFO = new ObjectKey<>(null); public static final ObjectKey<Destination> DESTINATION = new ObjectKey<>(null); public static final ObjectKey<CDOMSingleRef<Ability>> FEATEQ_STRING = new ObjectKey<>(null); public static final ObjectKey<Boolean> INTERNAL = new ObjectKey<>(Boolean.FALSE); public static final ObjectKey<DoubleKeyMapToList<Spell, CDOMList<Spell>, Integer>> SPELL_PC_INFO = new ObjectKey<>(null); public static final ObjectKey<ClassSkillList> CLASS_SKILLLIST = new ObjectKey<>(null); public static final ObjectKey<Status> STATUS = new ObjectKey<>(Status.Release); public static final ObjectKey<URI> ICON_URI = new ObjectKey<>(null); public static final ObjectKey<Category<CompanionMod>> MOD_CATEGORY = new ObjectKey<>(null); public static final ObjectKey<CDOMSingleRef<SizeAdjustment>> CUSTOMSIZE = new ObjectKey<>(null); /* * TODO Okay, this is a hack. */ static { buildMap(); BASESIZE = new ObjectKey<CDOMSingleRef<SizeAdjustment>>(null) { @Override public CDOMSingleRef<SizeAdjustment> getDefault() { return CDOMDirectSingleRef.getRef(SizeUtilities.getDefaultSizeAdjustment()); } }; map.put("BASESIZE", BASESIZE); SIZE = new ObjectKey<CDOMSingleRef<SizeAdjustment>>(null) { @Override public CDOMSingleRef<SizeAdjustment> getDefault() { return CDOMDirectSingleRef.getRef(SizeUtilities.getDefaultSizeAdjustment()); } }; map.put("SIZE", SIZE); } private final T defaultValue; private ObjectKey(T def) { defaultValue = def; } public T getDefault() { return defaultValue; } public T cast(Object obj) { return (T) obj; } public static <OT> ObjectKey<OT> getKeyFor(Class<OT> objectClass, String name) { if (map == null) { buildMap(); } /* * CONSIDER This is actually not type safe, there is a case of asking * for a String a second time with a different Class that ObjectKey * currently does not handle. Two solutions: One, store this in a * Two-Key map and allow a String to map to more than one ObjectKey * given different output types (considered confusing) or Two, store the * Class and validate that with a an error message if a different class * is requested. */ ObjectKey<OT> key = (ObjectKey<OT>) map.get(name); if (key == null) { key = new ObjectKey<>(null); map.put(name, key); } return key; } private static void buildMap() { map = new CaseInsensitiveMap<>(); Field[] fields = ObjectKey.class.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { int mod = fields[i].getModifiers(); if (java.lang.reflect.Modifier.isStatic(mod) && java.lang.reflect.Modifier.isFinal(mod) && java.lang.reflect.Modifier.isPublic(mod)) { try { Object obj = fields[i].get(null); if (obj instanceof ObjectKey) { map.put(fields[i].getName(), (ObjectKey<?>) obj); } } catch (IllegalArgumentException | IllegalAccessException e) { throw new UnreachableError(e); } } } } @Override public String toString() { /* * CONSIDER Should this find a way to do a Two-Way Map or something to * that effect? */ if (map == null) { buildMap(); } for (Map.Entry<?, ObjectKey<?>> me : map.entrySet()) { if (me.getValue() == this) { return me.getKey().toString(); } } // Error return ""; } public static Collection<ObjectKey<?>> getAllConstants() { if (map == null) { buildMap(); } return new HashSet<>(map.values()); } }