001/*
002 * To change this template, choose Tools | Templates
003 * and open the template in the editor.
004 */
005package com.nativelibs4java.util;
006
007import java.util.*;
008
009/**
010 * Methods to ease conversion between EnumValue-annotated enums and their integer value.
011 * @author ochafik
012 */
013public class EnumValues {
014
015    private static class Cache<E extends Enum<?>> {
016
017        final Map<Long, E> enumsByValue = new LinkedHashMap<Long, E>();
018        final Map<E, Long> valuesByEnum = new LinkedHashMap<E, Long>();
019
020        public Cache(Class<E> enumClass) {
021
022            if (ValuedEnum.class.isAssignableFrom(enumClass)) {
023                for (E e : enumClass.getEnumConstants()) {
024                    long value = ((ValuedEnum)e).value();
025                    enumsByValue.put(value, e);
026                    valuesByEnum.put(e, value);
027                }
028            } else {
029                for (E e : enumClass.getEnumConstants()) {
030                    EnumValue ev = null;
031                    try {
032                        ev = enumClass.getField(e.name()).getAnnotation(EnumValue.class);
033                    } catch (Exception ex) {
034                        throw new RuntimeException(ex);
035                    }
036                    if (ev == null) {
037                        throw new IllegalArgumentException("Enum value is not annotated with the " + EnumValue.class.getName() + " annotation : " + e);
038                    }
039                    long value = ev.value();
040                    enumsByValue.put(value, e);
041                    valuesByEnum.put(e, value);
042                }
043            }
044        }
045    }
046    private static final Map<Class<? extends Enum<?>>, Cache<?>> caches = new HashMap<Class<? extends Enum<?>>, Cache<?>>();
047
048    @SuppressWarnings("unchecked")
049    private static synchronized <E extends Enum<?>> Cache<E> getCache(Class<E> enumClass) {
050        Cache<E> cache = (Cache<E>) caches.get(enumClass);
051        if (cache == null) {
052            caches.put(enumClass, cache = new Cache(enumClass));
053        }
054        return cache;
055    }
056
057    /**
058     * Get the first enum item in enum class E which EnumValue value is equal to value
059     * @param <E> type of the enum
060     * @param value
061     * @param enumClass
062     * @return first enum item with matching value, null if there is no matching enum item
063     */
064    public static <E extends Enum<E>> E getEnum(long value, Class<E> enumClass) {
065        return getCache(enumClass).enumsByValue.get(value);
066    }
067
068    /**
069     * Get the set of all the enum item in enum class E which EnumValue value flags are all present in value
070     * @param <E> type of the enum
071     * @param value
072     * @param enumClass
073     * @return enum items with matching value flags
074     */
075    public static <E extends Enum<E>> EnumSet<E> getEnumSet(long value, Class<E> enumClass) {
076        EnumSet<E> set = EnumSet.noneOf(enumClass);
077        for (Map.Entry<Long, E> pair : getCache(enumClass).enumsByValue.entrySet()) {
078            long ev = pair.getKey();
079            if ((ev & value) == ev) {
080                set.add(pair.getValue());
081            }
082        }
083        return set;
084    }
085
086    /**
087     * Get the integer value associated with an enum item
088     * @see EnumValue
089     * @param enumItem
090     * @return the numeric value of the enum
091     */
092    @SuppressWarnings("unchecked")
093    public static <E extends Enum<?>> long getValue(E enumItem) {
094        return getCache((Class<E>) enumItem.getDeclaringClass()).valuesByEnum.get(enumItem);
095    }
096
097    /**
098     * Get the integer value resulting from ORing all the values of all the enum items present in the enum set.
099     * @see EnumValues#getValue(java.lang.Enum)
100     * @see EnumValue
101     * @param set the EnumSet to process
102     * @return the OR of all the values of the enums in the set
103     */
104    public static <E extends Enum<E>> long getValue(EnumSet<E> set) {
105        long v = 0;
106        for (E e : set) {
107            v |= getValue(e);
108        }
109        return v;
110    }
111}