package java.util;

import sun.misc.SharedSecrets;

//抽象枚举Set类,继承AbstractSet
public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
        implements Cloneable, java.io.Serializable {

    final Class<E> elementType;

    final Enum<?>[] universe;//缓存枚举类

    private static Enum<?>[] ZERO_LENGTH_ENUM_ARRAY = new Enum<?>[0];

    EnumSet(Class<E> elementType, Enum<?>[] universe){
        this.elementType = elementType;
        this.universe = universe;
    }

    //创建一个空的枚举Set类,容量小于等于64,创建的是RegularEnumSet,否则创建的JumboEnumSet
    public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType){
        Enum<?>[] universe = getUniverse(elementType);
        if(universe == null)
            throw new ClassCastException(elementType + " not an enum");

        if(universe.length <= 64)
            return new RegularEnumSet<>(elementType, universe);
        else
            return new JumboEnumSet<>(elementType, universe);
    }


    //构造一个包含枚举类中所有枚举项的集合
    public static <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType){
        EnumSet<E> result = noneOf(elementType);
        result.addAll();
        return result;
    }

    //将元素添加到枚举set中,调用前为空
    abstract void addAll();

    //由EnumSet创建它clone
    public static <E extends Enum<E>> EnumSet<E> copyOf(EnumSet<E> s){
        return s.clone();
    }

    //由一个集合创建EnumSet
    public static <E extends Enum<E>> EnumSet<E> copyOf(Collection<E> c){
        if(c instanceof EnumSet){
            return ((EnumSet<E>) c).clone();
        }else{
            if(c.isEmpty())
                throw new IllegalArgumentException("Collection is empty");
            Iterator<E> i = c.iterator();
            E first = i.next();
            EnumSet<E> result = EnumSet.of(first);
            while (i.hasNext())
                result.add(i.next());
            return result;
        }
    }

    //由一个EnumSet s创建EnumSet
    public static <E extends Enum<E>> EnumSet<E> complementOf(EnumSet<E> s){
        EnumSet<E> result = copyOf(s);
        result.complement();
        return result;
    }

    //创建一个包含e的EnumSet
    public static <E extends Enum<E>> EnumSet<E> of(E e){
        EnumSet<E> result = noneOf(e.getDeclaringClass());
        result.add(e);
        return result;
    }

    //创建一个包含e1,e2的EnumSet
    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2){
        EnumSet<E> result = noneOf(e1.getDeclaringClass());
        result.add(e1);
        result.add(e2);
        return result;
    }

    //创建一个包含e1,e2,e3的EnumSet
    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3){
        EnumSet<E> result = noneOf(e1.getDeclaringClass());
        result.add(e1);
        result.add(e2);
        result.add(e3);
        return result;
    }

    //创建一个包含e1,e2,e3,e4的EnumSet
    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4){
        EnumSet<E> result = noneOf(e1.getDeclaringClass());
        result.add(e1);
        result.add(e2);
        result.add(e3);
        result.add(e4);
        return result;
    }

    //创建一个包含e1,e2,e3,e4,e5的EnumSet
    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4,
            E e5){
        EnumSet<E> result = noneOf(e1.getDeclaringClass());
        result.add(e1);
        result.add(e2);
        result.add(e3);
        result.add(e4);
        result.add(e5);
        return result;
    }

    //创建至少包含first,rest元素的EnumSet,
    @SafeVarargs
    public static <E extends Enum<E>> EnumSet<E> of(E first, E... rest){
        EnumSet<E> result = noneOf(first.getDeclaringClass());
        result.add(first);
        for(E e : rest){ result.add(e); }
        return result;
    }

    //创建EnumSet,将[from,to]中所有元素都添加
    public static <E extends Enum<E>> EnumSet<E> range(E from, E to){
        if(from.compareTo(to) > 0)
            throw new IllegalArgumentException(from + " > " + to);
        EnumSet<E> result = noneOf(from.getDeclaringClass());
        result.addRange(from, to);
        return result;
    }

    abstract void addRange(E from, E to);

    //返回this的clone,super.clone是浅复制
    @SuppressWarnings("unchecked")
    public EnumSet<E> clone(){
        try {
            return (EnumSet<E>) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError(e);
        }
    }

    /**
     * Complements the contents of this enum set.
     */
    abstract void complement();

    //当类型不匹配,抛出此异常
    final void typeCheck(E e){
        Class<?> eClass = e.getClass();
        if(eClass != elementType && eClass.getSuperclass() != elementType)
            throw new ClassCastException(eClass + " != " + elementType);
    }

    //缓存element到Enum数组中
    private static <E extends Enum<E>> E[] getUniverse(Class<E> elementType){
        return SharedSecrets.getJavaLangAccess()
                .getEnumConstantsShared(elementType);
    }

    //快照序列化
    private static class SerializationProxy<E extends Enum<E>>
            implements java.io.Serializable {
        /**
         * The element type of this enum set.
         *
         * @serial
         */
        private final Class<E> elementType;

        /**
         * The elements contained in this enum set.
         *
         * @serial
         */
        private final Enum<?>[] elements;

        SerializationProxy(EnumSet<E> set){
            elementType = set.elementType;
            elements = set.toArray(ZERO_LENGTH_ENUM_ARRAY);
        }

        // instead of cast to E, we should perhaps use elementType.cast()
        // to avoid injection of forged stream, but it will slow the implementation
        @SuppressWarnings("unchecked")
        private Object readResolve(){
            EnumSet<E> result = EnumSet.noneOf(elementType);
            for(Enum<?> e : elements){ result.add((E) e); }
            return result;
        }

        private static final long serialVersionUID = 362491234563181265L;
    }

    Object writeReplace(){
        return new SerializationProxy<>(this);
    }

    // readObject method for the serialization proxy pattern
    // See Effective Java, Second Ed., Item 78.
    private void readObject(java.io.ObjectInputStream stream)
            throws java.io.InvalidObjectException{
        throw new java.io.InvalidObjectException("Proxy required");
    }
}