package restx.factory;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* Date: 16/11/13
* Time: 21:24
*/
public class WarehouseProvidersMachine implements FactoryMachine {
private final ImmutableList<Warehouse> providers;
public WarehouseProvidersMachine(ImmutableList<Warehouse> providers) {
this.providers = providers;
}
@Override
@SuppressWarnings("unchecked")
public boolean canBuild(Name<?> name) {
for (Warehouse provider : providers) {
if (Iterables.tryFind(provider.listNames(),
(Predicate<? super Name<?>>) Predicates.equalTo(name)).isPresent()) {
return true;
}
}
return false;
}
@Override
public <T> MachineEngine<T> getEngine(final Name<T> name) {
final Optional<NamedComponent<T>> component = findComponent(name);
if (!component.isPresent()) {
throw new IllegalArgumentException("can't build " + name);
}
final BillOfMaterials bom = findBomFor(name);
return new MachineEngine<T>() {
@Override
public Name<T> getName() {
return name;
}
@Override
public int getPriority() {
return component.get().getPriority();
}
@Override
public BillOfMaterials getBillOfMaterial() {
return bom;
}
@Override
public ComponentBox<T> newComponent(SatisfiedBOM satisfiedBOM) {
throw new UnsupportedOperationException(
"WarehouseProvidersMachine Engine should never be used to actually build components, " +
"they should be picked up in the warehouse directly.");
}
@Override
public String toString() {
return WarehouseProvidersMachine.this.toString() + "Engine";
}
};
}
private <T> BillOfMaterials findBomFor(Name<T> name) {
for (Warehouse provider : providers) {
Optional<Warehouse.StoredBox<T>> storedBox = provider.getStoredBox(name);
if (storedBox.isPresent()) {
return storedBox.get().getSatisfiedBOM().getBom();
}
}
throw new IllegalArgumentException("name not found " + name);
}
private <T> Optional<NamedComponent<T>> findComponent(Name<T> name) {
for (Warehouse provider : providers) {
Optional<NamedComponent<T>> componentOptional = provider.checkOut(name);
if (componentOptional.isPresent()) {
return componentOptional;
}
}
return Optional.absent();
}
@Override
@SuppressWarnings("unchecked")
public <T> Set<Name<T>> nameBuildableComponents(Class<T> componentClass) {
Set<Name<T>> names = new LinkedHashSet<>();
for (Warehouse provider : providers) {
for (Name<?> name : provider.listNames()) {
if (componentClass.isAssignableFrom(name.getClazz())) {
names.add((Name<T>) name);
}
}
}
return names;
}
@Override
public int priority() {
return -10000;
}
@Override
public String toString() {
return "WarehouseProvidersMachine{" +
"providers=" + providers +
'}';
}
}