/**
  * Gets list of all acceptable cardinalities for this expression from its parent.
  *
  * <ol>
  *   <li>evaluates index of this expression in parent
  *   <li>calls parent's <code>getRequiredCardinalities(index)</code> method
  * </ol>
  *
  * If this expression doesn't have any parent (it is legal for testing, but not for real use
  * case), returns list of all cardinalities.
  *
  * @param context TODO
  * @return list of all acceptable cardinalities for this expression from its parent
  */
 protected final Cardinality[] getParentRequiredCardinalities(final ValidationContext context) {
   if (getParent() != null) {
     final int index =
         getParent()
             .getNodeGroups()
             .getGroupSupporting(getQtiClassName())
             .getChildren()
             .indexOf(this);
     return getParent().getRequiredCardinalities(context, index);
   }
   return Cardinality.values();
 }
  /**
   * Gets list of all acceptable cardinalities which can child expression at given position produce.
   *
   * <p>This method is used when same cardinality is required (contains, match).
   *
   * @param context TODO
   * @param index position of child expression in this parent
   * @param includeParent whether parent requirements should be used during calculation
   * @return list of all acceptable cardinalities which can child expression at given position
   *     produce
   * @see #getRequiredCardinalities
   */
  @ToRefactor
  protected final Cardinality[] getRequiredSameCardinalities(
      final ValidationContext context, final int index, final boolean includeParent) {
    Cardinality[] required = getType().getRequiredCardinalities(index);

    if (includeParent) {
      required = Cardinality.intersection(required, getParentRequiredCardinalities(context));
    }

    for (int i = 0; i < index && i < getChildren().size(); i++) {
      final Expression child = getChildren().get(i);

      final Cardinality[] newRequired =
          Cardinality.intersection(required, child.getProducedCardinalities(context));
      if (newRequired.length == 0) {
        break;
      }

      required = newRequired;
    }

    return required;
  }