private static Set<Flavor> recursiveReplacements(Flavor flavor, Set<Flavor> replacements) { replacements.add(flavor); for (Flavor replaces : flavor.replaces()) { recursiveReplacements(replaces, replacements); } return replacements; }
public static Map<Flavor, FlavorSpareCount> constructFlavorSpareCountGraph(List<Flavor> flavors) { Map<Flavor, FlavorSpareCount> spareCountByFlavor = new HashMap<>(); Map<Flavor, Set<Flavor>> immediateReplaceeFlavorsByFlavor = new HashMap<>(); for (Flavor flavor : flavors) { for (Flavor replaces : flavor.replaces()) { if (! immediateReplaceeFlavorsByFlavor.containsKey(replaces)) { immediateReplaceeFlavorsByFlavor.put(replaces, new HashSet<>()); } immediateReplaceeFlavorsByFlavor.get(replaces).add(flavor); } spareCountByFlavor.put(flavor, new FlavorSpareCount(flavor)); } spareCountByFlavor.forEach((flavor, flavorSpareCount) -> { flavorSpareCount.immediateReplacees = ! immediateReplaceeFlavorsByFlavor.containsKey(flavor) ? Collections.emptySet() : immediateReplaceeFlavorsByFlavor.get(flavor).stream().map(spareCountByFlavor::get).collect(Collectors.toSet()); flavorSpareCount.possibleWantedFlavors = recursiveReplacements(flavor, new HashSet<>()) .stream().map(spareCountByFlavor::get).collect(Collectors.toSet()); }); return spareCountByFlavor; }
private static Collection<Flavor> toFlavors(FlavorsConfig config) { Map<String, Flavor> flavors = new HashMap<>(); // First pass, create all flavors, but do not include flavorReplacesConfig. for (FlavorsConfig.Flavor flavorConfig : config.flavor()) { flavors.put(flavorConfig.name(), new Flavor(flavorConfig)); } // Second pass, set flavorReplacesConfig to point to correct flavor. for (FlavorsConfig.Flavor flavorConfig : config.flavor()) { Flavor flavor = flavors.get(flavorConfig.name()); for (FlavorsConfig.Flavor.Replaces flavorReplacesConfig : flavorConfig.replaces()) { if (! flavors.containsKey(flavorReplacesConfig.name())) { throw new IllegalStateException("Replaces for " + flavor.name() + " pointing to a non existing flavor: " + flavorReplacesConfig.name()); } flavor.replaces().add(flavors.get(flavorReplacesConfig.name())); } flavor.freeze(); } // Third pass, ensure that retired flavors have a replacement for (Flavor flavor : flavors.values()) { if (flavor.isRetired() && !hasReplacement(flavors.values(), flavor)) { throw new IllegalStateException( String.format("Flavor '%s' is retired, but has no replacement", flavor.name()) ); } } return flavors.values(); }