package org.dodgybits.shuffle.android.core.model; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import org.dodgybits.shuffle.android.core.util.StringUtils; import org.dodgybits.shuffle.android.persistence.provider.TaskProvider; import android.text.format.DateUtils; import android.util.Log; public class TaskQuery { private static final String cTag = "TaskQuery"; private PredefinedQuery mPredefined; private List<Id> mProjects; private List<Id> mContexts; private DateRange mStartDateRange; private DateRange mDueDateRange; private DateRange mCreatedDateRange; private Boolean mComplete = null; private String mSortOrder; public final PredefinedQuery getPredefinedQuery() { return mPredefined; } public final List<Id> getProjects() { return mProjects; } public final List<Id> getContexts() { return mContexts; } public final DateRange getStartDateRange() { return mStartDateRange; } public final DateRange getDueDateRange() { return mDueDateRange; } public final DateRange getCreatedDateRange() { return mCreatedDateRange; } public final Boolean isComplete() { return mComplete; } public final String getSortOrder() { return mSortOrder; } public final boolean isInitialized() { return true; } public final String getSelection() { List<String> expressions = new ArrayList<String>(); if (mPredefined != null) { expressions.add(predefinedSelection()); } if (mProjects != null) { expressions.add(idListSelection(mProjects, TaskProvider.Tasks.PROJECT_ID)); } if (mContexts != null) { expressions.add(idListSelection(mContexts, TaskProvider.Tasks.CONTEXT_ID)); } // TODO add range values if (mComplete != null) { expressions.add(TaskProvider.Tasks.COMPLETE + "=" + (mComplete ? "1" : "0")); } return StringUtils.join(expressions, " AND "); } private String predefinedSelection() { String result; switch (mPredefined) { case nextTasks: result = "(complete = 0) AND (" + " (projectId is null) OR " + " (projectId IN (select p._id from project p where p.parallel = 1)) OR " + " (task._id = (select t2._id FROM task t2 WHERE " + " t2.projectId = task.projectId AND t2.complete = 0 " + " ORDER BY due ASC, displayOrder ASC limit 1))" + ")"; break; default: long startMS = 0L; long endOfToday = getEndDate(); long endOfTomorrow = endOfToday + DateUtils.DAY_IN_MILLIS; result = "complete = 0" + " AND (due > " + startMS + ")" + " AND ( (due < " + endOfToday + ") OR" + "( allDay = 1 AND due < " + endOfTomorrow + " ) )"; break; } return result; } private long getEndDate() { long endMS = 0L; Calendar cal = Calendar.getInstance(); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); switch (mPredefined) { case dueToday: cal.add(Calendar.DAY_OF_YEAR, 1); endMS = cal.getTimeInMillis(); break; case dueNextWeek: cal.add(Calendar.DAY_OF_YEAR, 7); endMS = cal.getTimeInMillis(); break; case dueNextMonth: cal.add(Calendar.MONTH, 1); endMS = cal.getTimeInMillis(); break; } if (Log.isLoggable(cTag, Log.INFO)) { Log.i(cTag, "Due date ends " + endMS); } return endMS; } private String idListSelection(List<Id> ids, String idName) { StringBuilder result = new StringBuilder(); if (ids.size() > 0) { result.append(idName) .append(" in (") .append(StringUtils.repeat(ids.size(), "?", ",")) .append(')'); } else { result.append(idName) .append(" is null"); } return result.toString(); } private void addIdListArgs(List<String> args, List<Id> ids) { if (ids != null && ids.size() > 0) { for(Id id : ids) { args.add(String.valueOf(id.getId())); } } } public final String[] getSelectionArgs() { List<String> args = new ArrayList<String>(); addIdListArgs(args, mProjects); addIdListArgs(args, mContexts); return args.size() > 0 ? args.toArray(new String[0]): null; } @Override public final String toString() { return String.format( "[TaskQuery predefined=%1$s projects=%2$s contexts='%3$s' " + "startDateRange=%4$s dueDateRange=%5$s createdDateRange=%6$s " + "complete=%7$s sortOrder=%8$s]", mPredefined, mProjects, mContexts, mStartDateRange, mDueDateRange, mCreatedDateRange, mComplete, mSortOrder); } public static Builder newBuilder() { return Builder.create(); } public static class Builder { private Builder() { } private TaskQuery result; private static Builder create() { Builder builder = new Builder(); builder.result = new TaskQuery(); return builder; } public PredefinedQuery getPredefined() { return result.mPredefined; } public Builder setPredefined(PredefinedQuery value) { result.mPredefined = value; return this; } public List<Id> getProjects() { return result.mProjects; } public Builder setProjects(List<Id> value) { result.mProjects = value; return this; } public List<Id> getContexts() { return result.mContexts; } public Builder setContexts(List<Id> value) { result.mContexts = value; return this; } public DateRange getStartDateRange() { return result.mStartDateRange; } public Builder setStartDateRange(DateRange value) { result.mStartDateRange = value; return this; } public DateRange getDueDateRange() { return result.mDueDateRange; } public Builder setDueDateRange(DateRange value) { result.mDueDateRange = value; return this; } public DateRange getCreatedDateRange() { return result.mCreatedDateRange; } public Builder setCreatedDateRange(DateRange value) { result.mCreatedDateRange = value; return this; } public Boolean isComplete() { return result.mComplete; } public Builder setComplete(Boolean value) { result.mComplete = value; return this; } public String getSortOrder() { return result.mSortOrder; } public Builder setSortOrder(String value) { result.mSortOrder = value; return this; } public final boolean isInitialized() { return result.isInitialized(); } public TaskQuery build() { if (result == null) { throw new IllegalStateException( "build() has already been called on this Builder."); } TaskQuery returnMe = result; result = null; return returnMe; } public Builder mergeFrom(TaskQuery query) { setPredefined(query.mPredefined); setProjects(query.mProjects); setContexts(query.mContexts); setStartDateRange(query.mStartDateRange); setDueDateRange(query.mDueDateRange); setCreatedDateRange(query.mCreatedDateRange); setComplete(query.mComplete); setSortOrder(query.mSortOrder); return this; } } public enum PredefinedQuery { nextTasks, dueToday, dueNextWeek, dueNextMonth } public final class DateRange { private final Date mBegin; private final Date mEnd; public DateRange(Date begin, Date end) { mBegin = begin; mEnd = end; } public Date getBegin() { return mBegin; } public Date getEnd() { return mEnd; } @Override public final String toString() { return String.format( "[DateRange startDate=%1$s endDate='%2$s']", mBegin, mEnd); } } }