package org.sana.android.service;
import java.util.Collection;
import java.util.PriorityQueue;
import org.sana.android.provider.Encounters;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;
/**
* Manages the items in the queue awaiting upload.
*
* @author Sana Development Team
*
*/
public class QueueManager {
private static final String TAG = QueueManager.class.getSimpleName();
public static final int UPLOAD_STATUS_NOT_IN_QUEUE = -1;
public static final int UPLOAD_STATUS_WAITING = 1;
public static final int UPLOAD_STATUS_SUCCESS = 2;
public static final int UPLOAD_STATUS_IN_PROGRESS = 3;
public static final int UPLOAD_NO_CONNECTIVITY = 4;
public static final int UPLOAD_STATUS_FAILURE = 5;
public static final int UPLOAD_STATUS_CREDENTIALS_INVALID = 6;
private static final String[] PROJECTION = { Encounters.Contract._ID,
Encounters.Contract.UUID, Encounters.Contract.PROCEDURE,
Encounters.Contract.UPLOAD_QUEUE };
/**
* Initializes the in-memory queue with what is stored in the database.
*/
public static PriorityQueue<Uri> initQueue(Context c) {
PriorityQueue<Uri> queue = new PriorityQueue<Uri>();
Cursor cursor = null;
try {
// Initialize the queue from the database
Log.i(TAG, "In initQueue - getting queue from database");
cursor = c.getContentResolver().query(
Encounters.CONTENT_URI, PROJECTION,
Encounters.Contract.UPLOAD_QUEUE + " >= 0", null,
Encounters.QUEUE_SORT_ORDER);
cursor.moveToFirst();
int position = 0;
while (!cursor.isAfterLast()) {
int savedProcedureId = cursor.getInt(0);
Uri savedProcedureUri = ContentUris.withAppendedId(
Encounters.CONTENT_URI, savedProcedureId);
Log.i(TAG, "Queue item #" + position + " has URI " + savedProcedureUri);
queue.add(savedProcedureUri);
cursor.moveToNext();
position++;
}
Log.i(TAG, "Queue has been extracted from database. Here is the "
+" queue: " + queue);
} catch (Exception e) {
Log.e(TAG, "Exception in getting queue from database: "
+ e.toString());
e.printStackTrace();
} finally {
if (cursor != null)
cursor.close();
}
return queue;
}
/**
* Updates upload status of items currently in the queue
*
* @param c the current context
* @param queue
*/
public static void updateQueueInDB(Context c, PriorityQueue<Uri> queue) {
Log.i(TAG, "Updating queue information in the database");
Log.i(TAG, "Queue is now: " + queue.toString());
// Reset all saved procedure to have -1 for UPLOAD_QUEUE. This takes
// everything out of the queue, then we re-add everything that is in the
// in-memory queue.
ContentValues cv = new ContentValues();
cv.put(Encounters.Contract.UPLOAD_QUEUE, -1);
c.getContentResolver().update(Encounters.CONTENT_URI, cv,
null, null);
// TODO(XXX) This loop is inefficient -- O(n^2) when it could be O(n)
for (Uri procedureUri : queue) {
cv = new ContentValues();
int index = queueIndex(queue, procedureUri);
Log.i(TAG, "In updateQueueInDB, queueIndex(" + procedureUri
+ ") returns: " + index);
cv.put(Encounters.Contract.UPLOAD_QUEUE, index);
c.getContentResolver().update(procedureUri, cv, null, null);
}
}
/**
* Adds an item to the global queue.
*
* @param c the current context
* @param queue the queue to update from
* @param procedureUri the procedure in the queue
*/
public static void addToQueue(Context c, PriorityQueue<Uri> queue,
Uri procedureUri)
{
queue.add(procedureUri);
setProcedureUploadStatus(c, procedureUri, UPLOAD_STATUS_WAITING);
updateQueueInDB(c, queue);
}
/**
* Removes an item to the global queue.
*
* @param c the current context
* @param queue the queue to update from
* @param procedureUri the procedure in the queue
*/
public static boolean removeFromQueue(Context c, PriorityQueue<Uri> queue,
Uri procedureUri)
{
return removeFromQueue(c, queue, procedureUri,
QueueManager.UPLOAD_STATUS_NOT_IN_QUEUE);
}
/**
* Removes an item to the global queue and updates its upload status.
*
* @param c the current context
* @param queue the queue to update from
* @param procedureUri the procedure in the queue
* @param newStatus the new upload status
* @return true if the procedure was in the queue and updated
*/
public static boolean removeFromQueue(Context c, PriorityQueue<Uri> queue,
Uri procedureUri, int newStatus)
{
if (QueueManager.isInQueue(queue, procedureUri)) {
queue.remove(procedureUri);
QueueManager.updateQueueInDB(c, queue);
QueueManager.setProcedureUploadStatus(c, procedureUri, newStatus);
return true;
}
return false;
}
/**
* Checks whether a procedure is in the queue
*
* @param queue the queue to check
* @param procedureUri the procedure look for
* @return true if the procedure was in the queue and updated
*/
public static boolean isInQueue(PriorityQueue<Uri> queue, Uri procedureUri) {
return queue.contains(procedureUri);
}
/**
* Finds the location of procedure is in the queue
*
* @param queue the queue to check
* @param procedureUri the procedure look for
* @return index of the procedure in the queue or -1
*/
public static int queueIndex(PriorityQueue<Uri> queue, Uri procedureUri) {
if (isInQueue(queue, procedureUri)) {
int index = 0;
for (Uri uri : queue) {
if (uri.equals(procedureUri)) {
return index;
}
index++;
}
}
return -1;
}
/**
* Updates the upload status of a procedure.
*
* @param c the current context
* @param procedureUri the procedure
* @param status the new status
*/
public static void setProcedureUploadStatus(Context c, Uri procedureUri,
int status)
{
Log.v(TAG, "Setting upload status for " + procedureUri + " to " + status);
ContentValues cv = new ContentValues();
cv.put(Encounters.Contract.UPLOAD_STATUS, status);
c.getContentResolver().update(procedureUri, cv, null, null);
}
/**
* Updates the upload status for a list procedures.
*
* @param c the current context
* @param procedureUris the procedures to update
* @param status the new status
*/
public static void setProceduresUploadStatus(Context c,
Collection<Uri> procedureUris, int status)
{
ContentValues cv = new ContentValues();
cv.put(Encounters.Contract.UPLOAD_STATUS, status);
for (Uri uri : procedureUris) {
c.getContentResolver().update(uri, cv, null, null);
}
}
}