/**
  * Checks the cache for a previously generated table meeting the criteria. If none is found,
  * generates it and adds it to the cache.
  *
  * @param faction - The faction for which to generate a table
  * @param unitType - a UnitType constant
  * @param year - the game year
  * @param rating - the unit's equipment rating; if null, the table is not adjusted for unit
  *     rating.
  * @param weightClasses - a collection of EntityWeightClass constants to include in the table; if
  *     null or empty all weight classes are included
  * @param networkMask - a ModelRecord.NETWORK_* constant
  * @param movementModes - the movement modes allowed to appear in the table; if null or empty, no
  *     filtering is applied.
  * @param roles - the roles for which to adjust the availability
  * @param roleStrictness - how rigidly to apply the role adjustments; normal range is <= 4
  * @param deployingFaction - when using the salvage/isorla mechanism, any omni unit will select
  *     the configuration based on the faction actually deploying
  * @return - a table containing the available units and their relative weights
  */
 public static synchronized UnitTable findTable(
     FactionRecord faction,
     int unitType,
     int year,
     String rating,
     Collection<Integer> weightClasses,
     int networkMask,
     Collection<EntityMovementMode> movementModes,
     Collection<MissionRole> roles,
     int roleStrictness,
     FactionRecord deployingFaction) {
   Objects.requireNonNull(faction);
   CacheKey key =
       new CacheKey(
           faction,
           unitType,
           year,
           rating,
           weightClasses,
           networkMask,
           movementModes,
           roles,
           roleStrictness,
           deployingFaction);
   UnitTable retVal = cache.get(key);
   if (retVal == null) {
     retVal = new UnitTable(key);
     if (retVal.hasUnits()) {
       cache.put(key, retVal);
     }
   }
   return retVal;
 }
 /**
  * Selects a faction from the salvage list and generates a table using the same parameters as this
  * table, but from five years earlier. Generated tables are cached for later use. If the generated
  * table contains no units, it is discarded and the selected entry is deleted. This continues
  * until either a unit is generated or there are no remaining entries.
  *
  * @param filter - passed to generateUnit() in the generated table.
  * @return - a unit generated from another faction, or null if none of the factions in the salvage
  *     list contain any units that meet the parameters.
  */
 private MechSummary generateSalvage(UnitFilter filter) {
   while (salvageTotal > 0) {
     int roll = Compute.randomInt(salvageTotal);
     TableEntry salvageEntry = null;
     for (TableEntry te : salvageTable) {
       if (roll < te.weight) {
         salvageEntry = te;
         break;
       }
       roll -= te.weight;
     }
     if (salvageEntry != null) {
       UnitTable salvage =
           UnitTable.findTable(
               salvageEntry.getSalvageFaction(),
               key.getUnitType(),
               key.getYear() - 5,
               key.getRating(),
               key.getWeightClasses(),
               key.getNetworkMask(),
               key.getMovementModes(),
               key.getRoles(),
               key.getRoleStrictness(),
               key.getFaction());
       if (salvage.hasUnits()) {
         return salvage.generateUnit(filter);
       } else {
         salvageTotal -= salvageEntry.weight;
         salvageTable.remove(salvageEntry);
       }
     }
   }
   assert (salvageTable.isEmpty() && salvageTotal == 0);
   return null;
 }