package com.gobbler;
import helpers.rest.RestHelper;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.util.Log;
import com.gobbler.synchronization.AccountQuota;
import com.gobbler.synchronization.File;
import com.gobbler.synchronization.Machine;
import com.gobbler.synchronization.MergeError;
import com.gobbler.synchronization.Project;
import com.gobbler.synchronization.Transfer;
import com.gobbler.synchronization.User;
import com.gobbler.synchronization.UserData;
import com.gobbler.synchronization.Volume;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
public class GobblerClient {
private static GobblerClient gobblerClient = null;
private String client_key;
private Collection<AccountQuota> accountQuotas;
private Collection<Machine> machines;
private Collection<Project> projects;
private Collection<Transfer> transfers;
private Collection<User> users;
private Collection<UserData> userDatas;
private Collection<Volume> volumes;
private Collection<Folder> folders;
public GobblerClient(String client_key) {
this.client_key = client_key;
}
public static GobblerClient initializeGobblerClient(String client_key) {
if (client_key == null) {
throw new RuntimeException("getGobblerClient must have a non-null clientKey");
}
if (gobblerClient == null) {
gobblerClient = new GobblerClient(client_key);
}
return gobblerClient;
}
public static GobblerClient getGobblerClient() {
if (gobblerClient == null)
throw new RuntimeException(
"getGobblerClient cannot return if GobblerClient has not been initialized");
return gobblerClient;
}
public String getJsonData(String method_type) {
String jsonString = "{ \"objects\" : [] }";
String url = String.format("http://api.gobbler.com/client_%s/sync_ask",
method_type);
String response = GobblerRestClient.post(url, jsonString, this.client_key);
JSONObject jsonObject = GobblerRestClient.convertToJSON(response);
String updates = null;
try {
updates = jsonObject.getJSONArray("updates").toString();
} catch (JSONException e) {
throw new ServerLoginError("Response from Gobbler server is unparseble");
}
Log.d("getJsonData", updates);
return updates;
}
/*
* Below we have some number of methods that all do more or less the same
* thing. An attempt was made to abstract these using generics, but due to
* Java type erasure, it is impossible to such an abstract method. See:
* http://
* stackoverflow.com/questions/10356140/how-can-i-use-google-gson-to-deserialize
* -a-json-array-into-a-a-collection-of-a-g/10359955#10359955
*/
/*
* Fetch the users's account quotas.
*/
public Collection<AccountQuota> getAccountQuotas() {
if (this.accountQuotas != null)
return this.accountQuotas;
String json = getJsonData("account_quota"); // TODO: Need to ensure that is
// a list, ie [1, 2, 3, 4]
Gson gson = new Gson();
// straight from gson docs. not sure what this does, but its apparently
// unavoidable
Type collectionType = new TypeToken<Collection<AccountQuota>>() {
}.getType();
return gson.fromJson(json, collectionType);
}
/*
* Fetch the users's machines.
*/
public Collection<Machine> getMachines() {
if (this.machines != null)
return this.machines;
String json = getJsonData("machine");
Gson gson = new Gson();
// straight from gson docs. not sure what this does, but its apparently
// unavoidable
Type collectionType = new TypeToken<Collection<Machine>>() {
}.getType();
return gson.fromJson(json, collectionType);
}
/*
* Fetch the user's projects.
*/
public Collection<Project> getProjects() {
if (this.projects != null)
return this.projects;
String json = getJsonData("project");
Gson gson = new Gson();
// straight from gson docs. not sure what this does, but its apparently
// unavoidable
Type collectionType = new TypeToken<Collection<Project>>() {
}.getType();
return gson.fromJson(json, collectionType);
}
/*
* Fetch the users's transfers.
*/
public Collection<Transfer> getTransfers() {
if (this.transfers != null)
return this.transfers;
String json = getJsonData("transfer");
Gson gson = new Gson();
// straight from gson docs. not sure what this does, but its apparently
// unavoidable
Type collectionType = new TypeToken<Collection<Transfer>>() {
}.getType();
return gson.fromJson(json, collectionType);
}
/*
*
*/
public Collection<User> getUsers() {
if (this.users != null)
return this.users;
String json = getJsonData("user");
Gson gson = new Gson();
// straight from gson docs. not sure what this does, but its apparently
// unavoidable
Type collectionType = new TypeToken<Collection<User>>() {
}.getType();
return gson.fromJson(json, collectionType);
}
/*
* Fetch the users's user datas.
*/
public Collection<UserData> getUserDatas() {
if (this.userDatas != null)
return this.userDatas;
String json = getJsonData("user_data");
Gson gson = new Gson();
// straight from gson docs. not sure what this does, but its apparently
// unavoidable
Type collectionType = new TypeToken<Collection<UserData>>() {
}.getType();
return gson.fromJson(json, collectionType);
}
/*
* Fetch the users's volumes.
*/
public Collection<Volume> getVolumes() {
if (this.volumes != null)
return this.volumes;
String json = getJsonData("volume");
Gson gson = new Gson();
// straight from gson docs. not sure what this does, but its apparently
// unavoidable
Type collectionType = new TypeToken<Collection<Volume>>() {
}.getType();
return gson.fromJson(json, collectionType);
}
/*
* Get the root of a file system.
*/
private File getRoot(Collection<File> files) {
File root = null;
for (File file : files) {
if (file.isRoot()) {
root = file;
}
}
assert root != null;
return root;
}
/*
* Given a list of files, arrange them into a tree.
*/
public File buildFileSystem(Collection<File> files) throws MergeError {
File root = getRoot(files);
files.remove(root);
// Sort each of the files by number of ancestors to ensure that during each merge, the parent of the file already exists.
// If a parent doesn't exist, then a MergeError is thrown.
ArrayList<File> fileArray = new ArrayList<File>(files);
Collections.sort(fileArray);
for (File file : files) {
root.merge(file.getAncestorNames(), file);
}
return root;
}
class Folder {
private String volumeGuid;
private String path;
private String name;
public Folder(String volumeGuid, String path) {
this.volumeGuid = volumeGuid;
this.path = path;
this.name = parseNameFromPath(path);
}
public String getVolume() {
return this.volumeGuid;
}
public String getPath() {
return this.path;
}
public String getName() {
return this.name;
}
public String parseNameFromPath(String path) {
Pattern p1 = Pattern.compile("([^\\/]+?)$");
Matcher m1 = p1.matcher(path);
String intermediaryString = m1.group(0);
Pattern p2 = Pattern.compile("^[^.]+");
Matcher m2 = p2.matcher(intermediaryString);
return m2.group(0);
}
}
public Collection<Folder> getFolders() {
if (this.folders != null)
return this.folders;
String jsonString = "{ \"objects\" : [] }";
String url = "http://api.gobbler.com/client_catalog/sync_ask_folder";
String response = GobblerRestClient.post(url, jsonString, client_key);
JSONObject jsonObject = GobblerRestClient.convertToJSON(response);
JSONArray projects = null;
try {
projects = jsonObject.getJSONArray("updates");
} catch (JSONException e) {
throw new ServerLoginError("Response from Gobbler server is unparseble");
}
folders = new ArrayList<Folder>();
for (int i = 0; i < projects.length(); i++) {
JSONObject project = null;
try {
project = projects.getJSONObject(i);
} catch (JSONException e) {
e.printStackTrace();
}
String volumeGuid = null, path = null;
try {
volumeGuid = project.getString("volume_guid");
path = project.getString("path");
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Folder volumePath = new Folder(volumeGuid, path);
folders.add(volumePath);
}
return this.folders;
}
}