/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.service;
import org.json.JSONException;
import org.json.JSONObject;
import android.database.Cursor;
import android.text.TextUtils;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Field;
import com.todoroo.andlib.sql.Functions;
import com.todoroo.andlib.sql.Join;
import com.todoroo.andlib.sql.Order;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.astrid.actfm.sync.ActFmSyncService;
import com.todoroo.astrid.adapter.UpdateAdapter;
import com.todoroo.astrid.api.PermaSql;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
import com.todoroo.astrid.dao.TagDataDao;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.dao.UserActivityDao;
import com.todoroo.astrid.data.History;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.SyncFlags;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.User;
import com.todoroo.astrid.data.UserActivity;
import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.tags.TaskToTagMetadata;
/**
* Service layer for {@link TagData}-centered activities.
*
* @author Tim Su <tim@todoroo.com>
*
*/
public class TagDataService {
@Autowired TagDataDao tagDataDao;
@Autowired TaskDao taskDao;
@Autowired UserActivityDao userActivityDao;
public TagDataService() {
DependencyInjectionService.getInstance().inject(this);
}
// --- service layer
/**
* Query underlying database
* @param query
* @return
*/
public TodorooCursor<TagData> query(Query query) {
return tagDataDao.query(query);
}
/**
* Save a single piece of metadata
* @param metadata
*/
public boolean save(TagData tagData) {
return tagDataDao.persist(tagData);
}
/**
*
* @param properties
* @param id id
* @return item, or null if it doesn't exist
*/
public TagData fetchById(long id, Property<?>... properties) {
return tagDataDao.fetch(id, properties);
}
/**
* Find a tag by name
* @return null if doesn't exist
*/
public TagData getTagByName(String name, Property<?>... properties) {
TodorooCursor<TagData> cursor = tagDataDao.query(Query.select(properties).where(TagData.NAME.eqCaseInsensitive(name)));
try {
if(cursor.getCount() == 0)
return null;
cursor.moveToFirst();
return new TagData(cursor);
} finally {
cursor.close();
}
}
/**
* Fetch tag data
* @param queryTemplate
* @param constraint
* @param properties
* @return
*/
@SuppressWarnings("nls")
public TodorooCursor<TagData> fetchFiltered(String queryTemplate, CharSequence constraint,
Property<?>... properties) {
Criterion whereConstraint = null;
if(constraint != null)
whereConstraint = Functions.upper(TagData.NAME).like("%" +
constraint.toString().toUpperCase() + "%");
if(queryTemplate == null) {
if(whereConstraint == null)
return tagDataDao.query(Query.select(properties));
else
return tagDataDao.query(Query.select(properties).where(whereConstraint));
}
String sql;
if(whereConstraint != null) {
if(!queryTemplate.toUpperCase().contains("WHERE"))
sql = queryTemplate + " WHERE " + whereConstraint;
else
sql = queryTemplate.replace("WHERE ", "WHERE " + whereConstraint + " AND ");
} else
sql = queryTemplate;
sql = PermaSql.replacePlaceholders(sql);
return tagDataDao.query(Query.select(properties).withQueryTemplate(sql));
}
private static Query queryForTagData(TagData tagData, Criterion extraCriterion, String userTableAlias, Property<?>[] activityProperties, Property<?>[] userProperties) {
Criterion criteria;
if (tagData == null)
criteria = UserActivity.DELETED_AT.eq(0);
else
criteria = Criterion.and(UserActivity.DELETED_AT.eq(0), Criterion.or(
Criterion.and(UserActivity.ACTION.eq(UserActivity.ACTION_TAG_COMMENT), UserActivity.TARGET_ID.eq(tagData.getUuid())),
Criterion.and(UserActivity.ACTION.eq(UserActivity.ACTION_TASK_COMMENT),
UserActivity.TARGET_ID.in(Query.select(TaskToTagMetadata.TASK_UUID)
.from(Metadata.TABLE).where(Criterion.and(MetadataCriteria.withKey(TaskToTagMetadata.KEY), TaskToTagMetadata.TAG_UUID.eq(tagData.getUuid())))))));
if (extraCriterion != null)
criteria = Criterion.and(criteria, extraCriterion);
Query result = Query.select(AndroidUtilities.addToArray(Property.class, activityProperties, userProperties)).where(criteria);
if (!TextUtils.isEmpty(userTableAlias))
result = result.join(Join.left(User.TABLE.as(userTableAlias), UserActivity.USER_UUID.eq(Field.field(userTableAlias + "." + User.UUID.name)))); //$NON-NLS-1$
return result;
}
public TodorooCursor<UserActivity> getUserActivityWithExtraCriteria(TagData tagData, Criterion criterion) {
if (tagData == null)
return userActivityDao.query(Query.select(UserActivity.PROPERTIES).where(
criterion).
orderBy(Order.desc(UserActivity.CREATED_AT)));
return userActivityDao.query(queryForTagData(tagData, criterion, null, UserActivity.PROPERTIES, null).orderBy(Order.desc(UserActivity.CREATED_AT)));
}
public Cursor getActivityAndHistoryForTagData(TagData tagData, Criterion extraCriterion, String userTableAlias, Property<?>...userProperties) {
Query activityQuery = queryForTagData(tagData, extraCriterion, userTableAlias, UpdateAdapter.USER_ACTIVITY_PROPERTIES, userProperties)
.from(UserActivity.TABLE);
Criterion historyCriterion;
if (tagData == null)
historyCriterion = Criterion.none;
else
historyCriterion = History.TAG_ID.eq(tagData.getUuid());
Query historyQuery = Query.select(AndroidUtilities.addToArray(Property.class, UpdateAdapter.HISTORY_PROPERTIES, userProperties)).from(History.TABLE)
.where(historyCriterion)
.join(Join.left(User.TABLE.as(userTableAlias), History.USER_UUID.eq(Field.field(userTableAlias + "." + User.UUID.name)))); //$NON-NLS-1$
Query resultQuery = activityQuery.union(historyQuery).orderBy(Order.desc("1")); //$NON-NLS-1$
return userActivityDao.query(resultQuery);
}
@SuppressWarnings("nls")
public void saveFeaturedList(JSONObject featObject) throws JSONException {
TodorooCursor<TagData> cursor = query(Query.select(TagData.PROPERTIES).where(
Criterion.and(Functions.bitwiseAnd(TagData.FLAGS, TagData.FLAG_FEATURED).gt(0), TagData.UUID.eq(featObject.get("id")))));
try {
cursor.moveToNext();
TagData tagData = new TagData();
if (!cursor.isAfterLast()) {
tagData.readFromCursor(cursor);
if(!tagData.getValue(TagData.NAME).equals(featObject.getString("name")))
TagService.getInstance().rename(tagData.getUuid(), featObject.getString("name"), true);
cursor.moveToNext();
}
ActFmSyncService.JsonHelper.featuredListFromJson(featObject, tagData);
tagData.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
save(tagData);
} finally {
cursor.close();
}
}
/**
* Return update
* @param tagData
* @return
*/
public UserActivity getLatestUpdate(TagData tagData) {
if(RemoteModel.NO_UUID.equals(tagData.getValue(TagData.UUID)))
return null;
TodorooCursor<UserActivity> updates = userActivityDao.query(queryForTagData(tagData, null, null, UserActivity.PROPERTIES, null).orderBy(Order.desc(UserActivity.CREATED_AT)).limit(1));
try {
if(updates.getCount() == 0)
return null;
updates.moveToFirst();
return new UserActivity(updates);
} finally {
updates.close();
}
}
}