/**
   * This method will be called by system creator during initialization and system update. Be sure
   * that this method can be called repeatedly.
   *
   * @param context the context provides the selected parameters and values
   */
  @SystemSetup(type = Type.ESSENTIAL, process = Process.ALL)
  public void createEssentialData(final SystemSetupContext context) {
    final boolean importCustomReports =
        getBooleanSystemSetupParameter(context, IMPORT_CUSTOM_REPORTS);

    if (importCustomReports) {
      if (MediaManager.getInstance()
              .getMediaFolderByQualifier(V2kartCockpitsConstants.JASPER_REPORTS_MEDIA_FOLDER)
              .size()
          < 1) {
        MediaManager.getInstance()
            .createMediaFolder(
                V2kartCockpitsConstants.JASPER_REPORTS_MEDIA_FOLDER,
                V2kartCockpitsConstants.JASPER_REPORTS_MEDIA_FOLDER);
      }
      try {
        String prefix = null;
        if (Config.isMySQLUsed()) {
          prefix = "mysql";
        } else if (Config.isHSQLDBUsed()) {
          prefix = "hsqldb";
        } else if (Config.isOracleUsed()) {
          prefix = "oracle";
        } else if (Config.isSQLServerUsed()) {
          prefix = "sqlserver";
        }

        if (prefix != null) {
          importImpexFile(
              context, "/v2kartcockpits/reportcockpit/import/" + prefix + "_jasperreports.impex");
        }
      } catch (final Exception e) {
        LOG.error("Error during Jasper Report files import " + e);
      }
    }
  }
  @Override
  public List<PossibleAttributeValue> findPossibleAttributeValues(
      final CategoryModel category,
      final Collection<ClassAttributeAssignmentModel> assignments,
      final Map<ClassAttributeAssignmentModel, Object> filteredAttributeValues) {
    final boolean useToCharForClob = Config.isOracleUsed() || Config.isHanaUsed();
    final Map<String, Object> filterParams = new HashMap<String, Object>();

    // We select the ClassAttributeAssignment, the value of the product feature, the unit
    // and a count of all product feature value. The latter is achieved by adding a group by
    // statement
    // later on
    final StringBuilder stringBuilder =
        new StringBuilder("SELECT {pf.classificationAttributeAssignment},");
    if (useToCharForClob) {
      stringBuilder.append(" to_char({pf.stringValue}),");
    } else {
      stringBuilder.append(" {pf.stringValue},");
    }
    stringBuilder.append(" {pf.unit}, COUNT(*) ");
    stringBuilder.append("FROM {").append(ProductFeatureModel._TYPECODE).append(" AS pf ");
    stringBuilder
        .append("JOIN ")
        .append(ProductModel._TYPECODE)
        .append(" ON {Product.pk} = {pf.product} } ");

    // Restricting the search to the given ClassAttributeAssignments
    stringBuilder.append("WHERE {pf.classificationAttributeAssignment} IN (?assignments) ");

    // Add a subquery that select all products with the given filter
    // This is necessary to only find attribute values contained in the filtered attributes
    final String filterQuery =
        createQueryToFindProductsByAttributeValues(
            category, filteredAttributeValues, filterParams, false);
    stringBuilder.append(" AND {Product.pk} IN ({{").append(filterQuery).append("}}) ");

    // Group the result to count the values
    stringBuilder.append("GROUP BY {pf.classificationAttributeAssignment} ");
    if (useToCharForClob) {
      stringBuilder.append(", to_char({pf.stringValue})");
    } else {
      stringBuilder.append(", {pf.stringValue}");
    }
    stringBuilder.append(", {pf.unit}");

    // Create the actual flexible search query
    final FlexibleSearchQuery query = new FlexibleSearchQuery(stringBuilder.toString());
    query.setResultClassList(Arrays.asList(Item.class, String.class, Item.class, Long.class));
    query.addQueryParameter("assignments", assignments);
    query.addQueryParameters(filterParams);
    final SearchResult<List<Object>> result = search(query);
    final List<PossibleAttributeValue> possibleAttributeValues =
        new ArrayList<PossibleAttributeValue>(result.getCount());
    for (final List<Object> row : result.getResult()) {
      if (row.size() != 4) {
        throw new IllegalStateException("Invalid size of row: " + row.size());
      }
      final ClassAttributeAssignmentModel assignment = (ClassAttributeAssignmentModel) row.get(0);
      final String stringValue = (String) row.get(1);
      final Object value = convertValue(assignment, stringValue);
      final ClassificationAttributeUnitModel unit = (ClassificationAttributeUnitModel) row.get(2);
      final Long count = (Long) row.get(3);
      final PossibleAttributeValue possibleValue =
          new PossibleAttributeValue(assignment, value, unit, count);
      possibleAttributeValues.add(possibleValue);
    }
    return possibleAttributeValues;
  }