/**
   * Adjusts the number of units and the amounts if the total is different from the transaction line
   * units. The correction will be done on the oldest tax lot. This method is specific to the Asset
   * Decrease document and is used in updateTaxLotsForSubTypeNonCashAndTransAmtNonZero().
   *
   * @param transLine
   * @param keepIntegers
   */
  private void adjustUnitsAndAmountsForNonCashAndTransactionAmtNotZero(
      EndowmentTransactionLine transLine) {
    // Adjust the number of units if the total is different from the transaction line units
    BigDecimal totalComputedTaxLotUnits = BigDecimal.ZERO;
    BigDecimal totalComputedCost = BigDecimal.ZERO;
    EndowmentTransactionTaxLotLine oldestTaxLotLine = null;

    if (transLine.getTaxLotLines() != null && transLine.getTaxLotLines().size() > 0) {
      for (EndowmentTransactionTaxLotLine taxLotLine : transLine.getTaxLotLines()) {
        BigDecimal lotUnits = taxLotLine.getLotUnits().negate();

        // calculate the total number of units to be decreased
        totalComputedTaxLotUnits = totalComputedTaxLotUnits.add(lotUnits);
        totalComputedCost = totalComputedCost.add(taxLotLine.getLotHoldingCost().negate());

        if (taxLotLine.getLotShortTermGainLoss() != null) {
          totalComputedCost = totalComputedCost.add(taxLotLine.getLotShortTermGainLoss());
        }

        if (taxLotLine.getLotLongTermGainLoss() != null) {
          totalComputedCost = totalComputedCost.add(taxLotLine.getLotLongTermGainLoss());
        }

        // keep the tax lot with the oldest acquired date so that we can adjust the units for that
        // one in case the
        // number of units needs and adjustment
        if (oldestTaxLotLine != null) {
          if (oldestTaxLotLine.getLotAcquiredDate().after(taxLotLine.getLotAcquiredDate())) {
            oldestTaxLotLine = taxLotLine;
          }
        } else {
          oldestTaxLotLine = taxLotLine;
        }
      }
    }

    // compare with the negated number of units on the transaction line because the units on the tax
    // lots have been negated
    if (totalComputedTaxLotUnits.compareTo(
            transLine.getTransactionUnits().bigDecimalValue().negate())
        != 0) {
      BigDecimal difUnits =
          transLine.getTransactionUnits().bigDecimalValue().subtract(totalComputedTaxLotUnits);
      oldestTaxLotLine.setLotUnits(oldestTaxLotLine.getLotUnits().add(difUnits.negate()));

      BigDecimal difAmount =
          transLine.getTransactionAmount().bigDecimalValue().subtract(totalComputedCost);
      oldestTaxLotLine.setLotHoldingCost(
          oldestTaxLotLine.getLotHoldingCost().add(difAmount.negate()));
    }
  }
  /**
   * Adjusts the number of units if the total is different from the transaction line units.
   *
   * @param lotsMap
   * @param transLine
   * @param keepIntegers
   * @param isSubTypeCash
   * @param perUnitValue
   */
  private void adjustUnitsNumberAndAmountsForAverageBalance(
      Map<Integer, HoldingTaxLot> lotsMap,
      EndowmentTransactionLine transLine,
      boolean keepIntegers,
      boolean isSubTypeCash,
      BigDecimal perUnitValue) {
    // Adjust the number of units if the total is different from the transaction line units
    BigDecimal totalComputedTaxLotUnits = BigDecimal.ZERO;
    BigDecimal totalComputedCost = BigDecimal.ZERO;
    EndowmentTransactionTaxLotLine oldestTaxLotLine = null;

    if (transLine.getTaxLotLines() != null && transLine.getTaxLotLines().size() > 0) {
      for (EndowmentTransactionTaxLotLine taxLotLine : transLine.getTaxLotLines()) {
        BigDecimal lotUnits = taxLotLine.getLotUnits().negate();

        // calculate the total number of units to be decreased
        totalComputedTaxLotUnits = totalComputedTaxLotUnits.add(lotUnits);
        totalComputedCost = totalComputedCost.add(taxLotLine.getLotHoldingCost().negate());

        if (taxLotLine.getLotShortTermGainLoss() != null) {
          totalComputedCost = totalComputedCost.add(taxLotLine.getLotShortTermGainLoss());
        }

        if (taxLotLine.getLotLongTermGainLoss() != null) {
          totalComputedCost = totalComputedCost.add(taxLotLine.getLotLongTermGainLoss());
        }

        // keep the tax lot with the oldest acquired date so that we can adjust the units for that
        // one in case the
        // number of units needs and adjustment
        if (oldestTaxLotLine != null) {
          if (oldestTaxLotLine.getLotAcquiredDate().after(taxLotLine.getLotAcquiredDate())) {
            oldestTaxLotLine = taxLotLine;
          }
        } else {
          oldestTaxLotLine = taxLotLine;
        }
      }
    }

    // compare with the negated number of units on the transaction line because the units on the tax
    // lots have been negated
    if (totalComputedTaxLotUnits.compareTo(
            transLine.getTransactionUnits().bigDecimalValue().negate())
        != 0) {
      BigDecimal difUnits =
          transLine.getTransactionUnits().bigDecimalValue().subtract(totalComputedTaxLotUnits);
      oldestTaxLotLine.setLotUnits(oldestTaxLotLine.getLotUnits().add(difUnits.negate()));
      oldestTaxLotLine.setLotUnits(oldestTaxLotLine.getLotUnits().negate());

      if (isSubTypeCash) {
        // update totalComputedCost
        totalComputedCost =
            totalComputedCost.subtract(oldestTaxLotLine.getLotHoldingCost().negate());
        if (oldestTaxLotLine.getLotShortTermGainLoss() != null) {
          totalComputedCost =
              totalComputedCost.subtract(oldestTaxLotLine.getLotShortTermGainLoss());
        }

        if (oldestTaxLotLine.getLotLongTermGainLoss() != null) {
          totalComputedCost = totalComputedCost.subtract(oldestTaxLotLine.getLotLongTermGainLoss());
        }
      }

      HoldingTaxLot holdingTaxLot = lotsMap.get(oldestTaxLotLine.getTransactionHoldingLotNumber());
      BigDecimal originalUnitValue =
          KEMCalculationRoundingHelper.divide(holdingTaxLot.getCost(), holdingTaxLot.getUnits(), 5);
      BigDecimal originalCost =
          KEMCalculationRoundingHelper.multiply(
              oldestTaxLotLine.getLotUnits(), originalUnitValue, 2);
      oldestTaxLotLine.setLotHoldingCost(originalCost);

      if (isSubTypeCash) {
        // 4. Calculate the value received for units sold in each tax lot
        BigDecimal valueReceived =
            KEMCalculationRoundingHelper.multiply(oldestTaxLotLine.getLotUnits(), perUnitValue, 2);

        // 7. Calculate Gain or loss
        calculateGainLoss(holdingTaxLot, oldestTaxLotLine, valueReceived, originalCost);
        // update totalComputedCost
        totalComputedCost = totalComputedCost.add(oldestTaxLotLine.getLotHoldingCost());
        if (oldestTaxLotLine.getLotShortTermGainLoss() != null) {
          totalComputedCost = totalComputedCost.add(oldestTaxLotLine.getLotShortTermGainLoss());
        }

        if (oldestTaxLotLine.getLotLongTermGainLoss() != null) {
          totalComputedCost = totalComputedCost.add(oldestTaxLotLine.getLotLongTermGainLoss());
        }
      }
      oldestTaxLotLine.setLotHoldingCost(oldestTaxLotLine.getLotHoldingCost().negate());
      oldestTaxLotLine.setLotUnits(oldestTaxLotLine.getLotUnits().negate());
    }

    if (isSubTypeCash) {
      // compare total computed cost with the transaction line amount
      if (totalComputedCost.compareTo(transLine.getTransactionUnits().bigDecimalValue()) != 0) {
        BigDecimal difAmount =
            transLine.getTransactionAmount().bigDecimalValue().subtract(totalComputedCost);
        oldestTaxLotLine.setLotHoldingCost(
            oldestTaxLotLine.getLotHoldingCost().negate().add(difAmount));

        oldestTaxLotLine.setLotHoldingCost(oldestTaxLotLine.getLotHoldingCost().negate());
      }
    }
  }