package br.com.caelum.iogi.collections;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
import br.com.caelum.iogi.Instantiator;
import br.com.caelum.iogi.parameters.Parameter;
import br.com.caelum.iogi.parameters.Parameters;
import br.com.caelum.iogi.reflection.Target;
import br.com.caelum.iogi.util.Assert;
import com.google.common.collect.Lists;
public class CyclingListInstantiator implements Instantiator<List<Object>> {
private final Instantiator<Object> elementInstantiator;
public CyclingListInstantiator(final Instantiator<Object> objectInstantiator) {
this.elementInstantiator = objectInstantiator;
}
public boolean isAbleToInstantiate(final Target<?> target) {
return target.getClassType().isAssignableFrom(List.class);
}
public List<Object> instantiate(final Target<?> target, final Parameters parameters) {
Assert.isNotARawType(target);
final Target<Object> listElementTarget = target.typeArgument(0);
final Collection<List<Parameter>> parameterLists = breakList(parameters.forTarget(target));
final ArrayList<Object> newList = Lists.newArrayListWithExpectedSize(parameterLists.size());
for (final List<Parameter> parameterListForAnElement : parameterLists) {
final Object listElement = elementInstantiator.instantiate(listElementTarget, new Parameters(parameterListForAnElement));
newList.add(listElement);
}
return newList;
}
private Collection<List<Parameter>> breakList(final List<Parameter> parameters) {
if (parameters.isEmpty())
return Collections.emptyList();
final int listSize = countToFirstRepeatedParameterName(parameters);
return Lists.partition(parameters, listSize);
}
private int countToFirstRepeatedParameterName(final List<Parameter> parameters) {
int count = 1;
final ListIterator<Parameter> parametersIterator = parameters.listIterator();
final String firstParameterName = parametersIterator.next().getName();
while (parametersIterator.hasNext()) {
if (parametersIterator.next().getName().equals(firstParameterName)) {
break;
}
count++;
}
return count;
}
}