package cl.monsoon.s1next.data.api.model;
import android.graphics.Color;
import android.support.annotation.Nullable;
import android.support.v4.util.SimpleArrayMap;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Objects;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@SuppressWarnings("UnusedDeclaration")
@JsonIgnoreProperties(ignoreUnknown = true)
public final class Post {
@JsonProperty("pid")
private String id;
@JsonProperty("author")
private String authorName;
@JsonProperty("authorid")
private String authorId;
@JsonProperty("message")
private String reply;
@JsonProperty("number")
private String count;
@JsonProperty("dbdateline")
private long datetime;
@JsonProperty("attachments")
private Map<Integer, Attachment> attachmentMap;
public Post() {}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getAuthorName() {
return authorName;
}
public void setAuthorName(String authorName) {
this.authorName = authorName;
}
public String getAuthorId() {
return authorId;
}
public void setAuthorId(String authorId) {
this.authorId = authorId;
}
/**
* Replies are null sometimes.
* <p>
* See https://github.com/floating-cat/S1-Next/issues/6
*/
@Nullable
public String getReply() {
return reply;
}
public void setReply(String reply) {
// Replaces "imgwidth" with "img width",
// because some img tags in S1 aren't correct.
// This may be the best way to deal with it though
// we may replace something wrong by accident.
// Also maps some colors, see mapColors(String).
this.reply = mapColors(reply).replaceAll("<imgwidth=\"", "<img width=\"");
processAttachment();
}
public String getCount() {
return count;
}
public void setCount(String count) {
this.count = count;
}
public long getDatetime() {
return datetime;
}
public void setDatetime(long datetime) {
// convert seconds to milliseconds
this.datetime = TimeUnit.SECONDS.toMillis(datetime);
}
public void setAttachmentMap(Map<Integer, Attachment> attachmentMap) {
this.attachmentMap = attachmentMap;
processAttachment();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Post post = (Post) o;
return Objects.equal(datetime, post.datetime) &&
Objects.equal(id, post.id) &&
Objects.equal(authorName, post.authorName) &&
Objects.equal(authorId, post.authorId) &&
Objects.equal(reply, post.reply) &&
Objects.equal(count, post.count) &&
Objects.equal(attachmentMap, post.attachmentMap);
}
@Override
public int hashCode() {
return Objects.hashCode(id, authorName, authorId, reply, count, datetime, attachmentMap);
}
/**
* {@link Color} doesn't support all HTML color names.
* So {@link android.text.Html#fromHtml(String)} won't
* map some color names for replies in S1.
* We need to map these color names to their hex value.
*/
private static String mapColors(String reply) {
// example: color="sienna"
// matcher.group(0): color="sienna"
// matcher.group(1): sienna
Matcher matcher = Pattern.compile("color=\"([a-zA-Z]+)\"").matcher(reply);
StringBuffer stringBuffer = new StringBuffer();
String color;
while (matcher.find()) {
// get color hex value for its color name
color = COLOR_NAME_MAP.get(matcher.group(1).toLowerCase(Locale.US));
if (color == null) {
continue;
}
// append part of the string and its color hex value
matcher.appendReplacement(stringBuffer, "color=\"" + color + "\"");
}
matcher.appendTail(stringBuffer);
return stringBuffer.toString();
}
/**
* Replaces attach tags with HTML img tags
* in order to display attachment images in TextView.
* <p>
* Also concats the missing img tag from attachment.
* See https://github.com/floating-cat/S1-Next/issues/7
*/
private void processAttachment() {
if (reply == null || attachmentMap == null) {
return;
}
for (Map.Entry<Integer, Post.Attachment> entry : attachmentMap.entrySet()) {
Post.Attachment attachment = entry.getValue();
String imgTag = "<img src=\"" + attachment.getUrl() + "\" />";
String replyCopy = reply;
// get the original string if there is nothing to replace
reply = reply.replace("[attach]" + entry.getKey() + "[/attach]", imgTag);
//noinspection StringEquality
if (reply == replyCopy) {
// concat the missing img tag
reply = reply + imgTag;
}
}
}
private static final SimpleArrayMap<String, String> COLOR_NAME_MAP;
static {
COLOR_NAME_MAP = new SimpleArrayMap<>();
COLOR_NAME_MAP.put("sienna", "#A0522D");
COLOR_NAME_MAP.put("darkolivegreen", "#556B2F");
COLOR_NAME_MAP.put("darkgreen", "#006400");
COLOR_NAME_MAP.put("darkslateblue", "#483D8B");
COLOR_NAME_MAP.put("indigo", "#4B0082");
COLOR_NAME_MAP.put("darkslategray", "#2F4F4F");
COLOR_NAME_MAP.put("darkred", "#8B0000");
COLOR_NAME_MAP.put("darkorange", "#FF8C00");
COLOR_NAME_MAP.put("slategray", "#708090");
COLOR_NAME_MAP.put("dimgray", "#696969");
COLOR_NAME_MAP.put("sandybrown", "#F4A460");
COLOR_NAME_MAP.put("yellowgreen", "#9ACD32");
COLOR_NAME_MAP.put("seagreen", "#2E8B57");
COLOR_NAME_MAP.put("mediumturquoise", "#48D1CC");
COLOR_NAME_MAP.put("royalblue", "#4169E1");
COLOR_NAME_MAP.put("orange", "#FFA500");
COLOR_NAME_MAP.put("deepskyblue", "#00BFFF");
COLOR_NAME_MAP.put("darkorchid", "#9932CC");
COLOR_NAME_MAP.put("pink", "#FFC0CB");
COLOR_NAME_MAP.put("wheat", "#F5DEB3");
COLOR_NAME_MAP.put("lemonchiffon", "#FFFACD");
COLOR_NAME_MAP.put("palegreen", "#98FB98");
COLOR_NAME_MAP.put("paleturquoise", "#AFEEEE");
COLOR_NAME_MAP.put("lightblue", "#ADD8E6");
// https://code.google.com/p/android/issues/detail?id=75953
COLOR_NAME_MAP.put("white", "#FFFFFF");
}
@JsonIgnoreProperties(ignoreUnknown = true)
public static final class Attachment {
@JsonIgnore
private final String url;
@JsonCreator
public Attachment(@JsonProperty("url") String urlPrefix,
@JsonProperty("attachment") String urlSuffix) {
this.url = urlPrefix + urlSuffix;
}
public String getUrl() {
return url;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Attachment that = (Attachment) o;
return Objects.equal(url, that.url);
}
@Override
public int hashCode() {
return Objects.hashCode(url);
}
}
}