package io.cattle.platform.allocator.dao.impl;
import io.cattle.platform.allocator.service.AllocationCandidate;
import io.cattle.platform.object.ObjectManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AllocationCandidateIterator implements Iterator<AllocationCandidate> {
private static final Logger log = LoggerFactory.getLogger(AllocationCandidateIterator.class);
List<Long> volumeIds;
Iterator<CandidateHostInfo> iterator;
Stack<AllocationCandidate> candidates = new Stack<AllocationCandidate>();
ObjectManager objectManager;
public AllocationCandidateIterator(ObjectManager objectManager, List<CandidateHostInfo> hostInfos, List<Long> volumeIds) {
super();
this.objectManager = objectManager;
this.iterator = hostInfos.iterator();
this.volumeIds = volumeIds;
}
@Override
public boolean hasNext() {
if (candidates.size() > 0) {
return true;
}
return readNext();
}
protected boolean readNext() {
if (iterator.hasNext()) {
CandidateHostInfo hostInfo = iterator.next();
enumerate(hostInfo);
}
return candidates.size() > 0;
}
protected void enumerate(CandidateHostInfo hostInfo) {
log.debug("Enumerating canditates hostId [{}] pools {}", hostInfo.getHostId(), hostInfo.getPoolIds());
Long candidateHostId = hostInfo.getHostId();
Map<Pair<Class<?>, Long>, Object> cache = new HashMap<Pair<Class<?>, Long>, Object>();
if (volumeIds.size() == 0) {
pushCandidate(new AllocationCandidate(objectManager, cache, candidateHostId, hostInfo.getHostUuid(), hostInfo.getUsedPorts(),
Collections.<Long, Long> emptyMap()));
}
for (List<Pair<Long, Long>> pairs : traverse(volumeIds, hostInfo.getPoolIds())) {
Map<Long, Long> volumeToPool = new HashMap<Long, Long>();
for (Pair<Long, Long> pair : pairs) {
volumeToPool.put(pair.getLeft(), pair.getRight());
}
pushCandidate(new AllocationCandidate(objectManager, cache, candidateHostId, hostInfo.getHostUuid(), hostInfo.getUsedPorts(), volumeToPool));
}
}
protected void pushCandidate(AllocationCandidate candidate) {
candidates.push(candidate);
}
public static <L, R> List<List<Pair<L, R>>> traverse(List<L> lefts, Set<R> rights) {
Stack<Pair<L, R>> pairSet = new Stack<Pair<L, R>>();
List<List<Pair<L, R>>> pairSets = new ArrayList<List<Pair<L, R>>>();
traverse(lefts, rights, 0, pairSet, pairSets);
return pairSets;
}
// Writing this code made me feel very stupid. There has got be a simpler
// way of doing this.
public static <L, R> void traverse(List<L> lefts, Set<R> rights, int i, Stack<Pair<L, R>> pairSet, List<List<Pair<L, R>>> pairSets) {
if (i == lefts.size()) {
pairSets.add(new ArrayList<Pair<L, R>>(pairSet));
return;
}
L left = lefts.get(i);
for (R right : rights) {
pairSet.push(new ImmutablePair<L, R>(left, right));
traverse(lefts, rights, i + 1, pairSet, pairSets);
pairSet.pop();
}
}
@Override
public AllocationCandidate next() {
return candidates.pop();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}