package moe.chionlab.wechatmomentstat;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import moe.chionlab.wechatmomentstat.Model.SnsInfo;
/**
* Created by chiontang on 2/11/16.
*/
public class Parser {
protected Class SnsDetailParser = null;
protected Class SnsDetail = null;
protected Class SnsObject = null;
public Parser(Class SnsDetail, Class SnsDetailParser, Class SnsObject) {
this.SnsDetailParser = SnsDetailParser;
this.SnsDetail = SnsDetail;
this.SnsObject = SnsObject;
}
public SnsInfo parseSnsAllFromBin(byte[] snsDetailBin, byte[] snsObjectBin) throws Throwable {
Object snsDetail = parseSnsDetailFromBin(snsDetailBin);
Object snsObject = parseSnsObjectFromBin(snsObjectBin);
SnsInfo snsInfo = parseSnsDetail(snsDetail);
parseSnsObject(snsObject, snsInfo);
return snsInfo;
}
public Object parseSnsDetailFromBin(byte[] bin) throws Throwable {
Object snsDetail = SnsDetail.newInstance();
Method fromBinMethod = SnsDetail.getMethod(Config.SNS_DETAIL_FROM_BIN_METHOD, byte[].class);
fromBinMethod.invoke(snsDetail, bin);
return snsDetail;
}
public SnsInfo parseSnsDetail(Object snsDetail) throws Throwable {
Method snsDetailParserMethod = SnsDetailParser.getMethod(Config.SNS_XML_GENERATOR_METHOD, SnsDetail);
String xmlResult = (String)snsDetailParserMethod.invoke(this, snsDetail);
return parseTimelineXML(xmlResult);
}
public Object parseSnsObjectFromBin(byte[] bin) throws Throwable {
Object snsObject = SnsObject.newInstance();
Method fromBinMethod = SnsObject.getMethod(Config.SNS_OBJECT_FROM_BIN_METHOD, byte[].class);
fromBinMethod.invoke(snsObject, bin);
return snsObject;
}
static public SnsInfo parseTimelineXML(String xmlResult) throws Throwable {
SnsInfo currentSns = new SnsInfo();
Pattern userIdPattern = Pattern.compile("<username><!\\[CDATA\\[(.+?)\\]\\]></username>", Pattern.DOTALL);
Pattern contentPattern = Pattern.compile("<contentDesc><!\\[CDATA\\[(.+?)\\]\\]></contentDesc>", Pattern.DOTALL);
Pattern mediaPattern = Pattern.compile("<media>.*?<url.*?><!\\[CDATA\\[(.+?)\\]\\]></url>.*?</media>", Pattern.DOTALL);
Pattern timestampPattern = Pattern.compile("<createTime><!\\[CDATA\\[(.+?)\\]\\]></createTime>");
Matcher userIdMatcher = userIdPattern.matcher(xmlResult);
Matcher contentMatcher = contentPattern.matcher(xmlResult);
Matcher mediaMatcher = mediaPattern.matcher(xmlResult);
Matcher timestampMatcher = timestampPattern.matcher(xmlResult);
currentSns.id = getTimelineId(xmlResult);
currentSns.rawXML = xmlResult;
if (timestampMatcher.find()) {
currentSns.timestamp = Integer.parseInt(timestampMatcher.group(1));
}
if (userIdMatcher.find()) {
currentSns.authorId = userIdMatcher.group(1);
}
if (contentMatcher.find()) {
currentSns.content = contentMatcher.group(1);
}
while (mediaMatcher.find()) {
boolean flag = true;
for (int i=0;i<currentSns.mediaList.size();i++) {
if (currentSns.mediaList.get(i).equals(mediaMatcher.group(1))) {
flag = false;
break;
}
}
if (flag)
currentSns.mediaList.add(mediaMatcher.group(1));
}
return currentSns;
}
static public void parseSnsObject(Object aqiObject, SnsInfo matchSns) throws Throwable{
Field field = null;
Object userId=null, nickname=null;
field = aqiObject.getClass().getField(Config.PROTOCAL_SNS_OBJECT_USERID_FIELD);
userId = field.get(aqiObject);
field = aqiObject.getClass().getField(Config.PROTOCAL_SNS_OBJECT_NICKNAME_FIELD);
nickname = field.get(aqiObject);
field = aqiObject.getClass().getField(Config.PROTOCAL_SNS_OBJECT_TIMESTAMP_FIELD);
long snsTimestamp = ((Integer) field.get(aqiObject)).longValue();
if (userId == null || nickname == null) {
return;
}
matchSns.ready = true;
matchSns.authorName = (String)nickname;
field = aqiObject.getClass().getField(Config.PROTOCAL_SNS_OBJECT_COMMENTS_FIELD);
LinkedList list = (LinkedList)field.get(aqiObject);
for (int i=0;i<list.size();i++) {
Object childObject = list.get(i);
parseSnsObjectExt(childObject, true, matchSns);
}
field = aqiObject.getClass().getField(Config.PROTOCAL_SNS_OBJECT_LIKES_FIELD);
LinkedList likeList = (LinkedList)field.get(aqiObject);
for (int i=0;i<likeList.size();i++) {
Object likeObject = likeList.get(i);
parseSnsObjectExt(likeObject, false, matchSns);
}
}
static public void parseSnsObjectExt(Object apzObject, boolean isComment, SnsInfo matchSns) throws Throwable {
if (isComment) {
Field field = apzObject.getClass().getField(Config.SNS_OBJECT_EXT_AUTHOR_NAME_FIELD);
Object authorName = field.get(apzObject);
field = apzObject.getClass().getField(Config.SNS_OBJECT_EXT_REPLY_TO_FIELD);
Object replyToUserId = field.get(apzObject);
field = apzObject.getClass().getField(Config.SNS_OBJECT_EXT_COMMENT_FIELD);
Object commentContent = field.get(apzObject);
field = apzObject.getClass().getField(Config.SNS_OBJECT_EXT_AUTHOR_ID_FIELD);
Object authorId = field.get(apzObject);
if (authorId == null || commentContent == null || authorName == null) {
return;
}
for (int i = 0; i < matchSns.comments.size(); i++) {
SnsInfo.Comment loadedComment = matchSns.comments.get(i);
if (loadedComment.authorId.equals((String) authorId) && loadedComment.content.equals((String) commentContent)) {
return;
}
}
SnsInfo.Comment newComment = new SnsInfo.Comment();
newComment.authorName = (String) authorName;
newComment.content = (String) commentContent;
newComment.authorId = (String) authorId;
newComment.toUserId = (String) replyToUserId;
for (int i = 0; i < matchSns.comments.size(); i++) {
SnsInfo.Comment loadedComment = matchSns.comments.get(i);
if (replyToUserId != null && loadedComment.authorId.equals((String) replyToUserId)) {
newComment.toUser = loadedComment.authorName;
break;
}
}
matchSns.comments.add(newComment);
} else {
Field field = apzObject.getClass().getField(Config.SNS_OBJECT_EXT_AUTHOR_NAME_FIELD);
Object nickname = field.get(apzObject);
field = apzObject.getClass().getField(Config.SNS_OBJECT_EXT_AUTHOR_ID_FIELD);
Object userId = field.get(apzObject);
if (nickname == null || userId == null) {
return;
}
if (((String)userId).equals("")) {
return;
}
for (int i = 0; i < matchSns.likes.size(); i++) {
if (matchSns.likes.get(i).userId.equals((String)userId)) {
return;
}
}
SnsInfo.Like newLike = new SnsInfo.Like();
newLike.userId = (String)userId;
newLike.userName = (String)nickname;
matchSns.likes.add(newLike);
}
}
static public String getTimelineId(String xmlResult) {
Pattern idPattern = Pattern.compile("<id><!\\[CDATA\\[(.+?)\\]\\]></id>");
Matcher idMatcher = idPattern.matcher(xmlResult);
if (idMatcher.find()) {
return idMatcher.group(1);
} else {
return "";
}
}
}