/**
   * Instantiate subviews for the given group view and the given key value to group-by. Makes
   * shallow copies of each child view and its subviews up to the merge point. Sets up merge data
   * views for merging the group-by key value back in.
   *
   * @param groupView is the parent view for which to copy subviews for
   * @param groupByValues is the key values to group-by
   * @param agentInstanceContext is the view services that sub-views may need
   * @param propertyNames names of expressions or properties
   * @return a single view or a list of views that are copies of the original list, with copied
   *     children, with data merge views added to the copied child leaf views.
   */
  public static Object makeSubViews(
      GroupByView groupView,
      String[] propertyNames,
      Object groupByValues,
      AgentInstanceViewFactoryChainContext agentInstanceContext) {
    if (!groupView.hasViews()) {
      String message = "Unexpected empty list of child nodes for group view";
      log.fatal(".copySubViews " + message);
      throw new EPException(message);
    }

    Object subviewHolder;
    if (groupView.getViews().length == 1) {
      subviewHolder =
          copyChildView(
              groupView,
              propertyNames,
              groupByValues,
              agentInstanceContext,
              groupView.getViews()[0]);
    } else {
      // For each child node
      ArrayList<View> subViewList = new ArrayList<View>(4);
      subviewHolder = subViewList;
      for (View originalChildView : groupView.getViews()) {
        View copyChildView =
            copyChildView(
                groupView, propertyNames, groupByValues, agentInstanceContext, originalChildView);
        subViewList.add(copyChildView);
      }
    }

    return subviewHolder;
  }
  private static View copyChildView(
      GroupByView groupView,
      String[] propertyNames,
      Object groupByValues,
      AgentInstanceViewFactoryChainContext agentInstanceContext,
      View originalChildView) {
    if (originalChildView instanceof MergeView) {
      String message = "Unexpected merge view as child of group-by view";
      log.fatal(".copySubViews " + message);
      throw new EPException(message);
    }

    if (!(originalChildView instanceof CloneableView)) {
      throw new EPException(
          "Unexpected error copying subview " + originalChildView.getClass().getName());
    }
    CloneableView cloneableView = (CloneableView) originalChildView;

    // Copy child node
    View copyChildView = cloneableView.cloneView();
    copyChildView.setParent(groupView);

    // Make the sub views for child copying from the original to the child
    copySubViews(
        groupView.getCriteriaExpressions(),
        propertyNames,
        groupByValues,
        originalChildView,
        copyChildView,
        agentInstanceContext);

    return copyChildView;
  }