package io.kaif.model.debate;
import java.sql.Date;
import java.time.Instant;
import java.util.Optional;
import java.util.UUID;
import javax.annotation.Nullable;
import com.google.common.base.Preconditions;
import io.kaif.flake.FlakeId;
import io.kaif.kmark.KmarkProcessor;
import io.kaif.model.account.Account;
import io.kaif.model.account.Authorization;
import io.kaif.model.article.Article;
import io.kaif.model.zone.Zone;
import io.kaif.web.v1.dto.V1DebateDto;
public class Debate {
public static final FlakeId NO_PARENT = FlakeId.MIN;
private static final int MAX_LEVEL = 10;
public static final int CONTENT_MIN = 5;
public static final int CONTENT_MAX = 4096;
public static Debate create(Article article,
FlakeId debateId,
@Nullable Debate parent,
String content,
Account debater,
Instant now) {
Optional<Debate> optParent = Optional.ofNullable(parent);
FlakeId parentId = optParent.map(Debate::getDebateId).orElse(NO_PARENT);
int parentLevel = optParent.map(Debate::getLevel).orElse(0);
UUID replyToAccountId = optParent.map(Debate::getDebaterId).orElseGet(article::getAuthorId);
return new Debate(article.getArticleId(),
debateId,
article.getZone(),
parentId,
replyToAccountId,
parentLevel + 1,
content,
DebateContentType.MARK_DOWN,
debater.getAccountId(),
debater.getUsername(),
0,
0,
now,
now);
}
public static String renderContentPreview(String rawContent) {
return KmarkProcessor.process(rawContent);
}
private final FlakeId articleId;
private final FlakeId debateId;
private final Zone zone;
private final FlakeId parentDebateId;
private final int level;
private final String content;
private final DebateContentType contentType;
private final UUID debaterId;
private final String debaterName;
private final long upVote;
private final long downVote;
private final Instant createTime;
private final Instant lastUpdateTime;
private final UUID replyToAccountId;
Debate(FlakeId articleId,
FlakeId debateId,
Zone zone,
FlakeId parentDebateId,
UUID replyToAccountId,
int level,
String content,
DebateContentType contentType,
UUID debaterId,
String debaterName,
long upVote,
long downVote,
Instant createTime,
Instant lastUpdateTime) {
Preconditions.checkArgument(level <= MAX_LEVEL);
Preconditions.checkArgument(!NO_PARENT.equals(debateId));
this.zone = zone;
this.articleId = articleId;
this.debateId = debateId;
this.parentDebateId = parentDebateId;
this.replyToAccountId = replyToAccountId;
this.level = level;
this.content = content;
this.contentType = contentType;
this.debaterId = debaterId;
this.debaterName = debaterName;
this.upVote = upVote;
this.downVote = downVote;
this.createTime = createTime;
this.lastUpdateTime = lastUpdateTime;
}
public FlakeId getArticleId() {
return articleId;
}
public FlakeId getDebateId() {
return debateId;
}
public FlakeId getParentDebateId() {
return parentDebateId;
}
public boolean hasParent() {
return !parentDebateId.equals(NO_PARENT);
}
public int getLevel() {
return level;
}
public String getContent() {
return content;
}
public DebateContentType getContentType() {
return contentType;
}
public UUID getDebaterId() {
return debaterId;
}
public String getDebaterName() {
return debaterName;
}
public long getUpVote() {
return upVote;
}
public long getDownVote() {
return downVote;
}
public Instant getCreateTime() {
return createTime;
}
public Instant getLastUpdateTime() {
return lastUpdateTime;
}
public String getRenderContent() {
return KmarkProcessor.process(content);
}
public String getEscapeContent() {
return KmarkProcessor.escapeHtml(content);
}
public UUID getReplyToAccountId() {
return replyToAccountId;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Debate debate = (Debate) o;
if (!debateId.equals(debate.debateId)) {
return false;
}
return true;
}
@Override
public int hashCode() {
return debateId.hashCode();
}
@Override
public String toString() {
return "Debate{" +
"articleId=" + articleId +
", debateId=" + debateId +
", zone=" + zone +
", parentDebateId=" + parentDebateId +
", level=" + level +
", content='" + content + '\'' +
", contentType=" + contentType +
", debaterId=" + debaterId +
", debaterName='" + debaterName + '\'' +
", upVote=" + upVote +
", downVote=" + downVote +
", createTime=" + createTime +
", lastUpdateTime=" + lastUpdateTime +
", replyToAccountId=" + replyToAccountId +
'}';
}
public long getTotalVote() {
return upVote - downVote;
}
public boolean isMaxLevel() {
return level >= MAX_LEVEL;
}
public boolean isParent(Debate child) {
return parentDebateId.equals(child.debateId);
}
public boolean canEdit(Authorization auth) {
return auth.belongToAccount(debaterId);
}
public Debate withVote(long newUpVote, long newDownVote) {
return new Debate(articleId,
debateId,
zone,
parentDebateId,
replyToAccountId,
level,
content,
contentType,
debaterId,
debaterName,
newUpVote,
newDownVote,
createTime,
lastUpdateTime);
}
public V1DebateDto toV1Dto() {
return new V1DebateDto(articleId.toString(),
debateId.toString(),
zone.value(),
hasParent() ? parentDebateId.toString() : null,
level,
content,
debaterName,
upVote,
downVote,
Date.from(createTime),
Date.from(lastUpdateTime));
}
public Zone getZone() {
return zone;
}
public boolean isEdited() {
return lastUpdateTime.isAfter(createTime);
}
public String getShortUrlPath() {
return String.format("/d/%s", getDebateId());
}
}