/**
   * Populates criteria arguments for the given target class and arguments map
   *
   * @param datastore the GrailsApplication instance
   * @param targetClass The target class
   * @param c The criteria instance
   * @param argMap The arguments map
   */
  @SuppressWarnings("rawtypes")
  public static void populateArgumentsForCriteria(
      AbstractHibernateDatastore datastore,
      Class<?> targetClass,
      Criteria c,
      Map argMap,
      ConversionService conversionService,
      boolean useDefaultMapping) {
    Integer maxParam = null;
    Integer offsetParam = null;
    if (argMap.containsKey(ARGUMENT_MAX)) {
      maxParam = conversionService.convert(argMap.get(ARGUMENT_MAX), Integer.class);
    }
    if (argMap.containsKey(ARGUMENT_OFFSET)) {
      offsetParam = conversionService.convert(argMap.get(ARGUMENT_OFFSET), Integer.class);
    }
    if (argMap.containsKey(ARGUMENT_FETCH_SIZE)) {
      c.setFetchSize(conversionService.convert(argMap.get(ARGUMENT_FETCH_SIZE), Integer.class));
    }
    if (argMap.containsKey(ARGUMENT_TIMEOUT)) {
      c.setTimeout(conversionService.convert(argMap.get(ARGUMENT_TIMEOUT), Integer.class));
    }
    if (argMap.containsKey(ARGUMENT_FLUSH_MODE)) {
      c.setFlushMode(convertFlushMode(argMap.get(ARGUMENT_FLUSH_MODE)));
    }
    if (argMap.containsKey(ARGUMENT_READ_ONLY)) {
      c.setReadOnly(ClassUtils.getBooleanFromMap(ARGUMENT_READ_ONLY, argMap));
    }
    String orderParam = (String) argMap.get(ARGUMENT_ORDER);
    Object fetchObj = argMap.get(ARGUMENT_FETCH);
    if (fetchObj instanceof Map) {
      Map fetch = (Map) fetchObj;
      for (Object o : fetch.keySet()) {
        String associationName = (String) o;
        c.setFetchMode(associationName, getFetchMode(fetch.get(associationName)));
      }
    }

    final int max = maxParam == null ? -1 : maxParam;
    final int offset = offsetParam == null ? -1 : offsetParam;
    if (max > -1) {
      c.setMaxResults(max);
    }
    if (offset > -1) {
      c.setFirstResult(offset);
    }
    if (ClassUtils.getBooleanFromMap(ARGUMENT_LOCK, argMap)) {
      c.setLockMode(LockMode.PESSIMISTIC_WRITE);
      c.setCacheable(false);
    } else {
      if (argMap.containsKey(ARGUMENT_CACHE)) {
        c.setCacheable(ClassUtils.getBooleanFromMap(ARGUMENT_CACHE, argMap));
      } else {
        cacheCriteriaByMapping(targetClass, c);
      }
    }

    final Object sortObj = argMap.get(ARGUMENT_SORT);
    if (sortObj != null) {
      boolean ignoreCase = true;
      Object caseArg = argMap.get(ARGUMENT_IGNORE_CASE);
      if (caseArg instanceof Boolean) {
        ignoreCase = (Boolean) caseArg;
      }
      if (sortObj instanceof Map) {
        Map sortMap = (Map) sortObj;
        for (Object sort : sortMap.keySet()) {
          final String order =
              ORDER_DESC.equalsIgnoreCase((String) sortMap.get(sort)) ? ORDER_DESC : ORDER_ASC;
          addOrderPossiblyNested(datastore, c, targetClass, (String) sort, order, ignoreCase);
        }
      } else {
        final String sort = (String) sortObj;
        final String order = ORDER_DESC.equalsIgnoreCase(orderParam) ? ORDER_DESC : ORDER_ASC;
        addOrderPossiblyNested(datastore, c, targetClass, sort, order, ignoreCase);
      }
    } else if (useDefaultMapping) {
      Mapping m = getDomainBinder().getMapping(targetClass);
      if (m != null) {
        Map sortMap = m.getSort().getNamesAndDirections();
        for (Object sort : sortMap.keySet()) {
          final String order =
              ORDER_DESC.equalsIgnoreCase((String) sortMap.get(sort)) ? ORDER_DESC : ORDER_ASC;
          addOrderPossiblyNested(datastore, c, targetClass, (String) sort, order, true);
        }
      }
    }
  }