package org.redcross.openmapkit.deployments;
import android.os.AsyncTask;
import org.apache.commons.io.FileUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.redcross.openmapkit.ExternalStorage;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* This is a simple container for the JSON response from the
* deployments endpoint from OpenMapKit Server.
*/
public class Deployments {
public enum Status { OFFLINE, SERVER_NOT_FOUND, ONLINE };
private static Deployments singleton = new Deployments();
private List<Deployment> deployments = new ArrayList<>();
private DeploymentsActivity activity;
private String omkServerUrl;
/**
* When we add a deployment to deployments, we keep
* track of the name to index in this HashMap. This lets
* us quickly find a deployment by name.
*/
private Map<String, Integer> nameToIdx = new HashMap<>();
public static Deployments singleton() {
return singleton;
}
private void putDeployment(JSONObject deploymentJson) {
Deployment deployment = new Deployment(deploymentJson);
String name = deployment.name();
if (name == null) return; // check if deployment has name. bogus if not.
Integer idx = nameToIdx.get(name);
// new deployment
if (idx == null) {
nameToIdx.put(name, deployments.size());
deployments.add(deployment);
}
/**
* Note: Needs Server Synchronization
*
* https://github.com/AmericanRedCross/OpenMapKitAndroid/issues/137
*/
// replace existing deployment
// else {
// deployments.set(idx, deployment);
// }
}
public void fetch(DeploymentsActivity activity, String url) {
this.activity = activity;
omkServerUrl = url;
DeploymentsListHttpTask task = new DeploymentsListHttpTask();
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url);
}
public Deployment get(int idx) {
return deployments.get(idx);
}
public int getIdxForName(String name) {
Integer idx = nameToIdx.get(name);
if (idx == null) {
return -1;
}
return idx;
}
public int size() {
return deployments.size();
}
public String omkServerUrl() {
return omkServerUrl;
}
private void parseJsonFromApi(String json) {
try {
JSONArray jsonFromAPI = new JSONArray(json);
int len = jsonFromAPI.length();
for (int i = 0; i < len; ++i) {
JSONObject obj = jsonFromAPI.optJSONObject(i);
if (obj != null) {
obj.put("api", true);
putDeployment(obj);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
/**
* Fetches the deployment JSON currently on disk
*/
private Deployments.Status fetchFromExternalStorage() {
Deployments.Status status = Status.SERVER_NOT_FOUND;
List<File> files = ExternalStorage.allDeploymentJSONFiles();
for (File f : files) {
try {
String jsonStr = FileUtils.readFileToString(f, "UTF-8");
JSONObject obj = new JSONObject(jsonStr);
// We can later look and know the deployment JSON came
// from ExternalStorage rather than the API.
obj.put("persisted", true);
putDeployment(obj);
status = Status.OFFLINE;
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
return status;
}
public class DeploymentsListHttpTask extends AsyncTask<String, Void, Deployments.Status> {
@Override
protected void onPreExecute() {
}
@Override
protected Deployments.Status doInBackground(String... params) {
Deployments.Status status = fetchFromExternalStorage();
HttpURLConnection urlConnection;
try {
String urlStr = params[0];
String endpoint;
if (urlStr.charAt(urlStr.length()-1) == '/') {
endpoint = urlStr + "omk/deployments";
} else {
endpoint = urlStr + "/omk/deployments";
}
URL url = new URL(endpoint);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setConnectTimeout(3000);
urlConnection.setReadTimeout(7000);
int statusCode = urlConnection.getResponseCode();
// 200 represents HTTP OK
if (statusCode == 200) {
BufferedReader r = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuilder response = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
response.append(line);
}
parseJsonFromApi(response.toString());
status = Deployments.Status.ONLINE; // Successful
}
} catch (Exception e) {
// Status is either SERVER_NOT_FOUND or OFFLINE.
}
return status;
}
@Override
protected void onPostExecute(Deployments.Status status) {
activity.deploymentsFetched(status);
}
}
}