class AbstractPropertyProvider extends BaseProvider implements PropertyProvider {

  protected static String substituteArgument(String propertyId, String argName, String val) {

    // find the argument in the property id
    int argStart = propertyId.indexOf(argName);

    String value = val == null ? "" : val;

    if (argStart > -1) {
      // get the string segment starting with the given argument
      String argSegment = propertyId.substring(argStart);

      // check to see if there are any methods attached to the argument
      Matcher matcher = CHECK_FOR_METRIC_ARGUMENT_METHODS_REGEX.matcher(argSegment);
      if (matcher.find()) {

        // expand the argument name to include its methods
        argName = argSegment.substring(matcher.start(), matcher.end());

        // for each method attached to the argument ...
        matcher = FIND_ARGUMENT_METHOD_REGEX.matcher(argName);
        while (matcher.find()) {
          // find the end of the method
          int openParenIndex = argName.indexOf('(', matcher.start());
          int closeParenIndex = indexOfClosingParenthesis(argName, openParenIndex);

          String methodName = argName.substring(matcher.start() + 1, openParenIndex);
          String args = argName.substring(openParenIndex + 1, closeParenIndex);

          List<Object> argList = new LinkedList<>();
          List<Class<?>> paramTypes = new LinkedList<>();

          // for each argument of the method ...
          Matcher argMatcher = FIND_ARGUMENT_METHOD_ARGUMENTS_REGEX.matcher(args);
          while (argMatcher.find()) {
            addArgument(args, argMatcher.start(), argMatcher.end(), argList, paramTypes);
          }

          try {
            value = invokeArgumentMethod(value, methodName, argList, paramTypes);
          } catch (Exception e) {
            throw new IllegalArgumentException("Can't apply method " + methodName + " for argument " +
              argName + " in " + propertyId, e);
          }
        }
        if (value.equals(val)) {
          return propertyId;
        }
      }
      // Do the substitution
      return propertyId.replace(argName, value);
    }
    throw new IllegalArgumentException("Can't substitute " + val + "  for argument " + argName + " in " + propertyId);
  }

  public  AbstractPropertyProvider(Map<String, Map<String, PropertyInfo>> componentMetrics);

}