package com.buddycloud.model;
import java.text.ParseException;
import java.util.Iterator;
import java.util.Map;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.Context;
import android.os.AsyncTask;
import com.buddycloud.http.BuddycloudHTTPHelper;
import com.buddycloud.log.Logger;
import com.buddycloud.model.dao.UnreadCountersDAO;
import com.buddycloud.preferences.Preferences;
import com.buddycloud.utils.JIDUtils;
import com.buddycloud.utils.TimeUtils;
public class SyncModel extends AbstractModel<JSONObject, JSONObject, String> {
private static SyncModel instance;
private static String TAG = SyncModel.class.toString();
private static final int PAGE_SIZE = 31;
private static final int PAGE_SIZE_NO_SUMMARY = 10;
private static final String SYNC_ENDPOINT = "/sync";
private SyncModel() {}
public static SyncModel getInstance() {
if (instance == null) {
instance = new SyncModel();
}
return instance;
}
private void parseChannelCounters(UnreadCountersDAO unreadCountersDAO, String channel,
JSONObject oldSummary, JSONObject newSummary) {
int oldTotalCount = 0;
int oldMentionsCount = 0;
int oldRepliesCount = 0;
boolean hasOldCounter = oldSummary != null;
if (hasOldCounter) {
oldTotalCount = oldSummary.optInt("totalCount");
oldMentionsCount = oldSummary.optInt("mentionsCount");
oldRepliesCount = oldSummary.optInt("replyCount");
}
JSONObject unreadCounters = new JSONObject();
try {
int lastWeekActivity = newSummary.has("postsThisWeek") ? newSummary.optJSONArray("postsThisWeek").length() : 0;
unreadCounters.put("totalCount", newSummary.optInt("totalCount") + oldTotalCount);
unreadCounters.put("mentionsCount", newSummary.optInt("mentionsCount") + oldMentionsCount);
unreadCounters.put("replyCount", newSummary.optInt("repliesCount") + oldRepliesCount);
unreadCounters.put("lastWeekActivity", lastWeekActivity);
} catch (JSONException e) {/*Do nothing*/}
if (hasOldCounter) {
unreadCountersDAO.update(channel, unreadCounters);
} else {
unreadCountersDAO.insert(channel, unreadCounters);
}
}
@SuppressWarnings("unchecked")
private void parse(Context context, JSONObject summary, Map<String, JSONObject> oldCounters) {
final UnreadCountersDAO unreadCountersDAO = UnreadCountersDAO.getInstance(context);
String lastUpdate = Preferences.getPreference(context, Preferences.LAST_UPDATE, TimeUtils.OLDEST_DATE);
String syncTimestamp = lastUpdate;
Iterator<String> keys = summary.keys();
while (keys.hasNext()) {
String node = keys.next();
String channel = JIDUtils.nodeToChannel(node);
JSONObject channelSummary = summary.optJSONObject(node);
String channelUpdated = channelSummary.optString("lastUpdated", null);
if (channelUpdated != null && after(channelUpdated, syncTimestamp)) {
syncTimestamp = channelUpdated;
}
parseChannelCounters(unreadCountersDAO, channel,
oldCounters.get(channel), channelSummary);
}
Preferences.setPreference(context, Preferences.LAST_UPDATE, syncTimestamp);
}
private boolean after(String dateA, String dateB) {
try {
return TimeUtils.fromISOToDate(dateA).after(
TimeUtils.fromISOToDate(dateB));
} catch (ParseException e) {
Logger.error(TAG, "Could not parse dates.", e);
return false;
}
}
@Override
public JSONObject getFromCache(Context context, String... p) {
UnreadCountersDAO unreadCountersDAO = UnreadCountersDAO.getInstance(context);
Map<String, JSONObject> counters = unreadCountersDAO.getAll();
return new JSONObject(counters);
}
@Override
public void getFromServer(Context context, final ModelCallback<JSONObject> callback, String... p) {
}
public void visitChannel(Context context, String channelJid) {
UnreadCountersDAO dao = UnreadCountersDAO.getInstance(context);
JSONObject summary = dao.get(channelJid);
try {
if (summary != null) {
summary.put("mentionsCount", 0);
summary.put("totalCount", 0);
summary.put("replyCount", 0);
summary.put("visitCount", summary.optInt("visitCount") + 1);
dao.update(channelJid, summary);
} else {
summary = new JSONObject();
summary.put("visitCount", 1);
dao.insert(channelJid, summary);
}
} catch (JSONException e) {
Logger.error(TAG, e.getMessage(), e);
}
notifyChanged();
}
public void resetUnreadCounters(Context context) {
UnreadCountersDAO.getInstance(context).resetUnreadCounters();
notifyChanged();
}
public void fill(Context context, final ModelCallback<Void> callback, String... p) {
UnreadCountersDAO unreadCountersDAO = UnreadCountersDAO.getInstance(context);
sync(unreadCountersDAO.getAll(), context, callback);
}
private void sync(final Map<String, JSONObject> oldCounters, final Context context,
final ModelCallback<Void> callback) {
BuddycloudHTTPHelper.getObject(syncUrlWithSummary(context), context,
new ModelCallback<JSONObject>() {
@Override
public void success(JSONObject newCounters) {
parse(context, newCounters, oldCounters);
notifyChanged();
if (callback != null) {
callback.success(null);
}
}
@Override
public void error(Throwable throwable) {
if (callback != null) {
callback.error(throwable);
}
}
});
}
public void syncNoSummary(final Context context, final ModelCallback<Void> callback) {
BuddycloudHTTPHelper.getObject(syncUrl(context), context,
new ModelCallback<JSONObject>() {
@SuppressWarnings("unchecked")
@Override
public void success(final JSONObject newPosts) {
if (callback != null) {
callback.success(null);
}
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
PostsModel postsModel = PostsModel.getInstance();
Iterator<String> keys = newPosts.keys();
while (keys.hasNext()) {
String key = keys.next();
String channelJid = JIDUtils.nodeToChannel(key);
JSONArray channelPosts = newPosts.optJSONArray(key);
for (int i = 0; i < channelPosts.length(); i++) {
try {
JSONObject post = channelPosts.getJSONObject(i);
postsModel.persistSinglePost(context, channelJid, post);
} catch (Exception e) {
// Best effort
}
}
}
return null;
}
}.execute();
}
@Override
public void error(Throwable throwable) {
if (callback != null) {
callback.error(throwable);
}
}
});
}
private String since(Context context) {
String lastUpdate = Preferences.getPreference(context, Preferences.LAST_UPDATE);
return lastUpdate == null ? TimeUtils.OLDEST_DATE : lastUpdate;
}
private String syncUrlWithSummary(Context context) {
String params = "?max=" + PAGE_SIZE + "&since=" + since(context) + "&summary=true";
String apiAddress = Preferences.getPreference(context, Preferences.API_ADDRESS);
return apiAddress + SYNC_ENDPOINT + params;
}
private String syncUrl(Context context) {
String params = "?max=" + PAGE_SIZE_NO_SUMMARY + "&since=" + since(context);
String apiAddress = Preferences.getPreference(context, Preferences.API_ADDRESS);
return apiAddress + SYNC_ENDPOINT + params;
}
@Override
public void save(Context context, JSONObject object,
ModelCallback<JSONObject> callback, String... p) {
}
@Override
public void delete(Context context, ModelCallback<Void> callback, String... p) {
// TODO Auto-generated method stub
}
}