package org.sana.android.app; import java.util.Collection; import java.util.PriorityQueue; import org.sana.android.provider.Encounters; import org.sana.net.Response; import org.sana.net.Response.Code; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.util.Log; /** * Manages the messages waiting to be dispatched. This class replaces * the Encounter specific QueueManager from version 1. * * @author Sana Development Team * @since 2.0 */ public class MessageQueueManager { private static final String TAG = MessageQueueManager.class.getSimpleName(); // Included for backwards compatibility 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; public enum State{ NOT_IN_QUEUE(-1), SUCCESS(0), FAILURE(1), WAITING(2), IN_PROGRESS(4); public final int code; State(int code){ this.code = code; } public static State fromCode(int code){ for(State state: State.values()){ if(state.code == code) return state; } throw new IllegalArgumentException("Illegal code: " + code); } public static State stateCompat(int code){ switch(code){ case UPLOAD_STATUS_NOT_IN_QUEUE: return NOT_IN_QUEUE; case UPLOAD_STATUS_WAITING: return WAITING; case UPLOAD_STATUS_IN_PROGRESS: return IN_PROGRESS; case UPLOAD_STATUS_SUCCESS: return SUCCESS; case UPLOAD_STATUS_FAILURE: case UPLOAD_STATUS_CREDENTIALS_INVALID: case UPLOAD_NO_CONNECTIVITY: return FAILURE; default: throw new IllegalArgumentException("Invalid code: " + code); } } } public enum Priority{ IMMEDIATE(-1), NORMAL(0), LOW(1); public final int code; Priority(int code){ this.code = code; } } public enum Method{ UNKNOWN(-1), CREATE(0), READ(1), UPDATE(2), DELETE(4); public final int code; Method(int code){ this.code = code; } public static Method fromCode(int code){ for(Method method: Method.values()){ if(method.code == code) return method; } throw new IllegalArgumentException("Illegal queue state: " + code); } public static Method fromString(String methodStr){ String[] segs = methodStr.split("."); String action = (segs.length > 0)?segs[segs.length-1]: segs[0]; for(Method method: Method.values()){ if(action.compareToIgnoreCase(method.toString()) == 0) return method; } throw new IllegalArgumentException("Illegal method: " + action); } } /** * Holds the message contents. * */ public static class MessageHolder{ public int version = 2; public Priority priority = Priority.NORMAL; public int id = -1; public Method method = Method.UNKNOWN; public Uri uri = Uri.EMPTY; public Bundle form = new Bundle(); public Bundle files = new Bundle(); public MessageHolder(){} public MessageHolder(Intent intent){ } } private static final PriorityQueue<Uri> queue = new PriorityQueue<Uri>(); private static final String[] PROJECTION = { }; /** * Initializes the in-memory queue with what is stored in the database. */ public static void initialize(Context c) { Cursor cursor = null; try { // Initialize the queue from the database } catch (Exception e) { e.printStackTrace(); } finally { if (cursor != null) cursor.close(); } } /** * Updates upload status of items currently in the queue * * @param c the current context * @param queue */ public static void persist(Context c, PriorityQueue<Uri> queue) { Log.i(TAG, "updateQueueInDB()"); } /** * Adds an item to the global queue. * * @param c the current context * @param queue the queue to update from * @param uri the procedure in the queue */ public static void add(Context c, PriorityQueue<Uri> queue, Uri uri) { queue.add(uri); setStatus(c, uri, UPLOAD_STATUS_WAITING); persist(c, queue); } /** * Removes an item to the global queue. * * @param c the current context * @param queue the queue to update from * @param uri the procedure in the queue */ public static boolean remove(Context c, PriorityQueue<Uri> queue, Uri uri) { return remove(c, uri, State.NOT_IN_QUEUE.code); } /** * 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 uri 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 remove(Context c, Uri uri, int newStatus) { if (MessageQueueManager.contains(uri)) { queue.remove(uri); persist(c, queue); setStatus(c, uri, newStatus); return true; } return false; } /** * Checks whether a procedure is in the queue * * @param queue the queue to check * @param uri the procedure look for * @return true if the procedure was in the queue and updated */ public static boolean contains(Uri uri) { return queue.contains(uri); } /** * Finds the location of procedure is in the queue * * @param queue the queue to check * @param uri the procedure look for * @return index of the procedure in the queue or -1 */ public static int indexOf(Uri uri) { if (contains(uri)) { int index = 0; for (Uri u : queue) { if (uri.equals(u)) { return index; } index++; } } return -1; } /** * Updates the upload status of a procedure. * * @param c the current context * @param uri the procedure * @param status the new status */ public static void setStatus(Context c, Uri uri, int status) { ContentValues cv = new ContentValues(); c.getContentResolver().update(uri, cv, null, null); } /** * Updates the upload status for a list procedures. * * @param c the current context * @param uris the procedures to update * @param status the new status */ public static void setStatus(Context c, Collection<Uri> uris, int status) { ContentValues cv = new ContentValues(); for (Uri uri : uris) { c.getContentResolver().update(uri, cv, null, null); } } }