package org.iatoki.judgels.raguel.forum.thread.post;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import org.iatoki.judgels.play.IdentityUtils;
import org.iatoki.judgels.play.Page;
import org.iatoki.judgels.raguel.forum.Forum;
import org.iatoki.judgels.raguel.forum.ForumDao;
import org.iatoki.judgels.raguel.forum.ForumLastPostDao;
import org.iatoki.judgels.raguel.forum.ForumModel;
import org.iatoki.judgels.raguel.forum.ForumServiceUtils;
import org.iatoki.judgels.raguel.forum.module.ForumModuleDao;
import org.iatoki.judgels.raguel.forum.module.ForumModuleFactory;
import org.iatoki.judgels.raguel.forum.thread.ForumThread;
import org.iatoki.judgels.raguel.forum.thread.ForumThreadDao;
import org.iatoki.judgels.raguel.forum.thread.ForumThreadModel;
import org.iatoki.judgels.raguel.forum.thread.ForumThreadServiceUtils;
import org.iatoki.judgels.raguel.user.postcount.UserPostCountDao;
import org.iatoki.judgels.raguel.user.postcount.UserPostCountModel;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.stream.Collectors;
@Singleton
public final class ThreadPostServiceImpl implements ThreadPostService {
private final ForumDao forumDao;
private final ForumLastPostDao forumLastPostDao;
private final ForumModuleDao forumModuleDao;
private final ForumModuleFactory forumModuleFactory;
private final ForumThreadDao forumThreadDao;
private final ThreadPostDao threadPostDao;
private final PostContentDao postContentDao;
private final UserPostCountDao userPostCountDao;
@Inject
public ThreadPostServiceImpl(ForumDao forumDao, ForumLastPostDao forumLastPostDao, ForumModuleDao forumModuleDao, ForumModuleFactory forumModuleFactory, ForumThreadDao forumThreadDao, ThreadPostDao threadPostDao, PostContentDao postContentDao, UserPostCountDao userPostCountDao) {
this.forumDao = forumDao;
this.forumLastPostDao = forumLastPostDao;
this.forumModuleDao = forumModuleDao;
this.forumModuleFactory = forumModuleFactory;
this.forumThreadDao = forumThreadDao;
this.threadPostDao = threadPostDao;
this.postContentDao = postContentDao;
this.userPostCountDao = userPostCountDao;
}
@Override
public ThreadPost findThreadPostById(long threadPostId) {
ThreadPostModel threadPostModel = threadPostDao.findById(threadPostId);
ForumThreadModel forumThreadModel = forumThreadDao.findByJid(threadPostModel.threadJid);
ForumModel forumModel = forumDao.findByJid(forumThreadModel.forumJid);
Forum forum = ForumServiceUtils.createForumWithParentFromModel(forumDao, forumLastPostDao, forumModuleDao, forumModuleFactory, forumModel);
ForumThread forumThread = ForumThreadServiceUtils.createForumThreadFromModelAndForum(forumThreadModel, forum);
List<PostContentModel> postContentModels = postContentDao.findSortedByFiltersEq("timeCreate", "asc", "", ImmutableMap.of(PostContentModel_.postJid, threadPostModel.jid), 0, -1);
List<PostContent> postContents = postContentModels.stream().map(m -> new PostContent(m.id, m.postJid, m.subject, m.content, new Date(m.timeCreate))).collect(Collectors.toList());
long userPostCount = getUserPostCountByUserJid(threadPostModel.userCreate);
return ThreadPostServiceUtils.createThreadPostFromModel(threadPostModel, forumThread, postContents, userPostCount);
}
@Override
public Map<String, Long> getThreadPostsJidToIdMap(List<String> threadPostJids) {
List<ThreadPostModel> threadPostModels = threadPostDao.getByJids(threadPostJids);
return threadPostModels.stream().collect(Collectors.toMap(m -> m.jid, m -> m.id));
}
@Override
public Map<String, String> getThreadPostsJidToUserJidMap(List<String> threadPostJids) {
List<ThreadPostModel> threadPostModels = threadPostDao.getByJids(threadPostJids);
return threadPostModels.stream().collect(Collectors.toMap(m -> m.jid, m -> m.userCreate));
}
@Override
public long getUserPostCountByUserJid(String userJid) {
return userPostCountDao.getByUserJid(userJid).postCount;
}
@Override
public long countThreadPost(ForumThread forumThread) {
return threadPostDao.countByFiltersEq("", ImmutableMap.of(ThreadPostModel_.threadJid, forumThread.getJid()));
}
@Override
public List<ThreadPostWithLevel> getAllThreadPostsWithLevel(ForumThread forumThread) {
List<ThreadPostModel> threadPostModels = threadPostDao.findSortedByFiltersEq("timeCreate", "asc", "", ImmutableMap.of(ThreadPostModel_.threadJid, forumThread.getJid()), 0, -1);
ThreadPostModel firstThreadPostModel = threadPostModels.get(0);
Map<String, Stack<ThreadPostModel>> threadPostsModelMap = Maps.newHashMap();
Map<String, Long> userJidToPostCountMap = getUserJidToPostCountMap(threadPostModels.stream().map(m -> m.userCreate).collect(Collectors.toList()));
for (ThreadPostModel model : threadPostModels) {
if ((model.replyJid != null) && !model.replyJid.isEmpty()) {
Stack<ThreadPostModel> threadPostsModelStack;
if (!threadPostsModelMap.containsKey(model.replyJid)) {
threadPostsModelStack = new Stack<>();
} else {
threadPostsModelStack = threadPostsModelMap.get(model.replyJid);
}
threadPostsModelStack.push(model);
threadPostsModelMap.put(model.replyJid, threadPostsModelStack);
}
}
ImmutableList.Builder<ThreadPostWithLevel> threadPostsWithLevelBuilder = ImmutableList.builder();
Map<String, ThreadPost> threadPostsMap = Maps.newHashMap();
Stack<ThreadPostModelWithLevel> threadPostsModelStack = new Stack<>();
threadPostsModelStack.push(new ThreadPostModelWithLevel(firstThreadPostModel, 0));
while (!threadPostsModelStack.isEmpty()) {
ThreadPostModelWithLevel threadPostModelWithLevel = threadPostsModelStack.pop();
int childLevel = threadPostModelWithLevel.level + 1;
if (threadPostsModelMap.containsKey(threadPostModelWithLevel.threadPostModel.jid)) {
Stack<ThreadPostModel> threadPostsModelStack1 = threadPostsModelMap.get(threadPostModelWithLevel.threadPostModel.jid);
while (!threadPostsModelStack1.isEmpty()) {
threadPostsModelStack.push(new ThreadPostModelWithLevel(threadPostsModelStack1.pop(), childLevel));
}
}
List<PostContentModel> postContentModels = postContentDao.findSortedByFiltersEq("timeCreate", "asc", "", ImmutableMap.of(PostContentModel_.postJid, threadPostModelWithLevel.threadPostModel.jid), 0, -1);
List<PostContent> postContents = postContentModels.stream().map(m -> new PostContent(m.id, m.postJid, m.subject, m.content, new Date(m.timeCreate))).collect(Collectors.toList());
ThreadPost threadPost = ThreadPostServiceUtils.createThreadPostFromModel(threadPostModelWithLevel.threadPostModel, forumThread, postContents, userJidToPostCountMap.get(threadPostModelWithLevel.threadPostModel.userCreate));
threadPostsWithLevelBuilder.add(new ThreadPostWithLevel(threadPost, threadPostModelWithLevel.level));
threadPostsMap.put(threadPost.getJid(), threadPost);
}
return threadPostsWithLevelBuilder.build();
}
@Override
public Page<ThreadPost> getPageOfThreadPosts(ForumThread forumThread, long pageIndex, long pageSize, String orderBy, String orderDir, String filterString) {
long totalRowsCount = threadPostDao.countByFiltersEq(filterString, ImmutableMap.of(ThreadPostModel_.threadJid, forumThread.getJid()));
List<ThreadPostModel> threadPostModels = threadPostDao.findSortedByFiltersEq(orderBy, orderDir, filterString, ImmutableMap.of(ThreadPostModel_.threadJid, forumThread.getJid()), pageIndex * pageSize, pageSize);
ImmutableList.Builder<ThreadPost> threadPostBuilder = ImmutableList.builder();
Map<String, Long> userJidToPostCountMap = getUserJidToPostCountMap(threadPostModels.stream().map(m -> m.userCreate).collect(Collectors.toList()));
for (ThreadPostModel threadPostModel : threadPostModels) {
List<PostContentModel> postContentModels = postContentDao.findSortedByFiltersEq("timeCreate", "asc", "", ImmutableMap.of(PostContentModel_.postJid, threadPostModel.jid), 0, -1);
List<PostContent> postContents = postContentModels.stream().map(m -> new PostContent(m.id, m.postJid, m.subject, m.content, new Date(m.timeCreate))).collect(Collectors.toList());
threadPostBuilder.add(ThreadPostServiceUtils.createThreadPostFromModel(threadPostModel, forumThread, postContents, userJidToPostCountMap.get(threadPostModel.userCreate)));
}
return new Page<>(threadPostBuilder.build(), totalRowsCount, pageIndex, pageSize);
}
@Override
public void createPost(ForumThread forumThread, String userJid, String subject, String body, String userIpAddress) {
ThreadPostModel threadPostModel = new ThreadPostModel();
threadPostModel.threadJid = forumThread.getJid();
threadPostDao.persist(threadPostModel, userJid, userIpAddress);
PostContentModel postContentModel = new PostContentModel();
postContentModel.postJid = threadPostModel.jid;
postContentModel.subject = subject;
postContentModel.content = body;
postContentDao.persist(postContentModel, userJid, userIpAddress);
UserPostCountModel userPostCountModel;
if (userPostCountDao.existsByUserJid(userJid)) {
userPostCountModel = userPostCountDao.getByUserJid(userJid);
userPostCountModel.postCount++;
userPostCountDao.edit(userPostCountModel, userJid, userIpAddress);
} else {
userPostCountModel = new UserPostCountModel();
userPostCountModel.userJid = userJid;
userPostCountModel.postCount = postContentDao.getCountByUserJid(userJid);
userPostCountDao.persist(userPostCountModel, userJid, userIpAddress);
}
updateThreadAndParents(forumThread, userJid, userIpAddress);
}
@Override
public void editPost(ThreadPost threadPost, String userJid, String subject, String body, String userIpAddress) {
ThreadPostModel threadPostModel = threadPostDao.findByJid(threadPost.getJid());
PostContentModel postContentModel = new PostContentModel();
postContentModel.postJid = threadPostModel.jid;
postContentModel.subject = subject;
postContentModel.content = body;
postContentDao.persist(postContentModel, userJid, userIpAddress);
threadPostDao.edit(threadPostModel, userJid, userIpAddress);
if (threadPostModel.replyJid == null) {
ForumThreadModel forumThreadModel = forumThreadDao.findByJid(threadPostModel.threadJid);
forumThreadModel.name = postContentModel.subject;
forumThreadDao.edit(forumThreadModel, userJid, userIpAddress);
ForumServiceUtils.updateForumAndParents(forumDao, forumLastPostDao, threadPost.getThread().getParentForum(), userJid, userIpAddress);
} else {
updateThreadAndParents(threadPost.getThread(), userJid, userIpAddress);
}
}
@Override
public void replyPost(ThreadPost threadPost, String userJid, String subject, String body, String userIpAddress) {
ThreadPostModel threadPostModel = new ThreadPostModel();
threadPostModel.threadJid = threadPost.getThread().getJid();
threadPostModel.replyJid = threadPost.getJid();
threadPostDao.persist(threadPostModel, userJid, userIpAddress);
PostContentModel postContentModel = new PostContentModel();
postContentModel.postJid = threadPostModel.jid;
postContentModel.subject = subject;
postContentModel.content = body;
postContentDao.persist(postContentModel, userJid, userIpAddress);
UserPostCountModel userPostCountModel;
if (userPostCountDao.existsByUserJid(userJid)) {
userPostCountModel = userPostCountDao.getByUserJid(userJid);
userPostCountModel.postCount++;
userPostCountDao.edit(userPostCountModel, userJid, userIpAddress);
} else {
userPostCountModel = new UserPostCountModel();
userPostCountModel.userJid = userJid;
userPostCountModel.postCount = postContentDao.getCountByUserJid(userJid);
userPostCountDao.persist(userPostCountModel, userJid, userIpAddress);
}
updateThreadAndParents(threadPost.getThread(), userJid, userIpAddress);
}
private Map<String, Long> getUserJidToPostCountMap(List<String> userJids) {
List<UserPostCountModel> postCountModelList = userPostCountDao.getByUserJids(userJids);
Set<String> allUsers = userJids.stream().collect(Collectors.toSet());
Set<String> existInDb = postCountModelList.stream().map(m -> m.userJid).collect(Collectors.toSet());
allUsers.removeAll(existInDb);
for (String userJid : allUsers) {
long postCount = postContentDao.getCountByUserJid(userJid);
UserPostCountModel userPostCountModel = new UserPostCountModel();
userPostCountModel.postCount = postCount;
userPostCountModel.userJid = userJid;
// TODO inject userJid and userIpAddress
userPostCountDao.persist(userPostCountModel, IdentityUtils.getUserJid(), IdentityUtils.getIpAddress());
postCountModelList.add(userPostCountModel);
}
return postCountModelList.stream().collect(Collectors.toMap(m -> m.userJid, m -> m.postCount));
}
private void updateThreadAndParents(ForumThread forumThread, String userJid, String userIpAddress) {
ForumThreadModel forumThreadModel = forumThreadDao.findByJid(forumThread.getJid());
forumThreadDao.edit(forumThreadModel, userJid, userIpAddress);
ForumServiceUtils.updateForumAndParents(forumDao, forumLastPostDao, forumThread.getParentForum(), userJid, userIpAddress);
}
private class ThreadPostModelWithLevel {
private final ThreadPostModel threadPostModel;
private final int level;
public ThreadPostModelWithLevel(ThreadPostModel threadPostModel, int level) {
this.threadPostModel = threadPostModel;
this.level = level;
}
}
}