package com.ecollege.android;
import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import roboguice.application.RoboApplication;
import roboguice.inject.SharedPreferencesName;
import roboguice.util.Ln;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.widget.Toast;
import com.ecollege.android.errors.ECollegeAlertException;
import com.ecollege.android.errors.ECollegeException;
import com.ecollege.android.errors.ECollegePromptException;
import com.ecollege.android.errors.ECollegePromptRetryException;
import com.ecollege.android.util.FileCacheManager;
import com.ecollege.android.util.VolatileCacheManager;
import com.ecollege.android.view.HeaderView;
import com.ecollege.api.ECollegeClient;
import com.ecollege.api.model.Course;
import com.ecollege.api.model.User;
import com.google.inject.Binder;
import com.google.inject.Inject;
import com.google.inject.Module;
public class ECollegeApplication extends RoboApplication implements UncaughtExceptionHandler {
@Inject SharedPreferences prefs;
final protected VolatileCacheManager volatileCache = new VolatileCacheManager(1000 * 60 * 30); // 30 minute cache
protected Context lastActiveContext;
private FileCacheManager serviceCache;
public ECollegeApplication() {
super();
lastActiveContext = this;
Thread.setDefaultUncaughtExceptionHandler(this); //global error handling on UI thread
}
private ECollegeClient client;
public ECollegeClient getClient() {
if (client == null) {
client = new ECollegeClient(getString(R.string.client_string), getString(R.string.client_id));
}
return client;
}
public String getSessionIdentifier() {
String id = getClient().getGrantToken();
return (id == null) ? "" : id;
}
@Override
protected void addApplicationModules(List<Module> modules) {
modules.add(new Module() {
public void configure(Binder binder) {
binder.bindConstant().annotatedWith(SharedPreferencesName.class).to("com.ecollege.android");
//can make a separate module as needed
}
});
}
public void logout() {
client = null;
currentUser = null;
currentCourseList = null;
serviceCache = null;
courseIdMap.clear();
volatileCache.clear();
SharedPreferences.Editor editor = prefs.edit();
editor.remove("grantToken");
editor.commit(); //change to apply if android 2.2
Intent i = new Intent(this,SplashActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
}
public void putObjectInVolatileCache(String key, Object object) {
volatileCache.put(key + "-" + getSessionIdentifier(), object);
}
public <CachedT> CachedT getObjectOfTypeFromVolatileCache(String key, Class<CachedT> clazz) {
CachedT cachedObject = volatileCache.get(key + "-" + getSessionIdentifier(), clazz);
return cachedObject;
}
public FileCacheManager getServiceCache() {
if (serviceCache == null) {
serviceCache = new FileCacheManager(this, 1000 * 60 * 60); //1 hour cache
sweepCacheInBackground();
}
return serviceCache;
}
protected void sweepCacheInBackground() {
Thread t = new Thread(new Runnable() {
public void run() {
try {
Integer count = serviceCache.removeInvalidEntries();
Ln.d(String.format("Finished sweeping cache, removed %d files", count));
} catch (Exception e) {
Ln.e("Error sweeping the cache", e);
}
}
});
t.start();
}
private int pendingServiceCalls = 0;
private User currentUser;
private long currentCourseListLastLoaded;
private List<Course> currentCourseList;
final private ConcurrentHashMap<Long, Course> courseIdMap = new ConcurrentHashMap<Long, Course>(8);
private int nextProgressDialogTitleId = -1;
private int nextProgressDialogMsgId = -1;
public int getPendingServiceCalls() {
return pendingServiceCalls;
}
public synchronized void incrementPendingServiceCalls() {
if (pendingServiceCalls == 0) {
this.pendingServiceCalls++;
updateHeaderProgress(true);
} else {
this.pendingServiceCalls++;
}
}
public synchronized void decrementPendingServiceCalls() {
if (pendingServiceCalls == 1) {
this.pendingServiceCalls--;
updateHeaderProgress(false);
} else {
this.pendingServiceCalls--;
}
}
public User getCurrentUser() {
return currentUser;
}
public void setCurrentUser(User currentUser) {
this.currentUser = currentUser;
}
public void setCurrentCourseList(List<Course> currentCourseList) {
this.currentCourseList = currentCourseList;
Collections.sort(this.currentCourseList, new Comparator<Course>() {
public int compare(Course course1, Course course2) {
assert(course1 != null);
assert(course2 != null);
return (course1.getTitle().compareToIgnoreCase(course2.getTitle()));
}
});
for (Course course : currentCourseList) {
courseIdMap.put(course.getId(), course);
}
currentCourseListLastLoaded = System.currentTimeMillis();
}
public List<Course> getCurrentCourseList() {
return currentCourseList;
}
public void setCurrentCourseListLastLoaded(long currentCourseListLastLoaded) {
this.currentCourseListLastLoaded = currentCourseListLastLoaded;
}
public long getCurrentCourseListLastLoaded() {
return currentCourseListLastLoaded;
}
public Course getCourseById(long id) {
return courseIdMap.get(id);
}
public int getNextProgressDialogTitleId() {
return nextProgressDialogTitleId;
}
public void setNextProgressDialogTitleId(int nextProgressDialogTitleId) {
this.nextProgressDialogTitleId = nextProgressDialogTitleId;
}
public int getNextProgressDialogMsgId() {
return nextProgressDialogMsgId;
}
public void setNextProgressDialogMsgId(int nextProgressDialogMsgId) {
this.nextProgressDialogMsgId = nextProgressDialogMsgId;
}
private HashMap<String, WeakReference<Context>> contextObjects = new HashMap<String, WeakReference<Context>>();
public synchronized Context getActiveContext(String className) {
WeakReference<Context> ref = contextObjects.get(className);
if (ref == null) {
return null;
}
final Context c = ref.get();
if (c == null) // If the WeakReference is no longer valid, ensure it is removed.
contextObjects.remove(className);
return c;
}
public synchronized Context getActiveContext() {
return lastActiveContext;
}
public synchronized void setActiveContext(String className, Context context) {
if (!(context instanceof ECollegeApplication)) {
lastActiveContext = context;
}
WeakReference<Context> ref = new WeakReference<Context>(context);
this.contextObjects.put(className, ref);
}
public synchronized void resetActiveContext(String className) {
contextObjects.remove(className);
}
private List<WeakReference<HeaderView>> registeredHeaderViews = new ArrayList<WeakReference<HeaderView>>();
public synchronized void updateHeaderProgress(boolean showProgress) {
for (int i=registeredHeaderViews.size()-1;i>=0;i--) {
HeaderView hv = registeredHeaderViews.get(i).get();
if (hv == null) {
registeredHeaderViews.remove(i);
} else {
hv.setProgressVisibility(showProgress);
}
}
}
public synchronized void registerHeaderView(HeaderView hv) {
WeakReference<HeaderView> ref = new WeakReference<HeaderView>(hv);
registeredHeaderViews.add(ref);
hv.setProgressVisibility(pendingServiceCalls > 0);
}
public synchronized void unregisterHeaderView(HeaderView hv) {
for (int i=registeredHeaderViews.size()-1;i>=0;i--) {
if (registeredHeaderViews.get(i).get() == hv) {
registeredHeaderViews.remove(i);
}
}
}
public void reportError(Throwable source) {
ECollegeException ex;
if (source instanceof ECollegeException){
ex = (ECollegeException)source;
} else {
ex = new ECollegePromptException(lastActiveContext, source);
}
if (ex.getSource() != null) {
Ln.e(ex.getSource());
}
if (ex instanceof ECollegeAlertException) {
Toast.makeText(this,ex.getErrorMessageId(),5000).show();
} else if (ex instanceof ECollegePromptException) {
((ECollegePromptException)ex).showErrorDialog();
} else if (ex instanceof ECollegePromptRetryException) {
((ECollegePromptRetryException)ex).showErrorDialog();
}
}
public void uncaughtException(Thread thread, Throwable ex) {
reportError(ex);
}
}