/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.gtasks.sync;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import com.google.api.services.tasks.model.TaskList;
import com.google.api.services.tasks.model.TaskLists;
import com.google.api.services.tasks.model.Tasks;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gtasks.GtasksListService;
import com.todoroo.astrid.gtasks.GtasksMetadata;
import com.todoroo.astrid.gtasks.GtasksMetadataService;
import com.todoroo.astrid.gtasks.GtasksPreferenceService;
import com.todoroo.astrid.gtasks.api.GtasksInvoker;
import com.todoroo.astrid.service.AstridDependencyInjector;
import com.todoroo.astrid.service.MetadataService;
import com.todoroo.astrid.service.TaskService;
/**
* Class to handle migration of legacy metadata (old remote ids) to new
* metadata based on the official remote ids returned by the api.
* @author Sam Bosley
*
*/
public class GtasksLegacyMigrator {
@Autowired GtasksMetadataService gtasksMetadataService;
@Autowired TaskService taskService;
@Autowired MetadataService metadataService;
@Autowired GtasksListService gtasksListService;
@Autowired GtasksPreferenceService gtasksPreferenceService;
private final GtasksInvoker gtasksService;
private final GtasksListService listService;
private final TaskLists allLists;
static {
AstridDependencyInjector.initialize();
}
public GtasksLegacyMigrator(GtasksInvoker service,GtasksListService listService, TaskLists allLists) {
DependencyInjectionService.getInstance().inject(this);
this.gtasksService = service;
this.listService = listService;
this.allLists = allLists;
}
public void checkAndMigrateLegacy() throws IOException {
if (!gtasksPreferenceService.migrationHasOccurred()) {
//Fetch all tasks that have associated gtask metadata
String defaultListTitle = gtasksListService.getListName(Preferences.getStringValue(GtasksPreferenceService.PREF_DEFAULT_LIST));
String defaultListId = null;
TodorooCursor<Task> allTasksWithGtaskData = taskService.query(Query.select(Task.PROPERTIES).
where(Task.ID.in(
Query.select(Metadata.TASK).from(Metadata.TABLE).
where(Metadata.KEY.eq(GtasksMetadata.METADATA_KEY)))));
try {
if (allTasksWithGtaskData.getCount() > 0) {
//Fetch all remote tasks from all remote lists (this may be an expensive operation)
//and map their titles to their real remote ids
HashMap<String, String> taskAndListTitlesToRemoteTaskIds = new HashMap<String, String>();
List<TaskList> items = allLists.getItems();
for (TaskList list : items) {
if (list.getTitle().equals(defaultListTitle)) {
defaultListId = list.getId();
}
Tasks allTasks = gtasksService.getAllGtasksFromListId(list.getId(), false, false, 0);
List<com.google.api.services.tasks.model.Task> tasksItems = allTasks.getItems();
if (tasksItems != null) {
for (com.google.api.services.tasks.model.Task t : tasksItems) {
String key = constructKeyFromTitles(t.getTitle(), list.getTitle());
taskAndListTitlesToRemoteTaskIds.put(key, t.getId());
}
}
}
if (defaultListId == null) {
com.google.api.services.tasks.model.TaskList defaultList = gtasksService.getGtaskList("@default"); //$NON-NLS-1$
defaultListId = defaultList.getId();
}
Preferences.setString(GtasksPreferenceService.PREF_DEFAULT_LIST, defaultListId);
//For each local task, check to see if its title paired with any list title has a match in the map
for (allTasksWithGtaskData.moveToFirst(); !allTasksWithGtaskData.isAfterLast(); allTasksWithGtaskData.moveToNext()) {
GtasksTaskContainer container = gtasksMetadataService.readTaskAndMetadata(allTasksWithGtaskData);
// memorize the original listname for the case that the task is not matched,
// then it should at least be recreated in the correct list
String originalListName = gtasksListService.getListName(
container.gtaskMetadata.getValue(GtasksMetadata.LIST_ID));
String originalListId = null;
//Search through lists to see if one of them has match
String taskTitle = container.task.getValue(Task.TITLE);
boolean foundMatch = false;
items = allLists.getItems();
for (TaskList list : items) {
String expectedKey = constructKeyFromTitles(taskTitle, list.getTitle());
// save the new id of the current list
// if it matches the listname of the current task
if (list.getTitle() != null && list.getTitle().equals(originalListName))
originalListId = list.getId();
if (taskAndListTitlesToRemoteTaskIds.containsKey(expectedKey)) {
foundMatch = true;
String newRemoteTaskId = taskAndListTitlesToRemoteTaskIds.get(expectedKey);
String newRemoteListId = list.getId();
container.gtaskMetadata.setValue(GtasksMetadata.ID, newRemoteTaskId);
container.gtaskMetadata.setValue(GtasksMetadata.LIST_ID, newRemoteListId);
gtasksMetadataService.saveTaskAndMetadata(container);
break;
}
}
if (!foundMatch) {
//For non-matches, make the task look newly created
container.gtaskMetadata = GtasksMetadata.createEmptyMetadata(container.task.getId());
container.gtaskMetadata.setValue(GtasksMetadata.ID, ""); //$NON-NLS-1$
if (originalListId != null) {
// set the list-id based on the original listname, saved above during for-loop
container.gtaskMetadata.setValue(GtasksMetadata.LIST_ID, originalListId);
} else {
// remote list or local list was renamed, so put this unmatched task in the default list
container.gtaskMetadata.setValue(GtasksMetadata.LIST_ID, defaultListId);
}
gtasksMetadataService.saveTaskAndMetadata(container);
break;
}
}
}
// migrate the list-id's afterwards, so that we can put the non-matched tasks in their original lists
// if the listnames didnt change before migration (defaultlist otherwise)
listService.migrateListIds(allLists);
} finally {
allTasksWithGtaskData.close();
}
Preferences.setBoolean(GtasksPreferenceService.PREF_MIGRATION_HAS_OCCURRED, true); //Record successful migration
}
}
private String constructKeyFromTitles(String taskTitle, String listTitle) {
return taskTitle + "//" + listTitle; //$NON-NLS-1$
}
}