/**
   * Returns the {@link Parameter} with the given key from the {@link ParameterBag} with the given
   * bagKey, or null if the {@link Parameter} or the {@link ParameterBag} does not exist
   *
   * @param bagKey the key of the {@link ParameterBag} from which the {@link Parameter} is to be
   *     returned
   * @param paramKey the key of the {@link Parameter} which is to be returned
   * @param assertExists if set to true, and the parameter does not exist, a {@link
   *     StrolchModelException} is thrown
   * @return the found {@link Parameter} or null if it was not found
   */
  public <T extends Parameter<?>> T getParameter(
      String bagKey, String paramKey, boolean assertExists) {
    if (this.parameterBagMap == null) {
      if (assertExists) {
        String msg = "The Parameter {0} does not exist";
        throw new StrolchModelException(
            MessageFormat.format(msg, getLocator().append(Tags.BAG, bagKey, paramKey)));
      }

      return null;
    }
    ParameterBag bag = this.parameterBagMap.get(bagKey);
    if (bag == null) {
      if (assertExists) {
        String msg = "The Parameter {0} does not exist";
        throw new StrolchModelException(
            MessageFormat.format(msg, getLocator().append(Tags.BAG, bagKey, paramKey)));
      }

      return null;
    }

    T parameter = bag.getParameter(paramKey);
    if (assertExists && parameter == null) {
      String msg = "The Parameter {0} does not exist";
      throw new StrolchModelException(
          MessageFormat.format(msg, getLocator().append(Tags.BAG, bagKey, paramKey)));
    }
    return parameter;
  }
  @Nullable
  public static MethodReferenceBag getMethodParameterReferenceBag(
      PsiElement psiElement, int wantIndex) {

    PsiElement variableContext = psiElement.getContext();
    if (!(variableContext instanceof ParameterList)) {
      return null;
    }

    ParameterList parameterList = (ParameterList) variableContext;
    if (!(parameterList.getContext() instanceof MethodReference)) {
      return null;
    }

    ParameterBag currentIndex = PsiElementUtils.getCurrentParameterIndex(psiElement);
    if (currentIndex == null) {
      return null;
    }

    if (wantIndex >= 0 && currentIndex.getIndex() != wantIndex) {
      return null;
    }

    return new MethodReferenceBag(
        parameterList, (MethodReference) parameterList.getContext(), currentIndex);
  }
  /**
   * Fills {@link GroupedParameterizedElement} properties of this clone
   *
   * @param clone
   */
  protected void fillClone(GroupedParameterizedElement clone) {
    super.fillClone(clone);
    clone.setType(getType());

    if (this.parameterBagMap != null) {
      for (ParameterBag bag : this.parameterBagMap.values()) {
        clone.addParameterBag(bag.getClone());
      }
    }
  }
  /**
   * Returns true if the {@link Parameter} with the given paramKey exists on the {@link
   * ParameterBag} with the given bagKey
   *
   * @param bagKey the key of the {@link ParameterBag} on which to find the {@link Parameter}
   * @param paramKey the key of the {@link Parameter} to be found
   * @return true if the {@link Parameter} with the given paramKey exists on the {@link
   *     ParameterBag} with the given bagKey. False is returned if the {@link ParameterBag} does not
   *     exist, or the {@link Parameter} does not exist on the {@link ParameterBag}
   */
  public boolean hasParameter(String bagKey, String paramKey) {
    if (this.parameterBagMap == null) {
      return false;
    }
    ParameterBag bag = this.parameterBagMap.get(bagKey);
    if (bag == null) {
      return false;
    }

    return bag.hasParameter(paramKey);
  }
  /**
   * Removes the {@link Parameter} with the given paramKey from the {@link ParameterBag} with the
   * given bagKey
   *
   * @param bagKey the key of the {@link ParameterBag} from which the {@link Parameter} is to be
   *     removed
   * @param paramKey the key of the {@link Parameter} which is to be removed
   * @return the removed {@link Parameter} or null if it did not exist
   */
  public <T> Parameter<T> removeParameter(String bagKey, String paramKey) {
    if (this.parameterBagMap == null) {
      return null;
    }
    ParameterBag bag = this.parameterBagMap.get(bagKey);
    if (bag == null) {
      return null;
    }

    return bag.removeParameter(paramKey);
  }
  /**
   * Adds the given {@link ParameterBag} to this {@link GroupedParameterizedElement}
   *
   * @param bag the {@link ParameterBag} to add
   */
  public void addParameterBag(ParameterBag bag) {
    if (this.parameterBagMap == null) {
      this.parameterBagMap = new HashMap<>();
    }

    if (this.parameterBagMap.containsKey(bag.getId())) {
      String msg = "A ParameterBag already exists with id {0} on {1}";
      throw new StrolchException(MessageFormat.format(msg, bag.getId(), getLocator()));
    }
    this.parameterBagMap.put(bag.getId(), bag);
    bag.setParent(this);
  }
  /**
   * Adds a new {@link Parameter} to the {@link ParameterBag} with the given key
   *
   * @param bagKey the key of the {@link ParameterBag} to which the {@link Parameter} should be
   *     added
   * @param parameter the {@link Parameter} to be added to the {@link ParameterBag}
   * @throws StrolchException if the {@link ParameterBag} does not exist
   */
  public void addParameter(String bagKey, Parameter<?> parameter) throws StrolchException {
    if (this.parameterBagMap == null) {
      this.parameterBagMap = new HashMap<>();
    }
    ParameterBag bag = this.parameterBagMap.get(bagKey);
    if (bag == null) {
      String msg = "No parameter bag exists with key {0}"; // $NON-NLS-1$
      msg = MessageFormat.format(msg, bagKey);
      throw new StrolchException(msg);
    }

    bag.addParameter(parameter);
  }
  public static int getParameterIndexValue(@Nullable PsiElement parameterListChild) {

    if (parameterListChild == null) {
      return -1;
    }

    ParameterBag parameterBag = PsiElementUtils.getCurrentParameterIndex(parameterListChild);
    if (parameterBag == null) {
      return -1;
    }

    return parameterBag.getIndex();
  }
  public static boolean isCallToWithParameter(
      PsiElement psiElement, String className, String methodName, int parameterIndex) {
    if (!(psiElement.getContext() instanceof ParameterList)) {
      return false;
    }

    ParameterList parameterList = (ParameterList) psiElement.getContext();
    if (parameterList == null || !(parameterList.getContext() instanceof MethodReference)) {
      return false;
    }

    MethodReference method = (MethodReference) parameterList.getContext();
    Symfony2InterfacesUtil interfacesUtil = new Symfony2InterfacesUtil();
    if (!interfacesUtil.isCallTo(method, className, methodName)) {
      return false;
    }

    ParameterBag currentIndex = PsiElementUtils.getCurrentParameterIndex(psiElement);
    if (currentIndex == null || currentIndex.getIndex() != parameterIndex) {
      return false;
    }

    return true;
  }