package net.hamnaberg.json;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javaslang.control.Option;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import net.hamnaberg.json.util.Iterables;
public final class Data implements Iterable<Property> {
private final List<Property> properties;
public static Map<String, Property> getDataAsMap(Iterable<Property> properties) {
return Collections.unmodifiableMap(
StreamSupport.stream(properties.spliterator(), false).
collect(Collectors.toMap(Property::getName, Function.<Property>identity()))
);
}
public Data(Iterable<Property> props) {
properties = Option.of(props)
.map(x -> StreamSupport.stream(x.spliterator(), false).collect(Collectors.toList()))
.getOrElseThrow(() -> new IllegalArgumentException("Properties in Data may not be null"));
}
public boolean isEmpty() {
return properties.isEmpty();
}
public Map<String, Property> getDataAsMap() {
return getDataAsMap(properties);
}
public Option<Property> findProperty(Predicate<Property> predicate) {
return Option.ofOptional(properties.stream().filter(predicate).findFirst());
}
public Option<Property> propertyByName(final String name) {
return findProperty(input -> name.equals(input.getName()));
}
public Option<Property> get(int index) {
int count = 0;
for (Property property : properties) {
if (index == count) {
return Option.of(property);
}
count++;
}
return Option.none();
}
/**
* Replaces all properties with the same name as the supplied properties.
*
* @param replacement property to replace with
* @return a new copy of the template
*/
public Data replace(Iterable<Property> replacement) {
if (Iterables.isEmpty(replacement)) {
return this;
}
Map<String, Property> map = getDataAsMap(replacement);
List<Property> props = this.stream().
map(f -> map.getOrDefault(f.getName(), f)).
collect(Collectors.toList());
return new Data(props);
}
/**
* Replaces all properties with the same name as the supplied property
*
* @param property property to replace with
* @return a new copy of the template, or this if nothing was modified.
*/
public Data replace(Property property) {
return replace(Collections.singletonList(property));
}
/**
* Adds a property to the data.
*
* @param property the property to add
* @return a new copy of the template.
*/
public Data add(Property property) {
return addAll(Collections.singletonList(property));
}
/**
* Adds properties to the data.
*
* @param toAdd the properties to add
* @return a new copy of the template.
*/
public Data addAll(Iterable<Property> toAdd) {
return !Iterables.isEmpty(toAdd)
? new Data(Stream.concat(properties.stream(), StreamSupport.stream(toAdd.spliterator(), false)).collect(Collectors.toList()))
: this;
}
/**
* Replaces all properties.
*
* @param props the property to add
* @return a new copy of the template.
*/
public Data set(Iterable<Property> props) {
return !Iterables.isEmpty(props)
? new Data(props)
: this;
}
@Override
public String toString() {
return properties.toString();
}
@Override
public Iterator<Property> iterator() {
return properties.iterator();
}
public Stream<Property> stream() {return StreamSupport.stream(spliterator(), false); }
}