package com.jscape.util;

import java.util.*;

/**
 * @author Alex Usun
 */
@SuppressWarnings("unchecked")
public class CollectionTools {

    @SafeVarargs
    public static <T> T[] array(T... values) {
        return values;
    }

    @SafeVarargs
    public static <T, U extends T> List<T> list(U... values) {
        List<T> ret = new LinkedList<>();
        Collections.addAll(ret, values);

        return ret;
    }

    @SafeVarargs
    public static <U, T extends U> List<T> castList(U... values) {
        List<T> ret = new LinkedList<>();
        for (U value : values) {
            ret.add((T) value);
        }

        return ret;
    }

    @SafeVarargs
    public static <T, U extends T> Set<T> set(U... values) {
        Set<T> ret = new LinkedHashSet<>();
        Collections.addAll(ret, values);

        return ret;
    }

    @SafeVarargs
    public static <T, U extends T> Set<T> sortedSet(U... values) {
        Set<T> ret = new TreeSet<>();
        Collections.addAll(ret, values);

        return ret;
    }

    @SafeVarargs
    public static <T extends Enum<T>> EnumSet<T> enumSet(Class<T> tClass, T... values) {
        return values.length > 0 ? EnumSet.copyOf(CollectionTools.<T, T>list(values)) : EnumSet.noneOf(tClass);
    }

    public static <T> List<T> copy(List<T> base) {
        return base != null ? new ArrayList<>(base) : new ArrayList<T>();
    }

    public static <T, U extends T> List<T> copyLinked(List<U> base) {
        return base != null ? new LinkedList<T>(base) : new LinkedList<T>();
    }

    public static <T> Set<T> copy(Set<T> base) {
        return base != null ? new HashSet<>(base) : new HashSet<T>();
    }

    public static <T> Set<T> copyLinked(Set<T> base) {
        return base != null ? new LinkedHashSet<>(base) : new LinkedHashSet<T>();
    }

    public static <K, V> Map<K, V> copy(Map<K, V> base) {
        return base != null ? new HashMap<>(base) : new HashMap<K, V>();
    }

    public static <K, V> Map<K, V> copyLinked(Map<K, V> base) {
        return base != null ? new LinkedHashMap<>(base) : new LinkedHashMap<K, V>();
    }

    public static <K, V> Map<K, V> map(K[] keys, V[] values) {
        Map<K, V> ret = new LinkedHashMap<>();

        for (int i = 0; i < keys.length; ++i) {
            ret.put(keys[i], values[i]);
        }

        return ret;
    }

    public static <K, V> Map<K, V> map(Collection<K> keys, Collection<V> values) {
        Map<K, V> ret = new LinkedHashMap<>();
        Iterator<K> key = keys.iterator();
        Iterator<V> value = values.iterator();
        while (key.hasNext() && value.hasNext()) {
            ret.put(key.next(), value.next());
        }

        return ret;
    }

    @SafeVarargs
    public static <K, V> Map<K, V> map(Pair<K, V>... pairs) {
        Map<K, V> ret = new LinkedHashMap<>();

        for (Pair<K, V> pair : pairs) {
            ret.put(pair.first, pair.second);
        }

        return ret;
    }

    @SafeVarargs
    public static <T> Collection<T> collect(Collection<? extends T>... collections) {
        Collection<T> ret = new LinkedList<>();

        for (Collection<? extends T> collection : collections) {
            ret.addAll(collection);
        }

        return ret;
    }

    @SafeVarargs
    public static <T, U extends T> Collection<T> collect(U[]... collections) {
        Collection<T> ret = new LinkedList<>();

        for (U[] collection : collections) {
            Collections.addAll(ret, collection);
        }

        return ret;
    }

    @SafeVarargs
    public static <T> Collection<T> add(Collection<T> collection, T... values) {
        Collections.addAll(collection, values);
        return collection;
    }

    public static <T extends Comparable<? super T>> List<T> sort(List<T> values) {
        Collections.sort(values);
        return values;
    }

    public static <T> List<T> sort(List<T> values, Comparator<? super T> c) {
        Collections.sort(values, c);
        return values;
    }

    public static <T extends Comparable<? super T>> List<T> sort(Collection<T> values) {
        return sort(new ArrayList<T>(values));
    }

    public static <T> List<T> sort(Collection<T> values, Comparator<? super T> c) {
        return sort(new ArrayList<T>(values), c);
    }

    private CollectionTools() {
    }
}
