package com.revolsys.collection.list;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;
import com.revolsys.datatype.DataType;
import com.revolsys.datatype.DataTypes;
import com.revolsys.record.io.format.json.JsonParser;
import com.revolsys.util.Property;
public interface Lists {
static final Supplier<List<?>> FACTORY_ARRAY = () -> {
return new ArrayList<>();
};
public static <V> void addAll(final List<V> list, final Iterable<? extends V> values) {
if (values != null) {
for (final V value : values) {
list.add(value);
}
}
}
public static <V> void addAll(final List<V> list, final Stream<? extends V> values) {
if (values != null) {
values.forEach(list::add);
}
}
public static <V> void addAll(final List<V> list,
@SuppressWarnings("unchecked") final V... values) {
if (values != null) {
for (final V value : values) {
list.add(value);
}
}
}
public static <V> void addListsAll(final List<V> list,
final Iterable<? extends Iterable<V>> lists) {
if (lists != null) {
for (final Iterable<V> values : lists) {
for (final V value : values) {
list.add(value);
}
}
}
}
/**
* Add the value to the list if it is not empty and not already in the list.
* @param list
* @param value
* @return
*/
public static <V> boolean addNotContains(final List<V> list, final int index, final V value) {
if (Property.hasValue(value)) {
if (!list.contains(value)) {
list.add(index, value);
return true;
}
}
return false;
}
/**
* Add the value to the list if it is not empty and not already in the list.
* @param list
* @param value
* @return
*/
public static <V> boolean addNotContains(final List<V> list, final V value) {
if (Property.hasValue(value)) {
if (!list.contains(value)) {
return list.add(value);
}
}
return false;
}
/**
* Add the value to the list if it is not empty and not already in the list.
* @param list
* @param value
* @return
*/
public static <V> boolean addNotContainsLast(final List<V> list, final V value) {
if (Property.hasValue(value)) {
if (list.isEmpty() || !list.get(list.size() - 1).equals(value)) {
list.add(value);
return true;
}
}
return false;
}
/**
* Add the value to the list if it is not empty.
* @param list
* @param value
* @return
*/
public static <V> boolean addNotEmpty(final List<V> list, final int index, final V value) {
if (Property.hasValue(value)) {
list.add(index, value);
return true;
} else {
return false;
}
}
/**
* Add the value to the list if it is not empty.
* @param list
* @param value
* @return
*/
public static <V> boolean addNotEmpty(final List<V> list, final V value) {
if (list != null && Property.hasValue(value)) {
return list.add(value);
} else {
return false;
}
}
static List<? extends Object> arrayToList(final Object value) {
final List<Object> list = new ArrayList<>();
if (value instanceof boolean[]) {
for (final Object item : (boolean[])value) {
list.add(item);
}
} else if (value instanceof Object[]) {
for (final Object item : (Object[])value) {
list.add(item);
}
} else if (value instanceof byte[]) {
for (final Object item : (byte[])value) {
list.add(item);
}
} else if (value instanceof short[]) {
for (final Object item : (short[])value) {
list.add(item);
}
} else if (value instanceof int[]) {
for (final Object item : (int[])value) {
list.add(item);
}
} else if (value instanceof long[]) {
for (final Object item : (long[])value) {
list.add(item);
}
} else if (value instanceof float[]) {
for (final Object item : (float[])value) {
list.add(item);
}
} else if (value instanceof double[]) {
for (final Object item : (double[])value) {
list.add(item);
}
} else {
list.add(value);
}
return list;
}
static <T> boolean containsReference(final List<WeakReference<T>> list, final T object) {
for (int i = 0; i < list.size(); i++) {
final WeakReference<T> reference = list.get(i);
final T value = reference.get();
if (value == null) {
list.remove(i);
} else if (value == object) {
return true;
}
}
return false;
}
static boolean equalsNotNull(final List<?> list1, final List<?> list2) {
if (list1.size() != list2.size()) {
return false;
} else {
for (int i = 0; i < list1.size(); i++) {
final Object value1 = list1.get(i);
final Object value2 = list2.get(i);
if (!DataType.equal(value1, value2)) {
return false;
}
}
}
return true;
}
static boolean equalsNotNull(final List<?> list1, final List<?> list2,
final Collection<? extends CharSequence> exclude) {
if (list1.size() != list2.size()) {
return false;
} else {
for (int i = 0; i < list1.size(); i++) {
final Object value1 = list1.get(i);
final Object value2 = list2.get(i);
if (!DataType.equal(value1, value2, exclude)) {
return false;
}
}
}
return true;
}
@SuppressWarnings({
"unchecked", "rawtypes"
})
public static <V> Supplier<List<V>> factoryArray() {
return (Supplier)FACTORY_ARRAY;
}
public static <V> Supplier<List<V>> factoryLinked() {
return () -> {
return new LinkedList<>();
};
}
static int getClassCount(final List<?> list, final Class<?> clazz) {
int count = 0;
for (int i = 0; i < list.size(); i++) {
final Object value = list.get(i);
if (value == null) {
list.remove(i);
} else if (clazz.isAssignableFrom(value.getClass())) {
count++;
}
}
return count++;
}
static <T> int getReferenceClassCount(final List<WeakReference<T>> list, final Class<?> clazz) {
int count = 0;
for (int i = 0; i < list.size(); i++) {
final WeakReference<?> reference = list.get(i);
final Object value = reference.get();
if (value == null) {
list.remove(i);
} else if (clazz.isAssignableFrom(value.getClass())) {
count++;
}
}
return count++;
}
static <T> List<T> getReferences(final List<WeakReference<T>> list) {
final List<T> values = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
final WeakReference<T> reference = list.get(i);
final T value = reference.get();
if (value == null) {
list.remove(i);
} else {
values.add(value);
}
}
return values;
}
public static <V> LinkedList<V> linked(@SuppressWarnings("unchecked") final V... values) {
final LinkedList<V> list = new LinkedList<>();
addAll(list, values);
return list;
}
public static <V> List<V> newArray(final BiConsumer<Consumer<V>, Predicate<V>> forEachFunction,
final Predicate<V> filter) {
final List<V> values = new ArrayList<>();
forEachFunction.accept(values::add, filter);
return values;
}
public static <V> ArrayList<V> newArray(final Consumer<Consumer<V>> action) {
final ArrayList<V> list = new ArrayList<>();
action.accept(list::add);
return list;
}
static List<Double> newArray(final double... values) {
if (values == null) {
return Collections.emptyList();
} else {
final List<Double> list = new ArrayList<>();
for (final double value : values) {
list.add(value);
}
return list;
}
}
static List<Integer> newArray(final int... values) {
if (values == null) {
return Collections.emptyList();
} else {
final List<Integer> list = new ArrayList<>();
for (final int value : values) {
list.add(value);
}
return list;
}
}
public static <V> ArrayList<V> newArray(@SuppressWarnings("unchecked") final V... values) {
final ArrayList<V> list = new ArrayList<>();
addAll(list, values);
return list;
}
public static <V> List<V> newArraySorted(
final BiConsumer<Consumer<V>, Predicate<V>> forEachFunction, final Predicate<V> filter,
final Comparator<V> comparator) {
final List<V> values = new ArrayList<>();
forEachFunction.accept(values::add, filter);
values.sort(comparator);
return values;
}
static <T> void removeReference(final List<WeakReference<T>> list, final T object) {
for (int i = 0; i < list.size(); i++) {
final WeakReference<T> reference = list.get(i);
final T value = reference.get();
if (value == null) {
list.remove(i);
} else if (value == object) {
list.remove(i);
}
}
}
static List<String> split(final String text, final String regex) {
if (Property.hasValue(text)) {
return Arrays.asList(text.split(regex));
} else {
return Collections.emptyList();
}
}
public static <V> List<V> to(final Supplier<List<V>> factory,
final Iterable<? extends V> values) {
final List<V> list = factory.get();
addAll(list, values);
return list;
}
public static <V> List<V> toArray(final Iterable<? extends V> values) {
final List<V> list = new ArrayList<>();
addAll(list, values);
return list;
}
static <T> List<T> toArray(final Iterable<T> iterable, final int size) {
final List<T> list = new ArrayList<>(size);
int i = 0;
for (final T value : iterable) {
if (i < size) {
list.add(value);
i++;
} else {
return list;
}
}
return list;
}
@SuppressWarnings({
"unchecked", "rawtypes"
})
static <V> List<V> toArray(final Object value) {
if (value == null) {
return null;
} else if (value instanceof List) {
return (List)value;
} else if (value instanceof Iterable) {
final Iterable<Object> iterable = (Iterable)value;
return (List<V>)toArray(iterable);
} else if (value instanceof Number) {
final List<V> list = new ArrayList<>();
list.add((V)value);
return list;
} else {
final String string = DataTypes.toString(value);
return toArray(string);
}
}
public static <V> List<V> toArray(final Stream<? extends V> values) {
final List<V> list = new ArrayList<>();
addAll(list, values);
return list;
}
@SuppressWarnings("unchecked")
static <V> List<V> toArray(final String string) {
final Object value = JsonParser.read(string);
if (value instanceof List) {
return (List<V>)value;
} else {
throw new IllegalArgumentException("Value must be a JSON list " + string);
}
}
public static <V> List<V> toArrayThreadSafe(final List<? extends V> values) {
final List<V> list = new ArrayList<>();
addAll(list, new ListByIndexIterator<>(values));
return list;
}
static String toString(final Object value) {
final Collection<?> collection;
if (value instanceof Collection) {
collection = (Collection<?>)value;
} else {
collection = toArray(value);
}
if (value == null) {
return null;
} else {
final StringBuilder string = new StringBuilder("[");
for (final Iterator<?> iterator = collection.iterator(); iterator.hasNext();) {
final Object object = iterator.next();
final String stringValue = DataTypes.toString(object);
string.append(stringValue);
if (iterator.hasNext()) {
string.append(", ");
}
}
string.append("]");
return string.toString();
}
}
public static <V> List<V> unmodifiable(final Iterable<? extends V> values) {
return new UnmodifiableArrayList<>(values);
}
public static <V> List<V> unmodifiable(@SuppressWarnings("unchecked") final V... values) {
return new UnmodifiableArrayList<>(values);
}
}