package com.todoroo.astrid.actfm.sync.messages;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import org.json.JSONArray;
import org.json.JSONObject;
import android.text.TextUtils;
import android.util.Log;
import com.todoroo.andlib.data.Property.IntegerProperty;
import com.todoroo.andlib.data.Property.LongProperty;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.astrid.actfm.sync.ActFmInvoker;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.actfm.sync.ActFmSyncThread.SyncMessageCallback;
import com.todoroo.astrid.dao.HistoryDao;
import com.todoroo.astrid.dao.RemoteModelDao;
import com.todoroo.astrid.dao.UserDao;
import com.todoroo.astrid.data.History;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.User;
public class FetchHistory<TYPE extends RemoteModel> {
private static final String ERROR_TAG = "actfm-fetch-history"; //$NON-NLS-1$
private final RemoteModelDao<TYPE> dao;
private final LongProperty historyTimeProperty;
private final IntegerProperty historyHasMoreProperty;
private final String table;
private final String uuid;
private final String taskTitle;
private final long modifiedAfter;
private final int offset;
private final SyncMessageCallback done;
@Autowired
private ActFmInvoker actFmInvoker;
@Autowired
private HistoryDao historyDao;
@Autowired
private UserDao userDao;
@Autowired
private ActFmPreferenceService actFmPreferenceService;
public FetchHistory(RemoteModelDao<TYPE> dao, LongProperty historyTimeProperty, IntegerProperty historyHasMoreProperty,
String table, String uuid, String taskTitle, long modifiedAfter, int offset, SyncMessageCallback done) {
DependencyInjectionService.getInstance().inject(this);
this.dao = dao;
this.historyTimeProperty = historyTimeProperty;
this.historyHasMoreProperty = historyHasMoreProperty;
this.table = table;
this.uuid = uuid;
this.taskTitle = taskTitle;
this.modifiedAfter = modifiedAfter;
this.offset = offset;
this.done = done;
}
@SuppressWarnings("nls")
public void execute() {
new Thread(new Runnable() {
@Override
public void run() {
String token = actFmPreferenceService.getToken();
if (TextUtils.isEmpty(token) || TextUtils.isEmpty(uuid))
return;
ArrayList<Object> params = new ArrayList<Object>();
if (NameMaps.TABLE_ID_TASKS.equals(table))
params.add("task_id");
else if (NameMaps.TABLE_ID_TAGS.equals(table))
params.add("tag_id");
else
return;
params.add(uuid);
if (modifiedAfter > 0) {
params.add("modified_after"); params.add(modifiedAfter / 1000L);
}
if (offset > 0) {
params.add("offset"); params.add(offset);
}
params.add("token"); params.add(token);
try {
JSONObject result = actFmInvoker.invoke("model_history_list", params.toArray(new Object[params.size()]));
JSONArray list = result.optJSONArray("list");
boolean hasMore = result.optInt("has_more") > 0;
long time = result.optLong("time") * 1000;
if (hasMore && offset == 0) {
historyDao.deleteWhere(History.TARGET_ID.eq(uuid));
}
if (list != null) {
for (int i = 0; i < list.length(); i++) {
JSONObject historyJson = list.optJSONObject(i);
if (historyJson != null) {
History history = new History();
history.setValue(History.TABLE_ID, table);
history.setValue(History.TARGET_ID, uuid);
history.setValue(History.UUID, historyJson.optString("id") + ":" + uuid);
String userId = historyJson.optString("user_id");
if (userId.equals(ActFmPreferenceService.userId()))
userId = Task.USER_ID_SELF;
history.setValue(History.USER_UUID, historyJson.optString("user_id"));
history.setValue(History.COLUMN, historyJson.optString("column"));
history.setValue(History.OLD_VALUE, historyJson.optString("prev"));
history.setValue(History.NEW_VALUE, historyJson.optString("value"));
history.setValue(History.CREATED_AT, historyJson.optLong("created_at") * 1000);
JSONArray taskObj = historyJson.optJSONArray("task");
if (taskObj != null) {
history.setValue(History.TABLE_ID, NameMaps.TABLE_ID_TASKS);
history.setValue(History.TARGET_ID, taskObj.optString(0));
history.setValue(History.TASK, taskObj.toString());
} else if (NameMaps.TABLE_ID_TASKS.equals(table) && !TextUtils.isEmpty(taskTitle)) {
taskObj = new JSONArray();
taskObj.put(uuid);
taskObj.put(taskTitle);
history.setValue(History.TASK, taskObj.toString());
}
if (NameMaps.TABLE_ID_TAGS.equals(table)) {
history.setValue(History.TAG_ID, uuid);
}
if (historyDao.update(History.UUID.eq(history.getValue(History.UUID)), history) <= 0) {
historyDao.createNew(history);
}
}
}
if (time > 0) {
TYPE template;
try {
template = dao.getModelClass().newInstance();
template.setValue(historyTimeProperty, time);
if (modifiedAfter == 0 || hasMore)
template.setValue(historyHasMoreProperty, hasMore ? 1 : 0);
dao.update(RemoteModel.UUID_PROPERTY.eq(uuid), template);
} catch (InstantiationException e) {
Log.e(ERROR_TAG, "Error instantiating model for recording time", e);
} catch (IllegalAccessException e) {
Log.e(ERROR_TAG, "Error instantiating model for recording time", e);
}
}
}
JSONObject users = result.optJSONObject("users");
if (users != null) {
Iterator<String> keys = users.keys();
while (keys.hasNext()) {
String key = keys.next();
JSONObject userObj = users.optJSONObject(key);
if (userObj != null) {
String userUuid = userObj.optString("id");
if (RemoteModel.isUuidEmpty(uuid))
continue;
User user = new User();
user.setValue(User.FIRST_NAME, userObj.optString("first_name"));
user.setValue(User.LAST_NAME, userObj.optString("last_name"));
user.setValue(User.NAME, userObj.optString("name"));
user.setValue(User.PICTURE, userObj.optString("picture"));
user.setValue(User.UUID, userUuid);
if (userDao.update(User.UUID.eq(userUuid), user) <= 0) {
userDao.createNew(user);
}
}
}
}
} catch (IOException e) {
Log.e(ERROR_TAG, "Error getting model history", e);
}
if (done != null)
done.runOnSuccess();
}
}).start();
}
}