package org.dodgybits.shuffle.android.synchronisation.tracks;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.LinkedList;
import java.util.Map;
import org.apache.http.HttpStatus;
import org.dodgybits.android.shuffle.R;
import org.dodgybits.shuffle.android.core.activity.flurry.Analytics;
import org.dodgybits.shuffle.android.core.model.EntityBuilder;
import org.dodgybits.shuffle.android.core.model.Id;
import org.dodgybits.shuffle.android.core.model.Task;
import org.dodgybits.shuffle.android.core.model.Task.Builder;
import org.dodgybits.shuffle.android.core.model.persistence.EntityPersister;
import org.dodgybits.shuffle.android.core.util.DateUtils;
import org.dodgybits.shuffle.android.synchronisation.tracks.ApiException;
import org.dodgybits.shuffle.android.synchronisation.tracks.parsing.ParseResult;
import org.dodgybits.shuffle.android.synchronisation.tracks.parsing.Parser;
import org.dodgybits.shuffle.android.synchronisation.tracks.parsing.TaskParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
import android.content.Context;
import android.util.Log;
import android.util.Xml;
/**
* @author Morten Nielsen
*/
public final class TaskSynchronizer extends Synchronizer<Task> {
private static final String cTag = "TaskSynchronizer";
private final String mTracksUrl;
private Parser<Task> mParser;
public TaskSynchronizer(
EntityPersister<Task> persister,
TracksSynchronizer tracksSynchronizer,
WebClient client,
Context context,
Analytics analytics,
int basePercent,
String tracksUrl) {
super(persister, tracksSynchronizer, client, context, basePercent);
mParser = new TaskParser(this, this, analytics);
this.mTracksUrl = tracksUrl;
}
@Override
protected EntityBuilder<Task> createBuilder() {
return Task.newBuilder();
}
@Override
protected void verifyEntitiesForSynchronization(Map<Id, Task> localEntities) {
LinkedList<Id> tasksWithoutContext = new LinkedList<Id>();
for(Task t : localEntities.values()) {
if(!t.getContextId().isInitialised()) {
tasksWithoutContext.add(t.getLocalId());
}
}
if (tasksWithoutContext.size() > 0) {
mTracksSynchronizer.postSyncMessage(R.string.cannotSyncTasksWithoutContext);
for(Id id : tasksWithoutContext) {
localEntities.remove(id);
}
}
}
@Override
protected String readingRemoteText() {
return mContext.getString(R.string.readingRemoteTasks);
}
@Override
protected String processingText() {
return mContext.getString(R.string.processingTasks);
}
@Override
protected String readingLocalText() {
return mContext.getString(R.string.readingLocalTasks);
}
@Override
protected String stageFinishedText() {
return mContext.getString(R.string.doneWithTasks);
}
protected Task createMergedLocalEntity(Task localTask, Task newTask) {
Builder builder = Task.newBuilder();
builder.mergeFrom(localTask);
builder
.setDescription(newTask.getDescription())
.setDetails(newTask.getDetails())
.setContextId(newTask.getContextId())
.setProjectId(newTask.getProjectId())
.setModifiedDate(newTask.getModifiedDate())
.setStartDate(newTask.getStartDate())
.setDeleted(newTask.isDeleted())
.setDueDate(newTask.getDueDate())
.setAllDay(newTask.isAllDay())
.setTracksId(newTask.getTracksId());
return builder.build();
}
protected String createDocumentForEntity(Task task) {
XmlSerializer serializer = Xml.newSerializer();
StringWriter writer = new StringWriter();
try {
serializer.setOutput(writer);
//serializer.startDocument("UTF-8", true);
serializer.startTag("", "todo");
if (task.isComplete()) {
String completedDateStr = DateUtils.formatIso8601Date(task.getModifiedDate());
serializer.startTag("", "completed-at").attribute("", "type", "datetime").text(completedDateStr).endTag("", "completed-at");
}
Id contextId = findTracksIdByContextId(task.getContextId());
if (contextId.isInitialised()) {
serializer.startTag("", "context-id").attribute("", "type", "integer").text(contextId.toString()).endTag("", "context-id");
}
String createdDateStr = DateUtils.formatIso8601Date(task.getCreatedDate());
serializer.startTag("", "created-at").attribute("", "type", "datetime").text(createdDateStr).endTag("", "created-at");
serializer.startTag("", "description").text(task.getDescription()).endTag("", "description");
if (task.getDueDate() != 0) {
String dueDateStr = DateUtils.formatIso8601Date(task.getDueDate());
serializer.startTag("", "due").attribute("", "type", "datetime").text(dueDateStr).endTag("", "due");
}
serializer.startTag("", "notes").text(task.getDetails() != null ? task.getDetails() : "").endTag("", "notes");
Id projectId = findTracksIdByProjectId(task.getProjectId());
if (projectId.isInitialised()) {
serializer.startTag("", "project-id").attribute("", "type", "integer").text(projectId.toString()).endTag("", "project-id");
}
if (task.getStartDate() != 0L) {
serializer.startTag("", "show-from").attribute("", "type", "datetime").text(DateUtils.formatIso8601Date(task.getStartDate())).endTag("", "show-from");
}
serializer.startTag("", "state").text(task.isComplete() ? "completed" : "active").endTag("", "state");
String updatedDateStr = DateUtils.formatIso8601Date(task.getModifiedDate());
serializer.startTag("", "updated-at").attribute("", "type", "datetime").text(updatedDateStr).endTag("", "updated-at");
serializer.endTag("", "todo");
serializer.flush();
} catch (IOException ignored) {
Log.d(cTag, "Failed to serialize task", ignored);
}
Log.d(cTag, writer.toString());
return writer.toString();
}
@Override
protected String createEntityUrl(Task task) {
return mTracksUrl + "/todos/" + task.getTracksId() + ".xml";
}
@Override
protected String entityIndexUrl() {
return mTracksUrl + "/todos.xml";
}
@Override
protected Parser<Task> getEntityParser() {
return mParser;
}
@Override
protected boolean deleteEntity(Task t) {
//Avoid extra calls if the entity is already deleted or completed.
if(t.isComplete() || t.isDeleted())
return true;
WebResult result;
try {
result = mWebClient.getUrlContent(this.createEntityUrl(t));
} catch (ApiException e1) {
return false;
}
XmlPullParser parser = Xml.newPullParser();
if(result.getStatus().getStatusCode() == HttpStatus.SC_NOT_FOUND) {
super.deleteEntity(t);
}
if(result.getStatus().getStatusCode() != HttpStatus.SC_OK) {
return false;
}
try {
parser.setInput(new StringReader(result.getContent()));
} catch (Exception e) {
return false;
}
ParseResult<Task> parseResult = getEntityParser().parseSingle(parser);
if(parseResult.IsSuccess() && parseResult.getResult().isComplete()){
Task task = Task.newBuilder().mergeFrom(t).mergeFrom(parseResult.getResult()).build();
mPersister.update(task);
return true;
}
return false;
}
}