package net.tomatentum.cutin.container; import java.lang.reflect.Method; import java.util.Collection; import java.util.HashSet; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.tomatentum.cutin.ReflectedMethod; import net.tomatentum.cutin.ReflectedMethodFactory; import net.tomatentum.cutin.util.ReflectionUtil; public class MultiMethodContainer implements MethodContainer { private Set> entries; private ReflectedMethodFactory factory; public MultiMethodContainer(ReflectedMethodFactory factory) { this.entries = new HashSet<>(); this.factory = factory; } @Override public MethodContainer addMethod(ReflectedMethod method) { Optional> oentry = this.entries.stream() .filter(e -> method.identifier().equals(e.identifier())) .findFirst(); Entry entry = oentry.orElse(new Entry<>(method.identifier())).addMethod(method); if (oentry.isEmpty()) this.entries.add(entry); return this; } @Override public MethodContainer addMethods(Object containingObject, Method... methods) { for (Method method : methods) this.factory.produce(method, containingObject) .ifPresent(this::addMethod); return this; } @Override public Set identifiers() { return entries().stream() .map(Entry::identifier) .collect(Collectors.toSet()); } @Override public Collection> methods() { return this.entries.stream() .flatMap(e -> e.methods.stream()) .toList(); } @Override public Collection> findFor(I identifier) { return this.entries.stream() .filter(e -> e.identifier().equals(identifier)) .flatMap(e -> e.methods.stream()) .toList(); } @Override public Optional> findFirstFor(I identifier) { return this.entries.stream() .filter(e -> e.identifier().equals(identifier)) .flatMap(e -> e.methods.stream()) .findFirst(); } protected Set> entries() { return this.entries; } public static record Entry(I identifier, Set> methods) { public Entry(I identifier) { this(identifier, new HashSet<>()); } private static Logger logger = LoggerFactory.getLogger(Entry.class); public Entry addMethod(ReflectedMethod method) { I midentifier = method.identifier(); if (!this.identifier().equals(midentifier)) throw new IllegalArgumentException("Method's identifier did not equal the entry's identifier"); this.methods.add(method); logger.debug("Added method {} to entry {}", method.method().getName(), this); return this; } public Object[] runAll(Object context) { logger.trace("Running all Methods from {} with context {}", this, context); return this.methods.stream() .map(x -> { logger.debug("Running Method {} from {} with context {}", x, this, context); return x.run(context); }) .flatMap(ReflectionUtil::getReturnAsStream) .toArray(); } @Override public boolean equals(Object obj) { if (!(obj instanceof Entry)) return false; Entry other = (Entry) obj; return other.identifier().equals(identifier()); } @Override public int hashCode() { return this.identifier().hashCode(); } @Override public String toString() { return "Content(%s)".formatted(identifier().toString()); } } }