/*
   * request info about a specific blog
   */
  public static void updateBlogInfo(
      long blogId, final String blogUrl, final UpdateBlogInfoListener infoListener) {
    // must pass either a valid id or url
    final boolean hasBlogId = (blogId != 0);
    final boolean hasBlogUrl = !TextUtils.isEmpty(blogUrl);
    if (!hasBlogId && !hasBlogUrl) {
      AppLog.w(T.READER, "cannot get blog info without either id or url");
      if (infoListener != null) {
        infoListener.onResult(null);
      }
      return;
    }

    RestRequest.Listener listener =
        new RestRequest.Listener() {
          @Override
          public void onResponse(JSONObject jsonObject) {
            handleUpdateBlogInfoResponse(jsonObject, infoListener);
          }
        };
    RestRequest.ErrorListener errorListener =
        new RestRequest.ErrorListener() {
          @Override
          public void onErrorResponse(VolleyError volleyError) {
            // authentication error may indicate that API access has been disabled for this blog
            int statusCode = VolleyUtils.statusCodeFromVolleyError(volleyError);
            boolean isAuthErr = (statusCode == HttpStatus.SC_FORBIDDEN);
            // if we failed to get the blog info using the id and this isn't an authentication
            // error, try again using just the domain
            if (!isAuthErr && hasBlogId && hasBlogUrl) {
              AppLog.w(T.READER, "failed to get blog info by id, retrying with url");
              updateBlogInfo(0, blogUrl, infoListener);
            } else {
              AppLog.e(T.READER, volleyError);
              if (infoListener != null) {
                infoListener.onResult(null);
              }
            }
          }
        };

    if (hasBlogId) {
      WordPress.getRestClientUtilsV1_1().get("read/sites/" + blogId, listener, errorListener);
    } else {
      WordPress.getRestClientUtilsV1_1()
          .get(
              "read/sites/" + UrlUtils.urlEncode(UrlUtils.getHost(blogUrl)),
              listener,
              errorListener);
    }
  }
  public static void undoBlockBlogFromReader(final BlockedBlogResult blockResult) {
    if (blockResult == null) {
      return;
    }
    if (blockResult.deletedPosts != null) {
      ReaderPostTable.addOrUpdatePosts(null, blockResult.deletedPosts);
    }

    com.wordpress.rest.RestRequest.Listener listener =
        new RestRequest.Listener() {
          @Override
          public void onResponse(JSONObject jsonObject) {
            boolean success = (jsonObject != null && jsonObject.optBoolean("success"));
            // re-follow the blog if it was being followed prior to the block
            if (success && blockResult.wasFollowing) {
              followBlogById(blockResult.blogId, true, null);
            } else if (!success) {
              AppLog.w(T.READER, "failed to unblock blog " + blockResult.blogId);
            }
          }
        };
    RestRequest.ErrorListener errorListener =
        new RestRequest.ErrorListener() {
          @Override
          public void onErrorResponse(VolleyError volleyError) {
            AppLog.e(T.READER, volleyError);
          }
        };

    AppLog.i(T.READER, "unblocking blog " + blockResult.blogId);
    String path = "me/block/sites/" + Long.toString(blockResult.blogId) + "/delete";
    WordPress.getRestClientUtilsV1_1().post(path, listener, errorListener);
  }
 public static void updateFeedInfo(
     long feedId, String feedUrl, final UpdateBlogInfoListener infoListener) {
   RestRequest.Listener listener =
       new RestRequest.Listener() {
         @Override
         public void onResponse(JSONObject jsonObject) {
           handleUpdateBlogInfoResponse(jsonObject, infoListener);
         }
       };
   RestRequest.ErrorListener errorListener =
       new RestRequest.ErrorListener() {
         @Override
         public void onErrorResponse(VolleyError volleyError) {
           AppLog.e(T.READER, volleyError);
           if (infoListener != null) {
             infoListener.onResult(null);
           }
         }
       };
   String path;
   if (feedId != 0) {
     path = "read/feed/" + feedId;
   } else {
     path = "read/feed/" + UrlUtils.urlEncode(feedUrl);
   }
   WordPress.getRestClientUtilsV1_1().get(path, listener, errorListener);
 }
  public static boolean followBlogById(
      final long blogId, final boolean isAskingToFollow, final ActionListener actionListener) {
    if (blogId == 0) {
      if (actionListener != null) {
        actionListener.onActionResult(false);
      }
      return false;
    }

    ReaderBlogTable.setIsFollowedBlogId(blogId, isAskingToFollow);
    ReaderPostTable.setFollowStatusForPostsInBlog(blogId, isAskingToFollow);

    if (isAskingToFollow) {
      AnalyticsUtils.trackWithBlogDetails(AnalyticsTracker.Stat.READER_BLOG_FOLLOWED, blogId);
    } else {
      AnalyticsUtils.trackWithBlogDetails(AnalyticsTracker.Stat.READER_BLOG_UNFOLLOWED, blogId);
    }

    final String actionName = (isAskingToFollow ? "follow" : "unfollow");
    final String path =
        "sites/" + blogId + "/follows/" + (isAskingToFollow ? "new" : "mine/delete");

    com.wordpress.rest.RestRequest.Listener listener =
        new RestRequest.Listener() {
          @Override
          public void onResponse(JSONObject jsonObject) {
            boolean success = isFollowActionSuccessful(jsonObject, isAskingToFollow);
            if (success) {
              AppLog.d(T.READER, "blog " + actionName + " succeeded");
            } else {
              AppLog.w(
                  T.READER,
                  "blog " + actionName + " failed - " + jsonToString(jsonObject) + " - " + path);
              localRevertFollowBlogId(blogId, isAskingToFollow);
            }
            if (actionListener != null) {
              actionListener.onActionResult(success);
            }
          }
        };
    RestRequest.ErrorListener errorListener =
        new RestRequest.ErrorListener() {
          @Override
          public void onErrorResponse(VolleyError volleyError) {
            AppLog.w(T.READER, "blog " + actionName + " failed with error");
            AppLog.e(T.READER, volleyError);
            localRevertFollowBlogId(blogId, isAskingToFollow);
            if (actionListener != null) {
              actionListener.onActionResult(false);
            }
          }
        };
    WordPress.getRestClientUtilsV1_1().post(path, listener, errorListener);

    return true;
  }
  /** like/unlike the passed post */
  public static boolean performLikeAction(final ReaderPost post, final boolean isAskingToLike) {
    // do nothing if post's like state is same as passed
    boolean isCurrentlyLiked = ReaderPostTable.isPostLikedByCurrentUser(post);
    if (isCurrentlyLiked == isAskingToLike) {
      AppLog.w(T.READER, "post like unchanged");
      return false;
    }

    // update like status and like count in local db
    int numCurrentLikes = ReaderPostTable.getNumLikesForPost(post.blogId, post.postId);
    int newNumLikes = (isAskingToLike ? numCurrentLikes + 1 : numCurrentLikes - 1);
    if (newNumLikes < 0) {
      newNumLikes = 0;
    }
    ReaderPostTable.setLikesForPost(post, newNumLikes, isAskingToLike);
    ReaderLikeTable.setCurrentUserLikesPost(post, isAskingToLike);

    final String actionName = isAskingToLike ? "like" : "unlike";
    String path = "sites/" + post.blogId + "/posts/" + post.postId + "/likes/";
    if (isAskingToLike) {
      path += "new";
    } else {
      path += "mine/delete";
    }

    com.wordpress.rest.RestRequest.Listener listener =
        new RestRequest.Listener() {
          @Override
          public void onResponse(JSONObject jsonObject) {
            AppLog.d(T.READER, String.format("post %s succeeded", actionName));
          }
        };

    RestRequest.ErrorListener errorListener =
        new RestRequest.ErrorListener() {
          @Override
          public void onErrorResponse(VolleyError volleyError) {
            String error = VolleyUtils.errStringFromVolleyError(volleyError);
            if (TextUtils.isEmpty(error)) {
              AppLog.w(T.READER, String.format("post %s failed", actionName));
            } else {
              AppLog.w(T.READER, String.format("post %s failed (%s)", actionName, error));
            }
            AppLog.e(T.READER, volleyError);
            ReaderPostTable.setLikesForPost(post, post.numLikes, post.isLikedByCurrentUser);
            ReaderLikeTable.setCurrentUserLikesPost(post, post.isLikedByCurrentUser);
          }
        };

    WordPress.getRestClientUtilsV1_1().post(path, listener, errorListener);
    return true;
  }
  /*
   * block a blog - result includes the list of posts that were deleted by the block so they
   * can be restored if the user undoes the block
   */
  public static BlockedBlogResult blockBlogFromReader(
      final long blogId, final ActionListener actionListener) {
    final BlockedBlogResult blockResult = new BlockedBlogResult();
    blockResult.blogId = blogId;
    blockResult.deletedPosts = ReaderPostTable.getPostsInBlog(blogId, 0, false);
    blockResult.wasFollowing = ReaderBlogTable.isFollowedBlog(blogId);

    ReaderPostTable.deletePostsInBlog(blogId);
    ReaderBlogTable.setIsFollowedBlogId(blogId, false);

    com.wordpress.rest.RestRequest.Listener listener =
        new RestRequest.Listener() {
          @Override
          public void onResponse(JSONObject jsonObject) {
            if (actionListener != null) {
              actionListener.onActionResult(true);
            }
          }
        };
    RestRequest.ErrorListener errorListener =
        new RestRequest.ErrorListener() {
          @Override
          public void onErrorResponse(VolleyError volleyError) {
            AppLog.e(T.READER, volleyError);
            ReaderPostTable.addOrUpdatePosts(null, blockResult.deletedPosts);
            if (blockResult.wasFollowing) {
              ReaderBlogTable.setIsFollowedBlogId(blogId, true);
            }
            if (actionListener != null) {
              actionListener.onActionResult(false);
            }
          }
        };

    AppLog.i(T.READER, "blocking blog " + blogId);
    String path = "me/block/sites/" + Long.toString(blogId) + "/new";
    WordPress.getRestClientUtilsV1_1().post(path, listener, errorListener);

    return blockResult;
  }
  private static boolean internalFollowFeed(
      final long feedId,
      final String feedUrl,
      final boolean isAskingToFollow,
      final ActionListener actionListener) {
    // feedUrl is required
    if (TextUtils.isEmpty(feedUrl)) {
      if (actionListener != null) {
        actionListener.onActionResult(false);
      }
      return false;
    }

    if (feedId != 0) {
      ReaderBlogTable.setIsFollowedFeedId(feedId, isAskingToFollow);
      ReaderPostTable.setFollowStatusForPostsInFeed(feedId, isAskingToFollow);
    }

    if (isAskingToFollow) {
      AnalyticsTracker.track(AnalyticsTracker.Stat.READER_BLOG_FOLLOWED);
    } else {
      AnalyticsTracker.track(AnalyticsTracker.Stat.READER_BLOG_UNFOLLOWED);
    }

    final String actionName = (isAskingToFollow ? "follow" : "unfollow");
    final String path =
        "read/following/mine/"
            + (isAskingToFollow ? "new" : "delete")
            + "?url="
            + UrlUtils.urlEncode(feedUrl);

    com.wordpress.rest.RestRequest.Listener listener =
        new RestRequest.Listener() {
          @Override
          public void onResponse(JSONObject jsonObject) {
            boolean success = isFollowActionSuccessful(jsonObject, isAskingToFollow);
            if (success) {
              AppLog.d(T.READER, "feed " + actionName + " succeeded");
            } else {
              AppLog.w(
                  T.READER,
                  "feed " + actionName + " failed - " + jsonToString(jsonObject) + " - " + path);
              localRevertFollowFeedId(feedId, isAskingToFollow);
            }
            if (actionListener != null) {
              actionListener.onActionResult(success);
            }
          }
        };
    RestRequest.ErrorListener errorListener =
        new RestRequest.ErrorListener() {
          @Override
          public void onErrorResponse(VolleyError volleyError) {
            AppLog.w(T.READER, "feed " + actionName + " failed with error");
            AppLog.e(T.READER, volleyError);
            localRevertFollowFeedId(feedId, isAskingToFollow);
            if (actionListener != null) {
              actionListener.onActionResult(false);
            }
          }
        };
    WordPress.getRestClientUtilsV1_1().post(path, listener, errorListener);

    return true;
  }