package com.codepoetics.octarine.functional.paths;
import com.codepoetics.octarine.functional.extractors.Extractor;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
public interface Path<T, V> extends Extractor.FromPartial<T, V> {
static <T, V> Named<T, V> to(Function<T, Optional<V>> f, String name) {
return new Named<>(name, f);
}
static <V> Indexed<Integer, List<V>, V> toIndex(int index) {
return new Indexed<>(index, vs -> index < vs.size() ? Optional.ofNullable(vs.get(index)) : Optional.empty());
}
static <K, V> Indexed<K, Map<K, V>, V> toKey(K key) {
return new Indexed<>(key, kvMap -> Optional.ofNullable(kvMap.get(key)));
}
void describe(StringBuilder sb);
default String describe() {
StringBuilder sb = new StringBuilder();
describe(sb);
return sb.toString();
}
default <V2> Path<T, V2> join(Path<? super V, V2> next) {
return new Path<T, V2>() {
@Override
public void describe(StringBuilder sb) {
Path.this.describe(sb);
next.describe(sb);
}
@Override
public Optional<V2> apply(T t) {
Optional<V> v = Path.this.apply(t);
if (v.isPresent()) {
return next.apply(v.get());
}
return Optional.empty();
}
};
}
final static class Indexed<I, T, V> implements Path<T, V> {
private final I index;
private final Function<T, Optional<V>> f;
private Indexed(I index, Function<T, Optional<V>> f) {
this.index = index;
this.f = f;
}
public I index() {
return index;
}
public Optional<V> apply(T value) {
return f.apply(value);
}
@Override
public void describe(StringBuilder sb) {
sb.append("[").append(index).append("]");
}
}
final static class Named<T, V> implements Path<T, V> {
private final String name;
private final Function<T, Optional<V>> f;
private Named(String name, Function<T, Optional<V>> f) {
this.name = name;
this.f = f;
}
public String name() {
return name;
}
@Override
public Optional<V> apply(T value) {
return f.apply(value);
}
@Override
public void describe(StringBuilder sb) {
if (sb.length() > 0) {
sb.append(".");
}
sb.append(name);
}
}
}