private int getCommentDepth(Comment comment) {
   int depth = 0;
   Comment parent = comment.getParentComment();
   while (parent != null) {
     depth++;
     parent = parent.getParentComment();
   }
   return depth;
 }
  private void replyToComment(final Comment parentComment) {
    String replyPromptMessage = "Reply";
    if (parentComment.getAuthor() != null) {
      replyPromptMessage = "Reply To: " + parentComment.getAuthor().getUsername();
    } else if (!StringUtils.isEmpty(parentComment.getEmail())) {
      replyPromptMessage = "Reply To: " + parentComment.getEmail();
    }
    PromptDialogBox dialog =
        new PromptDialogBox(replyPromptMessage, "Submit", null, "Cancel", false, true);
    dialog.setAllowKeyboardEvents(false);
    VerticalPanel replyPanel = new VerticalPanel();

    final TextArea textArea = new TextArea();
    textArea.setCharacterWidth(60);
    textArea.setVisibleLines(4);
    final TextBox emailTextBox = new TextBox();
    if (AuthenticationHandler.getInstance().getUser() == null) {
      replyPanel.add(new Label("Email:"));
      replyPanel.add(emailTextBox);
    }
    replyPanel.add(textArea);

    dialog.setFocusWidget(textArea);
    dialog.setContent(replyPanel);
    dialog.setValidatorCallback(
        new IDialogValidatorCallback() {
          public boolean validate() {
            if (textArea.getText() == null || "".equals(textArea.getText())) {
              MessageDialogBox dialog =
                  new MessageDialogBox("Error", "Comment is blank.", false, true, true);
              dialog.center();
              return false;
            }
            return true;
          }
        });
    dialog.setCallback(
        new IDialogCallback() {
          public void okPressed() {
            Comment newComment = new Comment();
            newComment.setGlobalRead(true);
            newComment.setOwner(permissibleObject.getOwner());
            newComment.setAuthor(AuthenticationHandler.getInstance().getUser());
            newComment.setComment(textArea.getText());
            newComment.setParent(permissibleObject);
            newComment.setParentComment(parentComment);
            newComment.setEmail(emailTextBox.getText());
            submitComment(newComment);
          }

          public void cancelPressed() {}
        });
    dialog.center();
  }
 public void onFailure(Throwable caught) {
   MessageDialogBox dialog =
       new MessageDialogBox("Error", caught.getMessage(), false, true, true);
   dialog.center();
   workingOnComment.setApproved(false);
   loadCommentWidget(true);
 }
 public void onSuccess(Boolean result) {
   workingOnComment.setApproved(true);
   loadCommentWidget(true);
 }
  private List<PermissibleObject> sortComments(List<PermissibleObject> comments) {
    List<Comment> commentSet = new ArrayList<Comment>();

    for (PermissibleObject obj : comments) {
      Comment comment = (Comment) obj;
      commentSet.add(comment);
      Comment parent = comment.getParentComment();
      do {
        if (parent != null) {
          if (!commentSet.contains(parent)) {
            commentSet.add(parent);
          }
          parent = parent.getParentComment();
        }
      } while (parent != null);
    }

    // create bare nodes for each element
    PermissibleObjectTreeNode rootNode = new PermissibleObjectTreeNode();

    for (Comment comment : commentSet) {
      PermissibleObjectTreeNode node = new PermissibleObjectTreeNode();
      node.setObject(comment);
      if (comment.getParentComment() == null) {
        if (!rootNode.getChildren().containsKey(comment)) {
          rootNode.getChildren().put(comment, node);
        }
      } else {
        // try to find parent in rootNode tree
        PermissibleObjectTreeNode parent = findParentCommentNode(rootNode, node);
        if (parent == null) {
          // this nodes parent cannot be found, let's add all of his parents
          List<Comment> parentComments = new ArrayList<Comment>();
          Comment parentComment = comment.getParentComment();
          do {
            if (parentComment != null) {
              parentComments.add(parentComment);
              parentComment = parentComment.getParentComment();
            }
          } while (parent != null);
          if (parentComments.size() == 0) {
            rootNode.getChildren().put(comment, node);
          } else {
            // reverse the order of the list and add/find existing parents
            Collections.reverse(parentComments);
            for (Comment myParentComment : parentComments) {
              PermissibleObjectTreeNode myParentCommentNode = new PermissibleObjectTreeNode();
              myParentCommentNode.setObject(myParentComment);
              PermissibleObjectTreeNode parentParent =
                  findParentCommentNode(rootNode, myParentCommentNode);
              if (parentParent == null) {
                rootNode.getChildren().put(myParentComment, myParentCommentNode);
              } else {
                if (!parentParent.getChildren().containsKey(myParentComment)) {
                  parentParent.getChildren().put(myParentComment, myParentCommentNode);
                }
              }
            }
            // we better find it now
            parent = findParentCommentNode(rootNode, node);
            parent.getChildren().put(comment, node);
          }
        } else {
          if (!parent.getChildren().containsKey(comment)) {
            parent.getChildren().put(comment, node);
          }
        }
      }
    }

    // march the tree
    ArrayList<PermissibleObject> list = new ArrayList<PermissibleObject>();
    marchTree(list, rootNode);

    return list;
  }
  private void loadCommentWidget(final boolean forceOpen) {
    clear();
    if (permissibleObject.isAllowComments()) {

      String fileName = permissibleObject.getName();
      final DisclosurePanel commentDisclosurePanel =
          new DisclosurePanel("View comments (" + numComments + ") for " + fileName);

      VerticalPanel commentsPanel = new VerticalPanel();
      commentsPanel.setSpacing(0);
      if (numComments > 0) {
        commentsPanel.setStyleName("commentsPanel");
      }
      commentsPanel.setWidth("100%");

      int renderedComments = 0;
      boolean userCanManage =
          AuthenticationHandler.getInstance().getUser() != null
              && (AuthenticationHandler.getInstance().getUser().isAdministrator()
                  || AuthenticationHandler.getInstance()
                      .getUser()
                      .equals(permissibleObject.getOwner()));
      List<PermissibleObject> sortedComments = new ArrayList<PermissibleObject>();
      if (comments != null) {
        sortedComments.addAll(comments);
      }
      if (!flatten) {
        sortedComments = sortComments(sortedComments);
      }

      for (PermissibleObject obj : sortedComments) {
        final Comment comment = (Comment) obj;
        int commentDepth = getCommentDepth(comment);

        int maxDepth =
            Integer.parseInt(
                maxCommentDepthListBox.getValue(maxCommentDepthListBox.getSelectedIndex()));
        if (commentDepth >= maxDepth) {
          continue;
        }

        boolean userIsAuthorOfComment =
            AuthenticationHandler.getInstance().getUser() != null
                && comment.getAuthor() != null
                && comment.getAuthor().equals(AuthenticationHandler.getInstance().getUser());

        if (userCanManage || userIsAuthorOfComment || comment.isApproved()) {

          FlexTable commentHeaderPanel = new FlexTable();
          commentHeaderPanel.setCellPadding(0);
          commentHeaderPanel.setCellSpacing(0);
          commentHeaderPanel.setStyleName("commentHeader");
          commentHeaderPanel.setWidth("100%");

          String authorLabelString =
              comment.getAuthor() == null ? comment.getEmail() : comment.getAuthor().getUsername();
          if (comment.getAuthor() != null
              && comment.getAuthor().getFirstname() != null
              && !"".equals(comment.getAuthor().getFirstname())) {
            authorLabelString += " (" + comment.getAuthor().getFirstname();
            if (comment.getAuthor() != null
                && comment.getAuthor().getLastname() != null
                && !"".equals(comment.getAuthor().getLastname())) {
              authorLabelString += " " + comment.getAuthor().getLastname() + ")";
            } else {
              authorLabelString += ")";
            }
          }

          Image replyCommentImage = new Image();
          replyCommentImage.setResource(BaseImageBundle.images.reply());
          replyCommentImage.setStyleName("commentActionButton");
          replyCommentImage.setTitle("Reply to this comment");
          replyCommentImage.addClickHandler(
              new ClickHandler() {

                public void onClick(ClickEvent event) {
                  replyToComment(comment);
                }
              });
          int columnIndex = 0;
          commentHeaderPanel.setWidget(0, columnIndex, replyCommentImage);
          commentHeaderPanel
              .getFlexCellFormatter()
              .setHorizontalAlignment(0, columnIndex, HasHorizontalAlignment.ALIGN_LEFT);
          columnIndex++;

          Label authorLabel = new Label(authorLabelString, false);
          commentHeaderPanel.setWidget(0, columnIndex, authorLabel);
          commentHeaderPanel
              .getFlexCellFormatter()
              .setHorizontalAlignment(0, columnIndex, HasHorizontalAlignment.ALIGN_LEFT);
          columnIndex++;
          commentHeaderPanel.setWidget(0, columnIndex, new Label());
          commentHeaderPanel.getFlexCellFormatter().setWidth(0, columnIndex, "100%");
          commentHeaderPanel
              .getFlexCellFormatter()
              .setHorizontalAlignment(0, columnIndex, HasHorizontalAlignment.ALIGN_RIGHT);
          columnIndex++;
          Label dateLabel = new Label(new Date(comment.getCommentDate()).toLocaleString(), false);
          commentHeaderPanel.setWidget(0, columnIndex, dateLabel);
          if (!userCanManage && !userIsAuthorOfComment) {
            DOM.setStyleAttribute(dateLabel.getElement(), "padding", "0 5px 0 0");
          }
          commentHeaderPanel
              .getFlexCellFormatter()
              .setHorizontalAlignment(0, columnIndex, HasHorizontalAlignment.ALIGN_RIGHT);

          columnIndex++;
          if (userCanManage || userIsAuthorOfComment) {
            if (userCanManage && !comment.isApproved()) {
              final Image approveCommentImage = new Image();
              approveCommentImage.setResource(BaseImageBundle.images.approve());
              approveCommentImage.setStyleName("commentActionButton");
              approveCommentImage.setTitle("Approve comment");
              approveCommentImage.addClickHandler(
                  new ClickHandler() {

                    public void onClick(ClickEvent event) {
                      workingOnComment = comment;
                      approveComment(comment);
                    }
                  });
              commentHeaderPanel.setWidget(0, columnIndex, approveCommentImage);
              commentHeaderPanel
                  .getFlexCellFormatter()
                  .setHorizontalAlignment(0, columnIndex, HasHorizontalAlignment.ALIGN_RIGHT);
              columnIndex++;
            } else {
              // put 16x16 spacer here for alignment
              final Image approveSpacerImage = new Image();
              approveSpacerImage.setResource(BaseImageBundle.images.empty16x16());
              approveSpacerImage.setStyleName("commentActionButton");
              commentHeaderPanel.setWidget(0, columnIndex, approveSpacerImage);
              commentHeaderPanel
                  .getFlexCellFormatter()
                  .setHorizontalAlignment(0, columnIndex, HasHorizontalAlignment.ALIGN_RIGHT);
              columnIndex++;
            }
            Image deleteCommentImage = new Image();
            deleteCommentImage.setResource(BaseImageBundle.images.delete());
            deleteCommentImage.setStyleName("commentActionButton");
            deleteCommentImage.setTitle("Remove comment");
            deleteCommentImage.addClickHandler(
                new ClickHandler() {

                  public void onClick(ClickEvent event) {
                    IDialogCallback callback =
                        new IDialogCallback() {

                          public void cancelPressed() {}

                          public void okPressed() {
                            deleteComment(comment);
                          }
                        };
                    PromptDialogBox dialogBox =
                        new PromptDialogBox("Question", "Yes", null, "No", false, true);
                    dialogBox.setContent(
                        new Label(
                            "Delete comment by "
                                + (comment.getAuthor() == null
                                    ? comment.getEmail()
                                    : comment.getAuthor().getUsername())
                                + "?"));
                    dialogBox.setCallback(callback);
                    dialogBox.center();
                  }
                });
            commentHeaderPanel.setWidget(0, columnIndex, deleteCommentImage);
            commentHeaderPanel
                .getFlexCellFormatter()
                .setHorizontalAlignment(0, columnIndex, HasHorizontalAlignment.ALIGN_RIGHT);
            columnIndex++;
          }

          if (commentDepth > 0) {
            HorizontalPanel commentHeaderPanelWrapper = new HorizontalPanel();
            commentHeaderPanelWrapper.setWidth("100%");
            Label spacerLabel = new Label();
            commentHeaderPanelWrapper.add(spacerLabel);
            if (!flatten) {
              commentHeaderPanelWrapper.setCellWidth(spacerLabel, (commentDepth * 20) + "px");
            }
            commentHeaderPanelWrapper.add(commentHeaderPanel);
            commentsPanel.add(commentHeaderPanelWrapper);
          } else {
            commentsPanel.add(commentHeaderPanel);
          }

          // Label commentLabel = new Label(comment.getId() + " " + comment.getComment(), true);
          Label commentLabel = new Label(comment.getComment(), true);
          if (comment.isApproved()) {
            commentLabel.setStyleName("comment");
          } else if (userCanManage || userIsAuthorOfComment) {
            commentLabel.setStyleName("commentAwaitingApproval");
          }

          if (commentDepth > 0) {
            HorizontalPanel commentHeaderPanelWrapper = new HorizontalPanel();
            commentHeaderPanelWrapper.setWidth("100%");
            Label spacerLabel = new Label();
            commentHeaderPanelWrapper.add(spacerLabel);
            if (!flatten) {
              commentHeaderPanelWrapper.setCellWidth(spacerLabel, (commentDepth * 20) + "px");
            }
            commentHeaderPanelWrapper.add(commentLabel);
            commentsPanel.add(commentHeaderPanelWrapper);
          } else {
            commentsPanel.add(commentLabel);
          }
          renderedComments++;
        }
      }

      final FlexTable mainPanel = new FlexTable();
      mainPanel.setWidth("100%");
      int row = 0;
      if (paginate) {
        mainPanel.setWidget(row, 0, createButtonPanel(mainPanel, forceOpen));
        mainPanel
            .getCellFormatter()
            .setHorizontalAlignment(row++, 0, HasHorizontalAlignment.ALIGN_LEFT);
      }
      mainPanel.setWidget(row, 0, commentsPanel);
      mainPanel.getCellFormatter().setWidth(row++, 0, "100%");

      commentDisclosurePanel.setContent(mainPanel);
      commentDisclosurePanel.setOpen(renderedComments == 0 || forceOpen);
      commentDisclosurePanel.setWidth("100%");
      add(createCommentPostPanel());
      add(commentDisclosurePanel);
    }
    if (layoutCallback != null) {
      layoutCallback.layoutComplete();
    }
  }