/*
* 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.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Map;
import pcgen.base.lang.UnreachableError;
import pcgen.base.util.CaseInsensitiveMap;
import pcgen.base.util.FixedStringList;
/**
* @author Tom Parker <thpr@users.sourceforge.net>
*
* This is a Typesafe enumeration of legal Characteristics of an Association. It
* is designed to act as an index to a specific Objects within an item that
* forms associations.
*
* @see pcgen.cdom.base.AssociatedObject
*
* AssociationKeys are designed to store items in an AssociatedObject in a
* type-safe fashion. Note that it is possible to use the AssociationKey to cast
* the object to the type of object stored by the AssociationKey. (This assists
* with Generics)
*
* @param <T>
* The class of object stored by this AssociationKey.
*/
public final class AssociationListKey<T>
{
/*
* CHOICES is a list used to store the choices made in a CHOOSE in a String
* (non-type-safe) fashion
*
* This should eventually be retired as the CHOOSE system becomes type safe.
* This is closely related to the transition to ChooseSelectionActor instead
* of ChooseResultActor, so this item is related to CODE-1902
*/
public static final AssociationListKey<FixedStringList> CHOICES = new AssociationListKey<>();
/*
* ADD is a widely used key used to store the information about items added to the PC.
* These items are stored against he TransitionChoice.
* This is a candidate to be sunset as part of CODE-1908
*/
public static final AssociationListKey<Object> ADD = new AssociationListKey<>();
/*
* End non-local token-related keys
*/
private static CaseInsensitiveMap<AssociationListKey<?>> map = null;
private AssociationListKey()
{
// Only allow instantiation here
}
public T cast(Object obj)
{
return (T) obj;
}
public static <OT> AssociationListKey<OT> getKeyFor(Class<OT> keyClass,
String keyName)
{
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.
*/
AssociationListKey<OT> key = (AssociationListKey<OT>) map.get(keyName);
if (key == null)
{
key = new AssociationListKey<>();
map.put(keyName, key);
}
return key;
}
private static void buildMap()
{
map = new CaseInsensitiveMap<>();
Field[] fields = AssociationListKey.class.getDeclaredFields();
for (int i = 0; i < fields.length; i++)
{
int mod = fields[i].getModifiers();
if (Modifier.isStatic(mod) && Modifier.isFinal(mod)
&& Modifier.isPublic(mod))
{
try
{
Object obj = fields[i].get(null);
if (obj instanceof AssociationListKey)
{
map.put(fields[i].getName(),
(AssociationListKey<?>) obj);
}
}
catch (IllegalArgumentException | IllegalAccessException e)
{
throw new UnreachableError(e);
}
}
}
}
@Override
public String toString()
{
if (map == null)
{
buildMap();
}
/*
* CONSIDER Should this find a way to do a Two-Way Map or something to
* that effect?
*/
for (Map.Entry<?, AssociationListKey<?>> me : map.entrySet())
{
if (me.getValue() == this)
{
return me.getKey().toString();
}
}
// Error
return "";
}
}