/**
   * Add a comment to a particular blog entry
   *
   * @param author Comment author
   * @param authorEmail Comment author e-mail
   * @param authorURL Comment author URL
   * @param userComment Comment
   * @param blogCommentsEnabled If comments are enabled or not
   * @param commentMetaData Metadata for the comment
   * @param blog {@link Blog}
   * @param entry {@link Entry}
   * @param httpServletRequest {@link HttpServletRequest}
   * @return BlogComment Entry
   */
  private Comment addBlogComment(
      String author,
      String authorEmail,
      String authorURL,
      String userComment,
      boolean blogCommentsEnabled,
      Map commentMetaData,
      Blog blog,
      Entry entry,
      HttpServletRequest httpServletRequest) {
    Comment comment = null;

    if (blogCommentsEnabled) {
      try {
        comment = _fetcher.newComment();
        comment.setBlogEntryId(entry.getId());
        comment.setEntry(entry);
        comment.setAuthor(author);
        comment.setAuthorEmail(authorEmail);
        comment.setAuthorURL(authorURL);
        comment.setComment(userComment);
        comment.setCommentDate(new Date());
        comment.setBlogId(blog.getId());
        comment.setIp(httpServletRequest.getRemoteAddr());
        if (commentMetaData.containsKey(
                CommentModerationPlugin.BLOJSOM_COMMENT_MODERATION_PLUGIN_APPROVED)
            && "true"
                .equals(
                    commentMetaData.get(
                        CommentModerationPlugin.BLOJSOM_COMMENT_MODERATION_PLUGIN_APPROVED))) {
          comment.setStatus(ResponseConstants.APPROVED_STATUS);
        } else {
          if ("true".equals(blog.getProperty(CommentModerationPlugin.COMMENT_MODERATION_ENABLED))) {
            comment.setStatus(ResponseConstants.NEW_STATUS);
          } else {
            comment.setStatus(ResponseConstants.APPROVED_STATUS);
          }
        }
        comment.setMetaData(commentMetaData);

        String commentParentID =
            BlojsomUtils.getRequestValue(COMMENT_PARENT_ID, httpServletRequest);
        if (!BlojsomUtils.checkNullOrBlank(commentParentID)) {
          try {
            comment.setParentId(Integer.valueOf(commentParentID));
          } catch (NumberFormatException e) {
          }
        }

        _fetcher.saveComment(blog, comment);
      } catch (FetcherException e) {
        if (_logger.isErrorEnabled()) {
          _logger.error(e);
        }

        comment = null;
      }
    }

    return comment;
  }
  /**
   * Process the blog entries
   *
   * @param httpServletRequest Request
   * @param httpServletResponse Response
   * @param blog {@link Blog} instance
   * @param context Context
   * @param entries Blog entries retrieved for the particular request
   * @return Modified set of blog entries
   * @throws PluginException If there is an error processing the blog entries
   */
  public Entry[] process(
      HttpServletRequest httpServletRequest,
      HttpServletResponse httpServletResponse,
      Blog blog,
      Map context,
      Entry[] entries)
      throws PluginException {
    context.put(BLOJSOM_COMMENT_PLUGIN_ENABLED, blog.getBlogCommentsEnabled());
    if (!blog.getBlogCommentsEnabled().booleanValue()) {
      if (_logger.isDebugEnabled()) {
        _logger.debug("Comments not enabled for blog: " + blog.getBlogId());
      }

      return entries;
    }

    Boolean _blogCommentsEnabled;
    _blogCommentsEnabled = blog.getBlogCommentsEnabled();

    int _cookieExpiration;
    String cookieExpiration = blog.getProperty(COMMENT_COOKIE_EXPIRATION_DURATION_IP);
    if (BlojsomUtils.checkNullOrBlank(cookieExpiration)) {
      _cookieExpiration = COOKIE_EXPIRATION_AGE;
    } else {
      try {
        _cookieExpiration = Integer.parseInt(cookieExpiration);
      } catch (NumberFormatException e) {
        _cookieExpiration = COOKIE_EXPIRATION_AGE;
      }
    }

    if (entries.length == 0) {
      return entries;
    }

    String author = httpServletRequest.getParameter(AUTHOR_PARAM);
    String authorEmail = httpServletRequest.getParameter(AUTHOR_EMAIL_PARAM);
    String authorURL = httpServletRequest.getParameter(AUTHOR_URL_PARAM);
    String rememberMe = httpServletRequest.getParameter(REMEMBER_ME_PARAM);

    // Check to see if the person has requested they be "remembered" and if so
    // extract their information from the appropriate cookies
    Cookie authorCookie = CookieUtils.getCookie(httpServletRequest, COOKIE_AUTHOR);
    if ((authorCookie != null) && BlojsomUtils.checkNullOrBlank(author)) {
      author = authorCookie.getValue();
      if (_logger.isDebugEnabled()) {
        _logger.debug("Pulling author from cookie: " + author);
      }

      if ("".equals(author)) {
        author = null;
      } else {
        context.put(BLOJSOM_COMMENT_PLUGIN_AUTHOR, author);
      }

      Cookie authorEmailCookie = CookieUtils.getCookie(httpServletRequest, COOKIE_EMAIL);
      if ((authorEmailCookie != null) && BlojsomUtils.checkNullOrBlank(authorEmail)) {
        authorEmail = authorEmailCookie.getValue();
        if (_logger.isDebugEnabled()) {
          _logger.debug("Pulling author email from cookie: " + authorEmail);
        }

        if (authorEmail == null) {
          authorEmail = "";
        } else {
          context.put(BLOJSOM_COMMENT_PLUGIN_AUTHOR_EMAIL, authorEmail);
        }
      }

      Cookie authorUrlCookie = CookieUtils.getCookie(httpServletRequest, COOKIE_URL);
      if ((authorUrlCookie != null) && BlojsomUtils.checkNullOrBlank(authorURL)) {
        authorURL = authorUrlCookie.getValue();
        if (_logger.isDebugEnabled()) {
          _logger.debug("Pulling author URL from cookie: " + authorURL);
        }

        if (authorURL == null) {
          authorURL = "";
        } else {
          context.put(BLOJSOM_COMMENT_PLUGIN_AUTHOR_URL, authorURL);
        }
      }

      Cookie rememberMeCookie = CookieUtils.getCookie(httpServletRequest, COOKIE_REMEMBER_ME);
      if ((rememberMeCookie != null) && ((rememberMe == null) || "".equals(rememberMe))) {
        rememberMe = rememberMeCookie.getValue();
        if (rememberMe != null) {
          context.put(BLOJSOM_COMMENT_PLUGIN_REMEMBER_ME, rememberMe);
        }
      }
    }

    String remoteIPAddress = httpServletRequest.getRemoteAddr();

    // Comment handling
    if ("y".equalsIgnoreCase(httpServletRequest.getParameter(COMMENT_PARAM))
        && _blogCommentsEnabled.booleanValue()) {
      String commentText = httpServletRequest.getParameter(COMMENT_TEXT_PARAM);
      String remember = httpServletRequest.getParameter(REMEMBER_ME_PARAM);

      if (!BlojsomUtils.checkNullOrBlank(author) && !BlojsomUtils.checkNullOrBlank(commentText)) {
        // Check for comment throttling
        String commentThrottleValue = blog.getProperty(COMMENT_THROTTLE_MINUTES_IP);
        if (!BlojsomUtils.checkNullOrBlank(commentThrottleValue)) {
          int commentThrottleMinutes;

          try {
            commentThrottleMinutes = Integer.parseInt(commentThrottleValue);
          } catch (NumberFormatException e) {
            commentThrottleMinutes = COMMENT_THROTTLE_DEFAULT_MINUTES;
          }
          if (_logger.isDebugEnabled()) {
            _logger.debug("Comment throttling enabled at: " + commentThrottleMinutes + " minutes");
          }

          if (_ipAddressCommentTimes.containsKey(remoteIPAddress)) {
            Calendar currentTime = Calendar.getInstance();
            Calendar timeOfLastComment = (Calendar) _ipAddressCommentTimes.get(remoteIPAddress);
            long timeDifference =
                currentTime.getTimeInMillis() - timeOfLastComment.getTimeInMillis();

            long differenceInMinutes = timeDifference / (60 * 1000);
            if (differenceInMinutes < commentThrottleMinutes) {
              if (_logger.isDebugEnabled()) {
                _logger.debug(
                    "Comment throttle enabled. Comment from IP address: "
                        + remoteIPAddress
                        + " in less than "
                        + commentThrottleMinutes
                        + " minutes");
              }

              return entries;
            } else {
              if (_logger.isDebugEnabled()) {
                _logger.debug(
                    "Comment throttle enabled. Resetting date of last comment to current time");
              }

              _ipAddressCommentTimes.put(remoteIPAddress, currentTime);
            }
          } else {
            Calendar calendar = Calendar.getInstance();
            _ipAddressCommentTimes.put(remoteIPAddress, calendar);
          }
        }

        author = author.trim();
        author = BlojsomUtils.escapeStringSimple(author);
        author = BlojsomUtils.stripLineTerminators(author, " ");

        commentText = commentText.trim();

        // Check if autoformatting of comment text should be done
        boolean autoformatComments =
            Boolean.valueOf(blog.getProperty(COMMENT_AUTOFORMAT_IP)).booleanValue();
        if (autoformatComments) {
          commentText = BlojsomUtils.replace(commentText, "\n", "<br />");
        }

        if (authorEmail != null) {
          authorEmail = authorEmail.trim();
          authorEmail = BlojsomUtils.escapeStringSimple(authorEmail);
          authorEmail = BlojsomUtils.stripLineTerminators(authorEmail, " ");
        } else {
          authorEmail = "";
        }

        if (authorURL != null) {
          authorURL = authorURL.trim();
          authorURL = BlojsomUtils.escapeStringSimple(authorURL);
          authorURL = BlojsomUtils.stripLineTerminators(authorURL, " ");
        } else {
          authorURL = "";
        }

        if (!BlojsomUtils.checkNullOrBlank(authorURL)
            && !authorURL.toLowerCase().startsWith("http://")) {
          authorURL = "http://" + authorURL;
        }

        Entry entryForComment = _fetcher.newEntry();
        try {
          String blogEntryId = BlojsomUtils.getRequestValue("entry_id", httpServletRequest);
          Integer entryId;
          try {
            entryId = Integer.valueOf(blogEntryId);
          } catch (NumberFormatException e) {
            if (_logger.isErrorEnabled()) {
              _logger.error(e);
            }

            return entries;
          }

          entryForComment.setId(entryId);

          _fetcher.loadEntry(blog, entryForComment);
          if (_logger.isDebugEnabled()) {
            _logger.debug("Loaded entry for comment: " + entryId.toString());
          }

          if (entryForComment.allowsComments().booleanValue()) {
            // Check for a comment where the number of days between comment auto-expiration has
            // passed
            String commentDaysExpiration = blog.getProperty(COMMENT_DAYS_EXPIRATION_IP);
            if (!BlojsomUtils.checkNullOrBlank(commentDaysExpiration)) {
              try {
                int daysExpiration = Integer.parseInt(commentDaysExpiration);
                int daysBetweenDates =
                    BlojsomUtils.daysBetweenDates(entryForComment.getDate(), new Date());
                if ((daysExpiration > 0) && (daysBetweenDates >= daysExpiration)) {
                  if (_logger.isDebugEnabled()) {
                    _logger.debug(
                        "Comment period for this entry has expired. Expiration period set at "
                            + daysExpiration
                            + " days. Difference in days: "
                            + daysBetweenDates);
                  }

                  return entries;
                }
              } catch (NumberFormatException e) {
                if (_logger.isErrorEnabled()) {
                  _logger.error(
                      "Error in parameter "
                          + COMMENT_DAYS_EXPIRATION_IP
                          + ": "
                          + commentDaysExpiration);
                }
              }
            }
          } else {
            if (_logger.isDebugEnabled()) {
              _logger.debug(
                  "Comments have been disabled for blog entry: " + entryForComment.getId());
            }

            return entries;
          }
        } catch (FetcherException e) {
          if (_logger.isErrorEnabled()) {
            _logger.error(e);
          }

          return entries;
        }

        Map commentMetaData = new HashMap();

        // Check to see if a previous plugin populated meta-data for the comment
        if (context.containsKey(BLOJSOM_PLUGIN_COMMENT_METADATA)) {
          Map metaData = (Map) context.get(BLOJSOM_PLUGIN_COMMENT_METADATA);

          Iterator metaDataKeys = metaData.keySet().iterator();
          Object key;
          Object value;
          while (metaDataKeys.hasNext()) {
            key = metaDataKeys.next();
            value = metaData.get(key);
            commentMetaData.put(key, value);
          }
        }

        CommentResponseSubmissionEvent commentResponseSubmissionEvent =
            new CommentResponseSubmissionEvent(
                this,
                new Date(),
                blog,
                httpServletRequest,
                httpServletResponse,
                author,
                authorEmail,
                authorURL,
                commentText,
                entryForComment,
                commentMetaData);
        _eventBroadcaster.processEvent(commentResponseSubmissionEvent);
        author = commentResponseSubmissionEvent.getSubmitter();
        authorEmail = commentResponseSubmissionEvent.getSubmitterItem1();
        authorURL = commentResponseSubmissionEvent.getSubmitterItem2();
        commentText = commentResponseSubmissionEvent.getContent();

        // Check to see if the comment should be destroyed (not saved) automatically
        if (!commentMetaData.containsKey(BLOJSOM_PLUGIN_COMMENT_METADATA_DESTROY)) {
          Comment comment =
              addBlogComment(
                  author,
                  authorEmail,
                  authorURL,
                  commentText,
                  _blogCommentsEnabled.booleanValue(),
                  commentMetaData,
                  blog,
                  entries[0],
                  httpServletRequest);

          // For persisting the Last-Modified time
          context.put(BlojsomConstants.BLOJSOM_LAST_MODIFIED, new Long(new Date().getTime()));

          if (comment != null) {
            context.put(BLOJSOM_COMMENT_PLUGIN_STATUS, comment.getStatus());

            try {
              _fetcher.loadEntry(blog, entries[0]);
              _fetcher.loadEntry(blog, entryForComment);
              _eventBroadcaster.broadcastEvent(
                  new CommentAddedEvent(this, new Date(), comment, blog));
            } catch (FetcherException e) {
              if (_logger.isErrorEnabled()) {
                _logger.error(e);
              }
            }
          } else {
            context.put(BLOJSOM_COMMENT_PLUGIN_STATUS, BLOJSOM_COMMENT_PLUGIN_STATUS_ERROR);
          }
        } else {
          if (_logger.isDebugEnabled()) {
            _logger.debug("Comment meta-data contained destroy key. Comment was not saved");
          }

          context.put(BLOJSOM_COMMENT_PLUGIN_STATUS, ResponseConstants.DELETED_STATUS);
          context.put(BLOJSOM_COMMENT_PLUGIN_AUTHOR, author);
          context.put(BLOJSOM_COMMENT_PLUGIN_AUTHOR_EMAIL, authorEmail);
          context.put(BLOJSOM_COMMENT_PLUGIN_AUTHOR_URL, authorURL);
          if (autoformatComments) {
            context.put(
                BLOJSOM_COMMENT_PLUGIN_COMMENT_TEXT,
                BlojsomUtils.escapeStringSimple(BlojsomUtils.replace(commentText, "<br />", "\n")));
          } else {
            context.put(
                BLOJSOM_COMMENT_PLUGIN_COMMENT_TEXT, BlojsomUtils.escapeStringSimple(commentText));
          }
        }

        // If we're asked to remember the person, then add the appropriate cookies
        if ((remember != null) && (!"".equals(remember))) {
          CookieUtils.addCookie(httpServletResponse, _cookieExpiration, COOKIE_AUTHOR, author);
          context.put(BLOJSOM_COMMENT_PLUGIN_AUTHOR, author);
          CookieUtils.addCookie(httpServletResponse, _cookieExpiration, COOKIE_EMAIL, authorEmail);
          context.put(BLOJSOM_COMMENT_PLUGIN_AUTHOR_EMAIL, authorEmail);
          CookieUtils.addCookie(httpServletResponse, _cookieExpiration, COOKIE_URL, authorURL);
          context.put(BLOJSOM_COMMENT_PLUGIN_AUTHOR_URL, authorURL);
          CookieUtils.addCookie(httpServletResponse, _cookieExpiration, COOKIE_REMEMBER_ME, "true");
          context.put(BLOJSOM_COMMENT_PLUGIN_REMEMBER_ME, "true");
        }
      }

      String redirectTo =
          BlojsomUtils.getRequestValue(BlojsomConstants.REDIRECT_TO_PARAM, httpServletRequest);
      if (!BlojsomUtils.checkNullOrBlank(redirectTo)) {
        try {
          httpServletResponse.sendRedirect(BlojsomUtils.urlEncodeForLink(redirectTo));
          httpServletRequest.setAttribute(BlojsomConstants.IS_IN_REDIRECT, Boolean.TRUE);
        } catch (IOException e) {
        }
      }
    }

    return entries;
  }