/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.timsu.astrid.data.tag;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import com.timsu.astrid.data.LegacyAbstractController;
import com.timsu.astrid.data.tag.AbstractTagModel.TagModelDatabaseHelper;
import com.timsu.astrid.data.tag.TagToTaskMapping.TagToTaskMappingDatabaseHelper;
import com.timsu.astrid.data.task.AbstractTaskModel.TaskModelDatabaseHelper;
import com.timsu.astrid.data.task.TaskIdentifier;
import com.todoroo.astrid.provider.Astrid2TaskProvider;
/** Controller for Tag-related operations */
@SuppressWarnings("nls")
@Deprecated
public class TagController extends LegacyAbstractController {
private SQLiteDatabase tagDatabase, tagToTaskMapDatabase;
// --- tag batch operations
/** Get a list of all tags */
public LinkedList<TagModelForView> getAllTags()
throws SQLException {
LinkedList<TagModelForView> list = new LinkedList<TagModelForView>();
Cursor cursor = tagDatabase.query(tagsTable,
TagModelForView.FIELD_LIST, null, null, null, null, null, null);
try {
if(cursor.getCount() == 0)
return list;
do {
cursor.moveToNext();
list.add(new TagModelForView(cursor));
} while(!cursor.isLast());
} finally {
cursor.close();
}
return list;
}
// --- tag to task map batch operations
/** Get a list of all tags as an id => tag map */
public HashMap<TagIdentifier, TagModelForView> getAllTagsAsMap() throws SQLException {
HashMap<TagIdentifier, TagModelForView> map = new HashMap<TagIdentifier, TagModelForView>();
for(TagModelForView tag : getAllTags())
map.put(tag.getTagIdentifier(), tag);
return map;
}
/** Get a list of tag identifiers for the given task */
public LinkedList<TagIdentifier> getTaskTags(TaskIdentifier
taskId) throws SQLException {
LinkedList<TagIdentifier> list = new LinkedList<TagIdentifier>();
Cursor cursor = tagToTaskMapDatabase.query(tagTaskTable,
TagToTaskMapping.FIELD_LIST, TagToTaskMapping.TASK + " = ?",
new String[] { taskId.idAsString() }, null, null, null);
try {
if(cursor.getCount() == 0)
return list;
do {
cursor.moveToNext();
list.add(new TagToTaskMapping(cursor).getTag());
} while(!cursor.isLast());
} finally {
cursor.close();
}
return list;
}
/** Get a list of task identifiers for the given tag.
* This searches for TAGGED tasks only.
* Use getUntaggedTasks() to get a list of UNTAGGED tasks **/
public LinkedList<TaskIdentifier> getTaggedTasks(TagIdentifier tagId)
throws SQLException {
LinkedList<TaskIdentifier> list = new LinkedList<TaskIdentifier>();
Cursor cursor = tagToTaskMapDatabase.query(tagTaskTable,
TagToTaskMapping.FIELD_LIST, TagToTaskMapping.TAG + " = ?",
new String[] { tagId.idAsString() }, null, null, null);
try {
if(cursor.getCount() == 0)
return list;
do {
cursor.moveToNext();
list.add(new TagToTaskMapping(cursor).getTask());
} while(!cursor.isLast());
} finally {
cursor.close();
}
return list;
}
/** Returns a list of task identifiers in the provided set that are UNtagged.
*
* The calling SubActivity must provide the set of tasks, since
* TagController cannot access the appropriate instance of TaskController.
*
* The current implementation is not very efficient, because queries
* the TagToTask map once for each active task.
**/
public LinkedList<TaskIdentifier> getUntaggedTasks() throws SQLException {
HashSet<Long> ids = new HashSet<Long>();
String[] tagMapColumns = new String[] { TagToTaskMapping.TASK };
Cursor tagMapCursor = tagToTaskMapDatabase.query(tagTaskTable,
tagMapColumns, null, null, TagToTaskMapping.TASK, null,
TagToTaskMapping.TASK + " ASC");
SQLiteDatabase taskDatabase = new TaskModelDatabaseHelper(context,
tasksTable, tasksTable).getReadableDatabase();
String[] taskColumns = new String[] { KEY_ROWID };
Cursor taskCursor = taskDatabase.query(tasksTable, taskColumns,
null, null, null, null, KEY_ROWID + " ASC");
LinkedList<TaskIdentifier> list = new LinkedList<TaskIdentifier>();
try {
if(taskCursor.getCount() == 0)
return list;
do {
taskCursor.moveToNext();
ids.add(taskCursor.getLong(0));
} while(!taskCursor.isLast());
if(tagMapCursor.getCount() > 0) {
do {
tagMapCursor.moveToNext();
ids.remove(tagMapCursor.getLong(0));
} while(!tagMapCursor.isLast());
}
} finally {
taskCursor.close();
tagMapCursor.close();
taskDatabase.close();
}
for(Long id : ids)
list.add(new TaskIdentifier(id));
return list;
}
// --- single tag operations
public TagIdentifier createTag(String name) throws SQLException {
if(name == null)
throw new NullPointerException("Name can't be null");
TagModelForView newTag = new TagModelForView(name);
long row = tagDatabase.insertOrThrow(tagsTable, AbstractTagModel.NAME,
newTag.getMergedValues());
return new TagIdentifier(row);
}
/** Creates or saves the given tag */
public boolean saveTag(AbstractTagModel tag) throws SQLException {
boolean saveSucessful;
if(tag.getTagIdentifier() == null) {
long newRow = tagDatabase.insert(tagsTable, AbstractTagModel.NAME,
tag.getMergedValues());
tag.setTagIdentifier(new TagIdentifier(newRow));
saveSucessful = newRow >= 0;
} else {
long id = tag.getTagIdentifier().getId();
saveSucessful = tagDatabase.update(tagsTable, tag.getSetValues(),
KEY_ROWID + "=" + id, null) > 0;
}
return saveSucessful;
}
/** Returns a TaskModelForView corresponding to the given Tag Name */
public TagModelForView fetchTagFromName(String name) throws SQLException {
Cursor cursor = tagDatabase.query(true, tagsTable,
TagModelForView.FIELD_LIST,
AbstractTagModel.NAME + " = ?", new String[] {name}, null, null, null, null);
try {
if (cursor != null && cursor.getCount() > 0) {
cursor.moveToFirst();
TagModelForView model = new TagModelForView(cursor);
return model;
}
return null;
} finally {
if(cursor != null)
cursor.close();
}
}
/** Returns a TaskModelForView corresponding to the given TagIdentifier */
public TagModelForView fetchTagForView(TagIdentifier tagId) throws SQLException {
long id = tagId.getId();
Cursor cursor = tagDatabase.query(true, tagsTable,
TagModelForView.FIELD_LIST,
KEY_ROWID + "=" + id, null, null, null, null, null);
try {
if (cursor != null) {
cursor.moveToFirst();
TagModelForView model = new TagModelForView(cursor);
return model;
}
throw new SQLException("Returned empty set!");
} finally {
if(cursor != null)
cursor.close();
}
}
/** Deletes the tag and removes tag/task mappings */
public boolean deleteTag( TagIdentifier tagId)
throws SQLException{
if(tagToTaskMapDatabase.delete(tagTaskTable,
TagToTaskMapping.TAG + " = " + tagId.idAsString(), null) < 0)
return false;
int res = tagDatabase.delete(tagsTable,
KEY_ROWID + " = " + tagId.idAsString(), null);
// notify modification
Astrid2TaskProvider.notifyDatabaseModification();
return res > 0;
}
// --- single tag to task operations
/** Remove the given tag from the task */
public boolean removeTag(TaskIdentifier taskId, TagIdentifier tagId)
throws SQLException{
int res = tagToTaskMapDatabase.delete(tagTaskTable,
String.format("%s = ? AND %s = ?",
TagToTaskMapping.TAG, TagToTaskMapping.TASK),
new String[] { tagId.idAsString(), taskId.idAsString() });
// notify modification
Astrid2TaskProvider.notifyDatabaseModification();
return res > 0;
}
/** Add the given tag to the task */
public boolean addTag(TaskIdentifier taskId, TagIdentifier tagId)
throws SQLException {
ContentValues values = new ContentValues();
values.put(TagToTaskMapping.TAG, tagId.getId());
values.put(TagToTaskMapping.TASK, taskId.getId());
long res = tagToTaskMapDatabase.insert(tagTaskTable, TagToTaskMapping.TAG,
values);
// notify modification
Astrid2TaskProvider.notifyDatabaseModification();
return res >= 0;
}
// --- boilerplate
/**
* Constructor - takes the context to allow the database to be
* opened/created
*/
public TagController(Context context) {
super(context);
}
/**
* Open the notes database. If it cannot be opened, try to create a new
* instance of the database. If it cannot be created, throw an exception to
* signal the failure
*
* @return this (self reference, allowing this to be chained in an
* initialization call)
* @throws SQLException if the database could be neither opened or created
*/
@Override
public synchronized void open() throws SQLException {
tagToTaskMapDatabase = new TagToTaskMappingDatabaseHelper(context,
tagTaskTable, tagTaskTable).getWritableDatabase();
tagDatabase = new TagModelDatabaseHelper(context,
tagsTable, tagsTable).getWritableDatabase();
}
/** Closes database resource */
@Override
public void close() {
if(tagDatabase != null)
tagDatabase.close();
if(tagToTaskMapDatabase != null)
tagToTaskMapDatabase.close();
}
}