/**
   * Utility method used for constructing a parameter values map for subreports, sub datasets and
   * crosstabs.
   *
   * @param filler report filler
   * @param expressionEvaluator expression evaluator
   * @param parametersMapExpression expression that yields bulk parameter values map
   * @param subreportParameters list of individual parameter values
   * @param evaluation evaluation type
   * @param ignoreNullExpressions whether to ignore individual parameter value expressions
   * @param removeResourceBundle whether to remove the {@link JRParameter#REPORT_RESOURCE_BUNDLE
   *     REPORT_RESOURCE_BUNDLE} value from the bulk values map
   * @return the parameter values map
   * @throws JRException
   */
  public static Map<String, Object> getParameterValues(
      // TODO using the filler or current dataset?
      JRBaseFiller filler,
      JRFillExpressionEvaluator expressionEvaluator,
      JRExpression parametersMapExpression,
      JRDatasetParameter[] subreportParameters,
      byte evaluation,
      boolean ignoreNullExpressions,
      boolean removeResourceBundle,
      boolean removeFormatFactory)
      throws JRException {
    Map<String, Object> parameterValues = null;
    if (parametersMapExpression != null) {
      parameterValues =
          (Map<String, Object>) expressionEvaluator.evaluate(parametersMapExpression, evaluation);
    }

    if (parameterValues != null) {
      // if the expression evaluates to the master parameters map
      if (parameterValues == filler.getParameterValuesMap()) {
        // create a clone of the map so that the master map is not altered
        parameterValues = new HashMap<String, Object>(parameterValues);
      }

      // parameterValues.remove(JRParameter.REPORT_LOCALE);
      if (removeResourceBundle) {
        parameterValues.remove(JRParameter.REPORT_RESOURCE_BUNDLE);
      }
      if (removeFormatFactory) {
        parameterValues.remove(JRParameter.REPORT_FORMAT_FACTORY);
      }
      // parameterValues.remove(JRParameter.REPORT_TIME_ZONE);
      parameterValues.remove(JRParameter.JASPER_REPORT);
      parameterValues.remove(JRParameter.REPORT_CONNECTION);
      parameterValues.remove(JRParameter.REPORT_MAX_COUNT);
      parameterValues.remove(JRParameter.REPORT_DATA_SOURCE);
      parameterValues.remove(JRParameter.REPORT_SCRIPTLET);
      // should we give access to scriplet extensions so that they can remove their parameters here?
      // yes, but then you should also give them access to create built-in parameters... too much
      // trouble.
      JRScriptlet[] scriptlets = filler.getJasperReport().getScriptlets();
      if (scriptlets != null) {
        for (int i = 0; i < scriptlets.length; i++) {
          parameterValues.remove(
              scriptlets[i].getName() + JRScriptlet.SCRIPTLET_PARAMETER_NAME_SUFFIX);
        }
      }
      parameterValues.remove(JRParameter.REPORT_VIRTUALIZER);
      // parameterValues.remove(JRParameter.REPORT_CLASS_LOADER);
      parameterValues.remove(JRParameter.IS_IGNORE_PAGINATION);
      parameterValues.remove(JRParameter.SORT_FIELDS);
      parameterValues.remove(JRParameter.FILTER);
      parameterValues.remove(JRParameter.REPORT_PARAMETERS_MAP);
    }

    if (parameterValues == null) {
      parameterValues = new HashMap<String, Object>();
    }

    /*   */
    if (subreportParameters != null && subreportParameters.length > 0) {
      Object parameterValue = null;
      for (int i = 0; i < subreportParameters.length; i++) {
        JRExpression expression = subreportParameters[i].getExpression();
        if (expression != null || !ignoreNullExpressions) {
          parameterValue = expressionEvaluator.evaluate(expression, evaluation);
          if (parameterValue == null) {
            parameterValues.remove(subreportParameters[i].getName());
          } else {
            parameterValues.put(subreportParameters[i].getName(), parameterValue);
          }
        }
      }
    }

    if (!parameterValues.containsKey(JRParameter.REPORT_LOCALE)) {
      parameterValues.put(JRParameter.REPORT_LOCALE, filler.getLocale());
    }

    if (!parameterValues.containsKey(JRParameter.REPORT_TIME_ZONE)) {
      parameterValues.put(JRParameter.REPORT_TIME_ZONE, filler.getTimeZone());
    }

    if (!parameterValues.containsKey(JRParameter.REPORT_FORMAT_FACTORY) && !removeFormatFactory) {
      parameterValues.put(JRParameter.REPORT_FORMAT_FACTORY, filler.getFormatFactory());
    }

    if (!parameterValues.containsKey(JRParameter.REPORT_CLASS_LOADER)
        && filler.reportClassLoader != null) {
      parameterValues.put(JRParameter.REPORT_CLASS_LOADER, filler.reportClassLoader);
    }

    if (!parameterValues.containsKey(JRParameter.REPORT_URL_HANDLER_FACTORY)
        && filler.urlHandlerFactory != null) {
      parameterValues.put(JRParameter.REPORT_URL_HANDLER_FACTORY, filler.urlHandlerFactory);
    }

    if (!parameterValues.containsKey(JRParameter.REPORT_FILE_RESOLVER)
        && filler.fileResolver != null) {
      parameterValues.put(JRParameter.REPORT_FILE_RESOLVER, filler.fileResolver);
    }

    if (!parameterValues.containsKey(JRParameter.REPORT_CONTEXT)) {
      ReportContext context =
          (ReportContext)
              filler.getMainDataset().getParameterValue(JRParameter.REPORT_CONTEXT, true);
      if (context != null) {
        parameterValues.put(JRParameter.REPORT_CONTEXT, context);
      }
    }

    return parameterValues;
  }