/**
   * Receives notification that a new group is about to start. If this is the group defined for the
   * function, then the minimum value is reset to zero.
   *
   * @param event Information about the event.
   */
  public void groupStarted(final ReportEvent event) {
    if (FunctionUtilities.isDefinedGroup(getGroup(), event)) {
      clear();
    }

    if (FunctionUtilities.isDefinedGroup(getCrosstabFilterGroup(), event)) {
      final int groupIndex = event.getState().getCurrentGroupIndex();
      this.lastGroupSequenceNumber =
          (int) event.getState().getCrosstabColumnSequenceCounter(groupIndex);
    }
  }
  public void summaryRowSelection(final ReportEvent event) {
    if (rowbandingOnGroup == false) {
      return;
    }

    if (StringUtils.isEmpty(group)) {
      final Group group = event.getReport().getGroup(event.getState().getCurrentGroupIndex());
      if (group instanceof CrosstabRowGroup) {
        final GroupBody body = group.getBody();
        if (body instanceof CrosstabColumnGroupBody) {
          if (Boolean.TRUE.equals(
              group.getAttribute(
                  AttributeNames.Crosstab.NAMESPACE, AttributeNames.Crosstab.PRINT_SUMMARY))) {
            triggerVisibleStateCrosstab(event);
          }
        }
      }
    } else {
      if (FunctionUtilities.isDefinedGroup(group, event)) {
        final Group group = event.getReport().getGroup(event.getState().getCurrentGroupIndex());
        if (Boolean.TRUE.equals(
            group.getAttribute(
                AttributeNames.Crosstab.NAMESPACE, AttributeNames.Crosstab.PRINT_SUMMARY))) {
          triggerVisibleStateCrosstab(event);
        }
      }
    }
  }
  /**
   * Receives notification that report generation initializes the current run.
   *
   * <p>The event carries a ReportState.Started state. Use this to initialize the report.
   *
   * @param event The event.
   */
  public void reportInitialized(final ReportEvent event) {
    if (ignoreCrosstabMode) {
      // If the user forces us into relational-mode, then we obey ..
      rowbandingOnGroup = StringUtils.isEmpty(group) == false;
    } else {
      // check whether there is a crosstab
      if (FunctionUtilities.isCrosstabDefined(event)) {
        // when we have one, we always rowband on a group instead of an item-count
        rowbandingOnGroup = true;
      } else {
        // we only row-band on an item-count if the group is not empty.
        rowbandingOnGroup = StringUtils.isEmpty(group) == false;
      }
    }

    trigger = !getInitialState();
    count = 0;
  }
  /**
   * Triggers the visible state of the specified itemband element. If the named element was visible
   * at the last call, it gets now invisible and vice versa. This creates the effect, that an
   * element is printed every other line.
   *
   * @param event the current report event.
   */
  private void triggerVisibleState(final ReportEvent event) {
    // avoid divide by zero exception
    if (numberOfElements == 0) {
      return;
    }

    if ((count % numberOfElements) == 0) {
      trigger = (!trigger);
    }
    count += 1;

    final ItemBand itemBand = event.getReport().getItemBand();
    if (itemBand == null) {
      return;
    }

    if (element == null) {
      if (trigger) {
        itemBand.getStyle().setStyleProperty(ElementStyleKeys.BACKGROUND_COLOR, visibleBackground);
      } else {
        itemBand
            .getStyle()
            .setStyleProperty(ElementStyleKeys.BACKGROUND_COLOR, invisibleBackground);
      }
    } else {
      final Element[] e = FunctionUtilities.findAllElements(itemBand, getElement());
      if (e.length > 0) {
        for (int i = 0; i < e.length; i++) {
          if (trigger) {
            e[i].getStyle().setStyleProperty(ElementStyleKeys.BACKGROUND_COLOR, visibleBackground);
          } else {
            e[i].getStyle()
                .setStyleProperty(ElementStyleKeys.BACKGROUND_COLOR, invisibleBackground);
          }
        }
      } else {
        if (warned == false) {
          RowBandingFunction.logger.warn(
              "The Band does not contain an element named " + getElement());
          warned = true;
        }
      }
    }
  }
  public void groupStarted(final ReportEvent event) {
    if (rowbandingOnGroup == false) {
      return;
    }

    if (StringUtils.isEmpty(group)) {
      final Group group = event.getReport().getGroup(event.getState().getCurrentGroupIndex());
      if (group instanceof CrosstabRowGroup) {
        final GroupBody body = group.getBody();
        if (body instanceof CrosstabColumnGroupBody) {
          triggerVisibleStateCrosstab(event);
        }
      }
    } else {
      if (FunctionUtilities.isDefinedGroup(group, event)) {
        triggerVisibleStateCrosstab(event);
      }
    }
  }
  /**
   * Triggers the visible state of the specified itemband element. If the named element was visible
   * at the last call, it gets now invisible and vice versa. This creates the effect, that an
   * element is printed every other line.
   *
   * @param event the current report event.
   */
  private void triggerVisibleStateCrosstab(final ReportEvent event) {
    if ((count % numberOfElements) == 0) {
      trigger = (!trigger);
    }
    count += 1;

    final CrosstabCellBody cellBody = event.getReport().getCrosstabCellBody();
    if (cellBody == null) {
      return;
    }

    if (element == null) {
      final int elementCount = cellBody.getElementCount();
      for (int i = 1; i < elementCount; i += 1) {
        final Element cell = cellBody.getElement(i);
        if (trigger) {
          cell.getStyle().setStyleProperty(ElementStyleKeys.BACKGROUND_COLOR, visibleBackground);
        } else {
          cell.getStyle().setStyleProperty(ElementStyleKeys.BACKGROUND_COLOR, invisibleBackground);
        }
      }
    } else {
      final Element[] e = FunctionUtilities.findAllElements(cellBody, getElement());
      if (e.length > 0) {
        for (int i = 0; i < e.length; i++) {
          if (trigger) {
            e[i].getStyle().setStyleProperty(ElementStyleKeys.BACKGROUND_COLOR, visibleBackground);
          } else {
            e[i].getStyle()
                .setStyleProperty(ElementStyleKeys.BACKGROUND_COLOR, invisibleBackground);
          }
        }
      } else {
        if (warned == false) {
          RowBandingFunction.logger.warn(
              "The cell-body does not contain an element named " + getElement());
          warned = true;
        }
      }
    }
  }