/**
   * Process the blog entries
   *
   * @param httpServletRequest Request
   * @param httpServletResponse Response
   * @param user {@link org.blojsom.blog.BlogUser}instance
   * @param context Context
   * @param entries Blog entries retrieved for the particular request
   * @return Modified set of blog entries
   * @throws org.blojsom.plugin.BlojsomPluginException If there is an error processing the blog
   *     entries
   */
  public org.blojsom.blog.BlogEntry[] process(
      HttpServletRequest httpServletRequest,
      HttpServletResponse httpServletResponse,
      BlogUser user,
      Map context,
      org.blojsom.blog.BlogEntry[] entries)
      throws org.blojsom.plugin.BlojsomPluginException {
    Map emoticonsForBlog = readEmoticonsMapForBlog(user.getId());
    if (emoticonsForBlog == null) {
      return entries;
    }

    List availableEmoticons = parseEmoticons((String) emoticonsForBlog.get(EMOTICONS_PARAM));
    String blogBaseUrl = user.getBlog().getBlogBaseURL();
    for (int i = 0; i < entries.length; i++) {
      BlogEntry entry = entries[i];
      if (!BlojsomUtils.checkMapForKey(
          entry.getMetaData(), BLOJSOM_PLUGIN_METADATA_EMOTICONS_DISABLED)) {
        String updatedDescription = entry.getDescription();
        Iterator iter = availableEmoticons.iterator();
        while (iter.hasNext()) {
          String emoticon = (String) iter.next();
          updatedDescription =
              replaceEmoticon(emoticonsForBlog, updatedDescription, emoticon, blogBaseUrl);
        }
        entry.setDescription(updatedDescription);
      }
    }
    return entries;
  }
  /**
   * Get a particular post for a blojsom category
   *
   * @since blojsom 1.9.3
   * @param appkey Unique identifier/passcode of the application sending the post
   * @param blogid Unique identifier of the blog the post will be added to
   * @param userid Login for a Blogger user who has permission to post to the blog
   * @param password Password for said username
   * @throws XmlRpcException If the user was not authenticated correctly
   * @return Post to the blog
   */
  public Object getPost(String appkey, String blogid, String userid, String password)
      throws Exception {
    _logger.debug("getPost() Called ===========[ SUPPORTED ]=====");
    _logger.debug("     Appkey: " + appkey);
    _logger.debug("     BlogId: " + blogid);
    _logger.debug("     UserId: " + userid);
    _logger.debug("   Password: "******"?" + PERMALINK_PARAM + "=";

      int pos = blogid.indexOf(match);
      if (pos != -1) {
        category = blogid.substring(0, pos);
        category = BlojsomUtils.normalize(category);
        permalink = blogid.substring(pos + match.length());

        Map fetchMap = new HashMap();
        BlogCategory blogCategory = _fetcher.newBlogCategory();
        blogCategory.setCategory(category);
        blogCategory.setCategoryURL(_blog.getBlogURL() + category);
        fetchMap.put(BlojsomFetcher.FETCHER_CATEGORY, blogCategory);
        fetchMap.put(BlojsomFetcher.FETCHER_PERMALINK, permalink);
        BlogEntry[] _entries = _fetcher.fetchEntries(fetchMap, _blogUser);

        if (_entries != null && _entries.length > 0) {
          BlogEntry entry = _entries[0];
          Hashtable entrystruct = new Hashtable();
          entrystruct.put(MEMBER_POSTID, entry.getId());
          entrystruct.put(MEMBER_BLOGID, entry.getCategory());
          entrystruct.put(MEMBER_TITLE, entry.getEscapedTitle());
          entrystruct.put(MEMBER_URL, entry.getEscapedLink());
          entrystruct.put(MEMBER_CONTENT, entry.getTitle() + "\n" + entry.getDescription());
          entrystruct.put(MEMBER_DATECREATED, entry.getDate());
          entrystruct.put(MEMBER_AUTHORNAME, _blog.getBlogOwner());
          entrystruct.put(MEMBER_AUTHOREMAIL, _blog.getBlogOwnerEmail());

          return entrystruct;
        } else {
          throw new XmlRpcException(INVALID_POSTID, INVALID_POSTID_MSG);
        }
      } else {
        throw new XmlRpcException(INVALID_POSTID, INVALID_POSTID_MSG);
      }
    } catch (BlojsomException e) {
      _logger.error(
          "Failed to authenticate user [" + userid + "] with password [" + password + "]");
      throw new XmlRpcException(AUTHORIZATION_EXCEPTION, AUTHORIZATION_EXCEPTION_MSG);
    }
  }
  /**
   * Get a list of recent posts for a blojsom category
   *
   * @param appkey Unique identifier/passcode of the application sending the post
   * @param blogid Unique identifier of the blog the post will be added to
   * @param userid Login for a Blogger user who has permission to post to the blog
   * @param password Password for said username
   * @param numposts Number of Posts to Retrieve
   * @throws XmlRpcException If the user was not authenticated correctly
   * @return Recent posts to the blog
   */
  public Object getRecentPosts(
      String appkey, String blogid, String userid, String password, int numposts) throws Exception {
    _logger.debug("getRecentPosts() Called ===========[ SUPPORTED ]=====");
    _logger.debug("     Appkey: " + appkey);
    _logger.debug("     BlogId: " + blogid);
    _logger.debug("     UserId: " + userid);
    _logger.debug("   Password: "******"     Number: " + numposts);

    Vector recentPosts = new Vector();
    blogid = BlojsomUtils.normalize(blogid);

    try {
      _authorizationProvider.loadAuthenticationCredentials(_blogUser);
      _authorizationProvider.authorize(_blogUser, null, userid, password);

      // Quick verify that the categories are valid
      File blogCategoryFile =
          new File(_blog.getBlogHome() + BlojsomUtils.removeInitialSlash(blogid));
      if (blogCategoryFile.exists() && blogCategoryFile.isDirectory()) {

        String requestedCategory = BlojsomUtils.removeInitialSlash(blogid);
        BlogCategory blogCategory = _fetcher.newBlogCategory();
        blogCategory.setCategory(blogid);
        blogCategory.setCategoryURL(_blog.getBlogURL() + requestedCategory);

        BlogEntry[] entries;
        Map fetchMap = new HashMap();

        if (BlojsomUtils.checkNullOrBlank(requestedCategory)) {
          fetchMap.put(BlojsomFetcher.FETCHER_FLAVOR, DEFAULT_FLAVOR_HTML);
          fetchMap.put(BlojsomFetcher.FETCHER_NUM_POSTS_INTEGER, new Integer(numposts));
          entries = _fetcher.fetchEntries(fetchMap, _blogUser);
        } else {
          fetchMap.put(BlojsomFetcher.FETCHER_CATEGORY, blogCategory);
          fetchMap.put(BlojsomFetcher.FETCHER_NUM_POSTS_INTEGER, new Integer(numposts));
          entries = _fetcher.fetchEntries(fetchMap, _blogUser);
        }

        if (entries != null && entries.length > 0) {
          for (int x = 0; x < entries.length; x++) {
            BlogEntry entry = entries[x];
            Hashtable entrystruct = new Hashtable();
            entrystruct.put(MEMBER_POSTID, entry.getId());
            entrystruct.put(MEMBER_BLOGID, entry.getCategory());
            entrystruct.put(MEMBER_TITLE, entry.getEscapedTitle());
            entrystruct.put(MEMBER_URL, entry.getEscapedLink());
            entrystruct.put(MEMBER_CONTENT, entry.getTitle() + "\n" + entry.getDescription());
            entrystruct.put(MEMBER_DATECREATED, entry.getDate());
            entrystruct.put(MEMBER_AUTHORNAME, _blog.getBlogOwner());
            entrystruct.put(MEMBER_AUTHOREMAIL, _blog.getBlogOwnerEmail());
            recentPosts.add(entrystruct);
          }
        }
      }

      return recentPosts;
    } catch (BlojsomException e) {
      _logger.error(
          "Failed to authenticate user [" + userid + "] with password [" + password + "]");
      throw new XmlRpcException(AUTHORIZATION_EXCEPTION, AUTHORIZATION_EXCEPTION_MSG);
    }
  }
  /**
   * Send trackback pings to a comma-separated list of trackback URLs
   *
   * @param blog Blog information
   * @param entry Blog entry
   * @param blogTrackbackURLs Trackback URLs
   */
  protected void sendTrackbackPings(Blog blog, BlogEntry entry, String blogTrackbackURLs) {
    // Build the URL parameters for the trackback ping URL
    StringBuffer trackbackPingURLParameters = new StringBuffer();
    try {
      trackbackPingURLParameters
          .append("&")
          .append(TrackbackPlugin.TRACKBACK_URL_PARAM)
          .append("=")
          .append(entry.getLink());
      trackbackPingURLParameters
          .append("&")
          .append(TrackbackPlugin.TRACKBACK_TITLE_PARAM)
          .append("=")
          .append(URLEncoder.encode(entry.getTitle(), UTF8));
      trackbackPingURLParameters
          .append("&")
          .append(TrackbackPlugin.TRACKBACK_BLOG_NAME_PARAM)
          .append("=")
          .append(URLEncoder.encode(blog.getBlogName(), UTF8));

      String excerpt = entry.getDescription().replaceAll("<.*?>", "");
      if (excerpt.length() > 255) {
        excerpt = excerpt.substring(0, 251);
        excerpt += "...";
      }
      trackbackPingURLParameters
          .append("&")
          .append(TrackbackPlugin.TRACKBACK_EXCERPT_PARAM)
          .append("=")
          .append(URLEncoder.encode(excerpt, UTF8));
    } catch (UnsupportedEncodingException e) {
      _logger.error(e);
    }

    String[] trackbackURLs = BlojsomUtils.parseDelimitedList(blogTrackbackURLs, WHITESPACE);
    if (trackbackURLs != null && trackbackURLs.length > 0) {
      for (int i = 0; i < trackbackURLs.length; i++) {
        String trackbackURL = trackbackURLs[i].trim();
        StringBuffer trackbackPingURL = new StringBuffer(trackbackURL);

        _logger.debug(
            "Automatically sending trackback ping to URL: " + trackbackPingURL.toString());

        try {
          URL trackbackUrl = new URL(trackbackPingURL.toString());

          // Open a connection to the trackback URL and read its input
          HttpURLConnection trackbackUrlConnection =
              (HttpURLConnection) trackbackUrl.openConnection();
          trackbackUrlConnection.setRequestMethod("POST");
          trackbackUrlConnection.setRequestProperty("Content-Encoding", UTF8);
          trackbackUrlConnection.setRequestProperty(
              "Content-Type", "application/x-www-form-urlencoded");
          trackbackUrlConnection.setRequestProperty(
              "Content-Length", "" + trackbackPingURLParameters.length());
          trackbackUrlConnection.setDoOutput(true);
          trackbackUrlConnection
              .getOutputStream()
              .write(trackbackPingURLParameters.toString().getBytes(UTF8));
          trackbackUrlConnection.connect();
          BufferedReader trackbackStatus =
              new BufferedReader(new InputStreamReader(trackbackUrlConnection.getInputStream()));
          String line;
          StringBuffer status = new StringBuffer();
          while ((line = trackbackStatus.readLine()) != null) {
            status.append(line).append("\n");
          }
          trackbackUrlConnection.disconnect();

          _logger.debug("Trackback status for ping to " + trackbackURL + ": " + status.toString());
        } catch (IOException e) {
          _logger.error(e);
        }
      }
    }
  }
  /**
   * Process the blog entries
   *
   * @param httpServletRequest Request
   * @param httpServletResponse Response
   * @param user {@link BlogUser} instance
   * @param context Context
   * @param entries Blog entries retrieved for the particular request
   * @return Modified set of blog entries
   * @throws BlojsomPluginException If there is an error processing the blog entries
   */
  public BlogEntry[] process(
      HttpServletRequest httpServletRequest,
      HttpServletResponse httpServletResponse,
      BlogUser user,
      Map context,
      BlogEntry[] entries)
      throws BlojsomPluginException {
    String wantsToSeeMore = httpServletRequest.getParameter(SHOW_ME_MORE_PARAM);
    if ("y".equalsIgnoreCase(wantsToSeeMore)) {
      return entries;
    } else {
      ShowMeMoreConfiguration showMeMoreConfiguration;
      try {
        showMeMoreConfiguration =
            ShowMeMoreUtilities.loadConfiguration(
                user.getId(), _showMeMoreConfigurationFile, _blojsomConfiguration, _servletConfig);
      } catch (IOException e) {
        _logger.error(e);

        return entries;
      }

      int cutoff = showMeMoreConfiguration.getCutoff();
      String textCutoff = showMeMoreConfiguration.getTextCutoff();
      String moreText = showMeMoreConfiguration.getMoreText();
      String textCutoffStart = showMeMoreConfiguration.getTextCutoffStart();
      String textCutoffEnd = showMeMoreConfiguration.getTextCutoffEnd();

      for (int i = 0; i < entries.length; i++) {
        BlogEntry entry = entries[i];
        String description = entry.getDescription();
        StringBuffer partialDescription = new StringBuffer();
        int indexOfCutoffText;

        if (!BlojsomUtils.checkNullOrBlank(textCutoffStart)
            && !BlojsomUtils.checkNullOrBlank(textCutoffEnd)) {
          StringBuffer showMeMoreText = new StringBuffer("<a href=\"");
          showMeMoreText.append(entry.getLink());
          showMeMoreText.append("&amp;");
          showMeMoreText.append(SHOW_ME_MORE_PARAM);
          showMeMoreText.append("=y\">");
          showMeMoreText.append(moreText);
          showMeMoreText.append("</a>");
          Pattern cutoffPattern =
              Pattern.compile(
                  "(" + textCutoffStart + ".*?" + textCutoffEnd + ").*?",
                  Pattern.DOTALL | Pattern.MULTILINE | Pattern.CASE_INSENSITIVE);
          Matcher cutoffMatcher = cutoffPattern.matcher(description);
          if (cutoffMatcher.find()) {
            description = cutoffMatcher.replaceAll(showMeMoreText.toString());
            entry.setDescription(description);
          }
        }

        if (!BlojsomUtils.checkNullOrBlank(textCutoff)) {
          indexOfCutoffText = description.indexOf(textCutoff);
          if (indexOfCutoffText != -1) {
            partialDescription.append(description.substring(0, indexOfCutoffText));
            partialDescription.append("&nbsp; <a href=\"");
            partialDescription.append(entry.getLink());
            partialDescription.append("&amp;");
            partialDescription.append(SHOW_ME_MORE_PARAM);
            partialDescription.append("=y\">");
            partialDescription.append(moreText);
            partialDescription.append("</a>");
            entry.setDescription(partialDescription.toString());
          } else if ((cutoff > 0) && (description.length() > cutoff)) {
            partialDescription.append(description.substring(0, cutoff));
            partialDescription.append("&nbsp; <a href=\"");
            partialDescription.append(entry.getLink());
            partialDescription.append("&amp;");
            partialDescription.append(SHOW_ME_MORE_PARAM);
            partialDescription.append("=y\">");
            partialDescription.append(moreText);
            partialDescription.append("</a>");
            entry.setDescription(partialDescription.toString());
          }
        } else if ((cutoff > 0) && (description.length() > cutoff)) {
          partialDescription.append(description.substring(0, cutoff));
          partialDescription.append("&nbsp; <a href=\"");
          partialDescription.append(entry.getLink());
          partialDescription.append("&amp;");
          partialDescription.append(SHOW_ME_MORE_PARAM);
          partialDescription.append("=y\">");
          partialDescription.append(moreText);
          partialDescription.append("</a>");
          entry.setDescription(partialDescription.toString());
        }
      }

      return entries;
    }
  }