package br.com.caelum.iogi.parameters; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Set; import br.com.caelum.iogi.reflection.ClassConstructor; import br.com.caelum.iogi.reflection.Target; import com.google.common.base.Joiner; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimaps; import com.google.common.collect.Sets; import com.google.common.collect.Sets.SetView; public class Parameters { private final ListMultimap<String, Parameter> parametersByFirstNameComponent; public Parameters(final Parameter... parameters) { this(Arrays.asList(parameters)); } public Parameters(final List<Parameter> parametersList) { this.parametersByFirstNameComponent = groupByFirstNameComponent(parametersList); } private ListMultimap<String, Parameter> groupByFirstNameComponent(final List<Parameter> parameters) { final ListMultimap<String, Parameter> firstNameComponentToParameterMap = ArrayListMultimap.create(); for (final Parameter parameter : parameters) { firstNameComponentToParameterMap.put(parameter.getFirstNameComponent(), parameter); } return Multimaps.unmodifiableListMultimap(firstNameComponentToParameterMap); } public List<Parameter> forTarget(final Target<?> target) { return parametersByFirstNameComponent.get(target.getName()); } public Parameter namedAfter(final Target<?> target) { final Collection<Parameter> named = parametersByFirstNameComponent.get(target.getName()); assertFoundAtMostOneTarget(target, named); return named.isEmpty() ? new Parameter(target.getName(), ""): named.iterator().next(); } private void assertFoundAtMostOneTarget(final Target<?> target, final Collection<Parameter> named) { if (named.size() > 1) throw new IllegalStateException( "Expecting only one parameter named after " + target + ", found instead " + named); } public Parameters focusedOn(final Target<?> target) { final List<Parameter> relevantParameters = forTarget(target); final List<Parameter> striped = Lists.newArrayListWithCapacity(relevantParameters.size()); for (final Parameter parameter : relevantParameters) { striped.add(parameter.strip()); } return new Parameters(striped); } public Parameters notUsedBy(final ClassConstructor aConstructor) { final SetView<String> namesNotUsedBy = Sets.difference(firstComponents(), aConstructor.getNames()); final List<Parameter> unusedParameters = new ArrayList<Parameter>(); for (final String name : namesNotUsedBy) { unusedParameters.addAll(parametersByFirstNameComponent.get(name)); } return new Parameters(unusedParameters); } private Set<String> firstComponents() { return this.parametersByFirstNameComponent.keySet(); } public boolean hasRelatedTo(final Target<?> target) { return !forTarget(target).isEmpty(); } public String signatureString() { return "(" + Joiner.on(", ").join(getParametersList()) + ")"; } @Override public String toString() { return "Parameters" + signatureString(); } @Override public int hashCode() { return this.parametersByFirstNameComponent.hashCode(); } @Override public boolean equals(final Object obj) { if (!(obj instanceof Parameters)) return false; final Parameters other = (Parameters)obj; return this.parametersByFirstNameComponent.equals(other.parametersByFirstNameComponent); } /* The only reason this is not private is to help unit tests. */ Collection<Parameter> getParametersList() { return this.parametersByFirstNameComponent.values(); } }