@Override
  public void setRemark(Context ctx, PeopleId friendId, String remark) {
    ParamChecker.notNull("ctx", ctx);
    ParamChecker.notNull("friendId", friendId);

    RemarkEntries res = ensureRemarkEntries(ctx.getViewer());
    if (StringUtils.isEmpty(remark)) res.remove(friendId);
    else res.put(friendId, remark);
  }
  @Override
  public boolean destroyCustomCircle(Context ctx, int circleId) {
    ParamChecker.notNull("ctx", ctx);
    long viewerId = ctx.getViewer();
    AccountHelper.checkUser(account, ctx, viewerId);

    FriendEntries fes = getFriendEntries(ctx, viewerId);
    if (fes != null) {
      boolean b = fes.destroyCircle(circleId);
      putFriendEntries(viewerId, fes);
      return b;
    } else {
      return false;
    }
  }
  @Override
  public void setFriendIntoCircles(Context ctx, int reason, PeopleId friendId, int... circleIds) {
    ParamChecker.notNull("ctx", ctx);
    ParamChecker.notNull("friendId", friendId);
    ParamChecker.notNull("circleIds", circleIds);
    long viewerId = ctx.getViewer();
    AccountHelper.checkUser(account, ctx, viewerId);

    FriendEntries fes = getFriendEntries(ctx, viewerId);
    if (fes == null || !fes.hasAllCircles(circleIds)) throw new ServerException(E.INVALID_CIRCLE);

    FriendEntry fe = fes.ensureFriend(friendId);
    fe.setCircles(reason, DateHelper.nowMillis(), circleIds);
    putFriendEntries(viewerId, fes);
  }
  @Override
  public Circle createCustomCircle(Context ctx, String circleName) {
    ParamChecker.notNull("ctx", ctx);
    long viewerId = ctx.getViewer();
    AccountHelper.checkUser(account, ctx, viewerId);

    FriendEntries fes = getFriendEntries(ctx, viewerId);
    int[] customCircleIds = fes.circles.getCircleIds(Circle.MIN_CUSTOM_CIRCLE_ID);
    int newCircleId = newCircleId(customCircleIds);
    if (newCircleId < 0) throw new ServerException(E.TOO_MANY_CIRCLES, "Too many circles");

    Circle newCircle = new Circle(newCircleId, circleName, DateHelper.nowMillis(), null);
    fes.circles.add(newCircle);
    putFriendEntries(viewerId, fes);
    return newCircle;
  }
  @Override
  public void removeFriendsInCircle(Context ctx, PeopleIds friendIds, int circleId) {
    ParamChecker.notNull("ctx", ctx);
    ParamChecker.notNull("friendIds", friendIds);
    ParamChecker.notNull("circleId", circleId);

    long viewerId = ctx.getViewer();
    AccountHelper.checkUser(account, ctx, viewerId);

    FriendEntries fes = getFriendEntries(ctx, viewerId);
    for (PeopleId friendId : friendIds) {
      FriendEntry fe = fes.ensureFriend(friendId);
      fe.removeCircle(circleId);
    }
    putFriendEntries(viewerId, fes);
  }
  @Override
  public boolean updateCustomCircleName(Context ctx, int circleId, String circleName) {
    ParamChecker.notNull("ctx", ctx);
    ParamChecker.notEmpty("circleName", circleName);
    long viewerId = ctx.getViewer();
    AccountHelper.checkUser(account, ctx, viewerId);

    if (!Circle.isCustomCircleId(circleId)) return false;

    FriendEntries fes = getFriendEntries(ctx, viewerId);
    if (fes != null) {
      fes.updateCircleName(circleId, circleName);
      putFriendEntries(viewerId, fes);
      return true;
    } else {
      return false;
    }
  }
  @Override
  public void addFriendsIntoCircle(Context ctx, int reason, PeopleIds friendIds, int circleId) {
    ParamChecker.notNull("ctx", ctx);
    ParamChecker.notNull("friendIds", friendIds);
    ParamChecker.notNull("circleI", circleId);

    long viewerId = ctx.getViewer();
    AccountHelper.checkUser(account, ctx, viewerId);

    long now = DateHelper.nowMillis();
    FriendEntries fes = getFriendEntries(ctx, viewerId);
    if (fes == null || !fes.hasCircle(circleId)) throw new ServerException(E.INVALID_CIRCLE);

    for (PeopleId friendId : friendIds) {
      FriendEntry fe = fes.ensureFriend(friendId);
      fe.addCircle(circleId, reason, now);
    }
    putFriendEntries(viewerId, fes);
  }