/**
   * Adds to the given velocity parameters using the given fieldValuesHolder and fieldLayoutItem (to
   * determine the renderer).
   *
   * @param fieldLayoutItem the FieldLayoutItem in play
   * @param fieldValuesHolder the fields values holder in play
   * @param velocityParams the velocity parameters to which values will be added
   */
  private void populateVelocityParams(
      FieldLayoutItem fieldLayoutItem, Map fieldValuesHolder, Map<String, Object> velocityParams) {
    if (fieldValuesHolder != null) {
      Map commentParams = (Map) fieldValuesHolder.get(getId());
      if (commentParams != null) {
        velocityParams.put(getId(), commentParams.get(getId()));
      }
    }

    velocityParams.put("rendererParams", new HashMap());
    String rendererType = (fieldLayoutItem != null) ? fieldLayoutItem.getRendererType() : null;
    velocityParams.put(
        "rendererDescriptor", rendererManager.getRendererForType(rendererType).getDescriptor());
    velocityParams.put("groupLevels", getGroupLevels());
    velocityParams.put(
        "mentionable", mentionService.isUserAbleToMention(authenticationContext.getLoggedInUser()));

    Issue issue = (Issue) velocityParams.get("issue");
    if (issue != null) {
      velocityParams.put("roleLevels", getRoleLevels(issue));
    } else {
      // We are possibly in a bulk screen
      Object action = velocityParams.get("action");
      if (action != null && action instanceof BulkWorkflowTransition) {
        BulkWorkflowTransition bulkWorkflowTransition = (BulkWorkflowTransition) action;
        BulkEditBean bulkEditBean = bulkWorkflowTransition.getBulkEditBean();
        if (bulkEditBean != null) {
          // TODO: what if there are multiple projects? We should get the intersection of all roles.
          GenericValue project = bulkEditBean.getProject();
          if (project != null) {
            velocityParams.put("roleLevels", getRoleLevels(project));
          }
        }
      }
    }
  }
  @Override
  public void updateValue(
      FieldLayoutItem fieldLayoutItem,
      Issue issue,
      ModifiedValue modifiedValue,
      IssueChangeHolder issueChangeHolder) {
    // all comment creations are seen as an update
    Map<String, Object> commentParams = (Map<String, Object>) modifiedValue.getNewValue();
    String body = (String) commentParams.get(getId());

    // allow the renderer for this field a change to transform the value
    String rendererType = (fieldLayoutItem != null) ? fieldLayoutItem.getRendererType() : null;
    body = (String) rendererManager.getRendererForType(rendererType).transformFromEdit(body);

    if (commentParams.containsKey(EDIT_COMMENT)) {
      editComment(issueChangeHolder, commentParams, body);
    } else if (commentParams.containsKey(REMOVE_COMMENT)) {
      removeComment(issueChangeHolder, commentParams);
    } else {
      if (StringUtils.isNotBlank(body)) {
        createComment(issue, issueChangeHolder, commentParams, body);
      }
    }
  }