public static ManuQuote calculateQuote(
      Blueprint b,
      int runs,
      ManuQuote oldQuote,
      PriceDB pdb,
      BlueprintDB bdb,
      Preferences prefs,
      MatAcquirePriority mPrio) {

    // ---Skills and modifiers---
    // Apply skills, implant and slotModifier.
    double time =
        b.getManuTime()
            * (1 - (0.04 * SKILL_LEVEL_VALUE[prefs.getSkillLvlIndex(Skill.INDUSTRY)]))
            * MOD_IMPLANT_VALUE[prefs.getImplantModIndex(ImplantMod.MOD_PE)]
            * MOD_SLOT_VALUE[prefs.getInstallationModIndex(InstallationMod.SLOT_MOD_PE)];

    // Finalize time calculation.
    if ((b.getProductivityMod() / ((double) b.getManuTime())) <= 1) {
      if (b.getPe() >= 0) {

        time *=
            (1
                - ((b.getProductivityMod() / ((double) b.getManuTime()))
                    * (b.getPe() / ((double) (1 + b.getPe())))));
      } else {

        time *= (1 - ((b.getProductivityMod() / ((double) b.getManuTime())) * (b.getPe() - 1)));
      }
    }

    double cost = 0, income = 0;
    // Base material list.
    ArrayList<Material> bML = new ArrayList<>();
    // Extra material list.
    ArrayList<Material> eML = new ArrayList<>();
    // Extra material recycle list.
    ArrayList<Material> eMRL = new ArrayList<>();
    double amount;
    double afterRecycleAmount;

    // Divide the extra materials.
    for (Material m : b.getExtraMaterials()) {

      // Check if base materials already has a entry for the material.
      if (m.isRecycled()) {
        // Add to subtraction-list if item is recycled.
        for (Material m1 : m.getItem().getBaseMaterials()) {
          eMRL.add(new Material(m1.getItem(), m1.getAmount()));
        }
      }
      // Add skill waste.
      eML.add(
          new Material(
              m.getItem(),
              (m.getAmount()
                  + (int)
                      ((((25
                                      - (5
                                          * SKILL_LEVEL_VALUE[
                                              prefs.getSkillLvlIndex(Skill.PRODUCTION_EFFICIENCY)]))
                                  * m.getAmount())
                              / 100)
                          + 0.5))));
    }

    // Calculate the correct amount of base materials including, skill and Me-based waste.
    for (Material m : b.getProduct().getBaseMaterials()) {

      afterRecycleAmount = m.getAmount();

      // Remove recycled amount.
      if (eMRL.contains(m)) {
        afterRecycleAmount -= eMRL.get(eMRL.indexOf(m)).getAmount();
        // Material amount can't be lower than 0.
        if (afterRecycleAmount < 0) {
          // Don't add the material, recycle has covered the amount.
          continue;
        }
      }

      // Set base.
      amount = afterRecycleAmount;

      // Add skill waste.
      amount +=
          (int)
              ((((25 - (5 * SKILL_LEVEL_VALUE[prefs.getSkillLvlIndex(Skill.PRODUCTION_EFFICIENCY)]))
                          * afterRecycleAmount)
                      / 100)
                  + 0.5);

      // Add ME waste.
      if (b.getMe() >= 0) {
        amount +=
            (int)
                ((afterRecycleAmount
                        * ((b.getWasteFactor()) / 100.0)
                        * (1 / (double) (b.getMe() + 1)))
                    + 0.5);

      } else {
        amount +=
            (int) ((afterRecycleAmount * ((b.getWasteFactor()) / 100.0) * (1 - b.getMe())) + 0.5);
      }

      // Apply slot modifier.
      amount *= MOD_SLOT_VALUE[prefs.getInstallationModIndex(InstallationMod.SLOT_MOD_ME)];
      bML.add(new Material(m.getItem(), (amount * runs)));
    }

    // Add extra materials to base-list.
    for (Material m : eML) {
      if (bML.contains(m)) {
        bML.get(bML.indexOf(m))
            .setAmount(bML.get(bML.indexOf(m)).getAmount() + (m.getAmount() * runs));
      } else {
        bML.add(new Material(m.getItem(), m.getAmount() * runs));
      }
    }

    // ---PriceChecks---
    // Calculate the cost for the Materials.
    for (Material m : bML) {
      m.setPrice(MarketCalculator.calculatePrice(Action.BUY, m.getItem().getTypeId(), pdb, prefs));
    }

    // Do pre calculations of cost to decide how to acquire materials.
    for (Material m : bML) {
      cost += m.getPrice() * m.getAmount();
    }
    // Installation cost.
    cost +=
        prefs.getManufacturingCost(ManufacturingCost.INSTALLATION_COST)
            + time * prefs.getManufacturingCost(ManufacturingCost.INSTALLATION_COST_H) / 3600;

    // Income.
    income =
        b.getItemsPerRun()
            * runs
            * MarketCalculator.calculatePrice(Action.SELL, b.getProduct().getTypeId(), pdb, prefs);

    Blueprint tempB;
    // Add special manufacturing prices.
    for (Material m : bML) {
      // Add price to manufacture if applicable, otherwise add null.
      tempB = bdb.getByProductId(m.getItem().getTypeId());
      if (tempB != null) {
        // Set default me/pe levels.
        tempB.setMe(prefs.getBlueprintStat(BlueprintStat.MOD_ME));
        tempB.setPe(prefs.getBlueprintStat(BlueprintStat.MOD_PE));
        m.setManufactureQuote(calculateQuote(tempB, 1, null, pdb, bdb, prefs, mPrio));
        m.setCanBeManufactured(true);
      } else {
        m.setCanBeManufactured(false);
        m.setProduced(false);
        // Leave ManufactureQuote to null.
      }
    }

    // Set which prices to use, checks the values from the "oldQuote".
    if (oldQuote != null) {
      for (Material m1 : bML) {
        for (Material m : oldQuote.getMatList()) {
          if (m1.getItem().equals(m.getItem())) {
            m1.setProduced(m.isProduced());
            break;
          }
        }
      }
    }

    // Set the values that were not set.
    for (Material m : bML) {
      if (m.isProduced() == null) {
        // Overrides priorities, if material can't be bought (price = 0), always produce.
        if (m.getPrice() == 0) {
          m.setProduced(true);
        } else if (mPrio == MatAcquirePriority.PROFIT_MARGIN
            && m.getManufactureQuote().getManuCost() < m.getPrice()) {
          // Set to true if the profit increases by manufacturing the material.
          m.setProduced(true);
        } else if (mPrio == MatAcquirePriority.PROFIT_PER_H_CHAIN
            && ((income - cost) * 3600) / (time * runs)
                < ((m.getPrice() - m.getManufactureQuote().getManuCost())
                    / m.getManufactureQuote().getManuTime().toHours())) {
          // Set to true if the profit/h increases by manufacturing the material in regard to the
          // time it takes.
          m.setProduced(true);
        } else {
          m.setProduced(false);
        }
      }
    }

    // Reset and re-do calculations.
    cost = 0;
    for (Material m : bML) {
      if (m.isProduced()) {
        cost += m.getManufactureQuote().getManuCost() * m.getAmount();
      } else {
        cost += m.getPrice() * m.getAmount();
      }
    }
    // Installation cost.
    cost +=
        prefs.getManufacturingCost(ManufacturingCost.INSTALLATION_COST)
            + time * prefs.getManufacturingCost(ManufacturingCost.INSTALLATION_COST_H) / 3600;

    // Set the T1 BPO market availability.
    boolean seededOnMarket = b.getBlueprintItem().isOnMarket();

    // Create quote.
    ManuQuote ans =
        new ManuQuote(
            b,
            new Time((int) (time + 0.5)),
            cost,
            income,
            income - cost,
            ((income - cost) * 3600) / (time * runs),
            calculateSalesVolumeRatio(b, pdb, time),
            runs,
            bML,
            mPrio,
            MarketCalculator.calculateMarketTrend(Action.SELL, b.getProduct(), pdb, prefs),
            seededOnMarket);

    // Set sustainableProfitValue.
    ans.setSustainableProfitValue(calculateSustainableProfitValue(ans));

    return ans;
  }