package tc.oc.pgm.compose;
import java.util.List;
import javax.inject.Inject;
import com.google.common.collect.Range;
import org.jdom2.Element;
import tc.oc.pgm.filters.matcher.StaticFilter;
import tc.oc.pgm.filters.parser.FilterParser;
import tc.oc.pgm.xml.InvalidXMLException;
import tc.oc.pgm.xml.parser.ElementParser;
import tc.oc.pgm.xml.parser.ElementListParser;
import tc.oc.pgm.xml.property.PropertyBuilderFactory;
import static tc.oc.commons.core.exception.LambdaExceptionUtils.rethrowFunction;
/**
* Parses a {@link Composition<T>} using an injected {@link ElementParser<T>}
*/
public class CompositionParser<T> implements ElementListParser<Composition<T>> {
@Inject private ElementParser<T> elementParser;
@Inject private PropertyBuilderFactory<Boolean, ?> booleans;
@Inject private PropertyBuilderFactory<Double, ?> doubles;
@Inject private PropertyBuilderFactory<Range<Integer>, ?> integerRanges;
@Inject private FilterParser filterParser;
@Override
public Composition<T> parseElementList(List<Element> elements) throws InvalidXMLException {
switch(elements.size()) {
case 0: return new None<>();
case 1: return parseAtom(elements.get(0));
default: return new All<>(elements.stream().map(rethrowFunction(this::parseAtom)));
}
}
public Composition<T> parseAtom(Element element) throws InvalidXMLException {
switch(element.getName()) {
case "none":
return new None<>();
case "maybe":
return new Maybe<>(filterParser.property(element).required(),
parseElement(element));
case "all":
return parseElement(element);
case "any":
return new Any<>(integerRanges.property(element, "count")
.optional(Range.singleton(1)),
booleans.property(element, "unique")
.optional(true),
element.getChildren()
.stream()
.map(rethrowFunction(this::parseOption)));
default:
return new Unit<>(elementParser.parseElement(element));
}
}
Any.Option<T> parseOption(Element element) throws InvalidXMLException {
if("option".equals(element.getName())) {
return new Any.Option<>(doubles.property(element, "weight").optional(1D),
filterParser.property(element).optional(StaticFilter.ALLOW),
parseElement(element));
} else {
return new Any.Option<>(1, StaticFilter.ALLOW, parseAtom(element));
}
}
}