package ru.yandex.webmaster3.core.util.enums;

import java.util.EnumSet;
import java.util.Set;

import ru.yandex.common.util.functional.Function;

/**
 * @author Stepan Koltsov
 * @author Ildar Safarov
 */
public abstract class AbstractIntEnumResolver<T extends Enum<T> & IntEnum> extends EnumResolver<T> {

    protected AbstractIntEnumResolver(Class<T> enumClass) {
        super(enumClass);
    }

    public abstract T fromValueOrNull(int value);

    public static Function<IntEnum, Integer> valueM() {
        return new Function<IntEnum, Integer>() {
            public Integer apply(IntEnum a) {
                return a.value();
            }
        };
    }

    public T fromValue(int intValue) {
        T value = fromValueOrNull(intValue);
        if (value != null) {
            return value;
        }
        throw new IllegalArgumentException("invalid value for enum: " + intValue);
    }

    public Function<Integer, T> fromValueM() {
        return new Function<Integer, T>() {
            public T apply(Integer value) {
                return fromValue(value);
            }
        };
    }

    public T fromValueOrUnknown(int intValue) {
        T value = fromValueOrNull(intValue);
        if (value != null) {
            return value;
        }
        if (unknown != null) {
            return unknown;
        }
        throw new IllegalArgumentException("enum has no UNKNOWN");
    }

    public Function<Integer, T> fromValueOrUnknownM() {
        return new Function<Integer, T>() {
            public T apply(Integer value) {
                return fromValue(value);
            }
        };
    }

    public ExtendedIntEnumSet<T> any() {
        return ExtendedIntEnumSet.any();
    }

    public ExtendedIntEnumSet<T> anyOf(Set<T> set) {
        return ExtendedIntEnumSet.anyOf(set);
    }

    public ExtendedIntEnumSet<T> anyOf(T... set) {
        if (set.length == 0) return none();
        else {
            EnumSet<T> enumSet = EnumSet.of(set[0]);
            for (int i = 1; i < set.length; ++i) {
                enumSet.add(set[i]);
            }
            return anyOf(enumSet);
        }
    }

    public ExtendedIntEnumSet<T> none() {
        return ExtendedIntEnumSet.none();
    }

    public ExtendedIntEnumSet<T> noneOf(Set<T> set) {
        return ExtendedIntEnumSet.noneOf(set);
    }

    public ExtendedIntEnumSet<T> noneOf(T... set) {
        if (set.length == 0) return any();
        else {
            EnumSet<T> enumSet = EnumSet.of(set[0]);
            for (int i = 1; i < set.length; ++i) {
                enumSet.add(set[i]);
            }
            return noneOf(enumSet);
        }
    }

}