package amidst.version;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import com.google.gson.JsonSyntaxException;
import amidst.Util;
import amidst.logging.Log;
import amidst.resources.ResourceLoader;
public class LatestVersionList {
public static LatestVersionList instance = new LatestVersionList();
public static LatestVersionList get() {
return instance;
}
public enum LoadState {
LOADED,
LOADING,
FAILED,
IDLE
}
private LoadState loadState = LoadState.IDLE;
private VersionList profile;
private ArrayList<ILatestVersionListListener> loadListeners = new ArrayList<ILatestVersionListListener>();
private Object listenerLock = new Object();
public LatestVersionList() {
}
public HashMap<String, String>[] getVersions() {
return profile.versions;
}
public void load(boolean threaded) {
if (threaded) {
(new Thread(new Runnable() {
@Override
public void run() {
doLoad();
}
})).start();
} else {
doLoad();
}
}
private void doLoad() {
Log.i("Beginning latest version list load.");
setLoadState(LoadState.LOADING);
if (!attemptRemoteLoad() && !attemptLocalLoad()) {
Log.w("Failed to load both remote and local version list.");
setLoadState(LoadState.FAILED);
}
setLoadState(LoadState.LOADED);
}
private boolean attemptLocalLoad() {
Log.i("Attempting to download local version list...");
URL versionUrl = ResourceLoader.getResourceURL("versions.json");
return attemptLoad(versionUrl);
}
private boolean attemptRemoteLoad() {
Log.i("Attempting to download remote version list...");
URL versionUrl = null;
try {
versionUrl = new URL(Util.REMOTE_VERSION_LIST_URL);
} catch (MalformedURLException e) {
Log.w("MalformedURLException on remote version list. Aborting load. This should never be possible.");
Log.printTraceStack(e);
Log.w("Aborting remote version list load.");
return false;
}
return attemptLoad(versionUrl);
}
private boolean attemptLoad(URL versionUrl) {
URLConnection urlConnection = null;
try {
urlConnection = versionUrl.openConnection();
} catch (IOException e) {
Log.w("IOException when attempting to open connection to version list.");
Log.printTraceStack(e);
Log.w("Aborting version list load. URL: " + versionUrl);
return false;
}
int contentLength = urlConnection.getContentLength();
if (contentLength == -1) {
Log.w("Content length of version list returned -1.");
Log.w("Aborting version list load. URL: " + versionUrl);
return false;
}
InputStream inputStream = null;
try {
inputStream = urlConnection.getInputStream();
} catch (IOException e) {
Log.w("IOException on opening input stream to version list.");
Log.printTraceStack(e);
Log.w("Aborting version list load. URL: " + versionUrl);
return false;
}
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
try {
profile = Util.readObject(bufferedReader, VersionList.class);
} catch (JsonSyntaxException e) {
Log.w("Unable to parse version list.");
Log.printTraceStack(e);
Log.w("Aborting version list load. URL: " + versionUrl);
return false;
} finally {
try {
bufferedReader.close();
} catch (IOException e) {
Log.w("IOException thrown when attempting to close stream for version list.");
Log.printTraceStack(e);
}
}
Log.i("Successfully loaded version list. URL: " + versionUrl);
return true;
}
public LoadState getLoadState() {
return loadState;
}
private void setLoadState(LoadState state) {
synchronized (listenerLock) {
loadState = state;
for (ILatestVersionListListener listener : loadListeners)
listener.onLoadStateChange(new LatestVersionListEvent(this));
}
}
public void addLoadListener(ILatestVersionListListener listener) {
synchronized (listenerLock) {
loadListeners.add(listener);
}
}
public void removeLoadListener(ILatestVersionListListener listener) {
synchronized (listenerLock) {
loadListeners.remove(listener);
}
}
public void addAndNotifyLoadListener(ILatestVersionListListener listener) {
synchronized (listenerLock) {
loadListeners.add(listener);
listener.onLoadStateChange(new LatestVersionListEvent(this));
}
}
private class VersionList {
public HashMap<String, String> latest;
public HashMap<String, String>[] versions;
}
}