package com.openfarmanager.android.googledrive.api;
import com.openfarmanager.android.googledrive.R;
import com.openfarmanager.android.googledrive.model.About;
import com.openfarmanager.android.googledrive.model.Token;
import com.openfarmanager.android.googledrive.model.exceptions.ResponseException;
import org.json.JSONException;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import static com.openfarmanager.android.googledrive.GoogleDriveConstants.ABOUT_URL;
import static com.openfarmanager.android.googledrive.GoogleDriveConstants.AUTH_URL;
import static com.openfarmanager.android.googledrive.GoogleDriveConstants.CLIENT_ID;
import static com.openfarmanager.android.googledrive.GoogleDriveConstants.REDIRECT_URL;
import static com.openfarmanager.android.googledrive.GoogleDriveConstants.TOKEN_URL;
import static com.openfarmanager.android.googledrive.api.Fields.ACCESS_TOKEN;
import static com.openfarmanager.android.googledrive.api.Fields.AUTHORIZATION_CODE;
import static com.openfarmanager.android.googledrive.api.Fields.CODE;
import static com.openfarmanager.android.googledrive.api.Fields.GRANT_TYPE;
import static com.openfarmanager.android.googledrive.api.Fields.REFRESH_TOKEN;
/**
* author: Vlad Namashko
*/
public class Api {
protected static final String METHOD_DELETE = "DELETE";
protected static final String METHOD_PUT = "PUT";
protected static final String METHOD_POST = "POST";
private static final String AUTH_CODE_URL = AUTH_URL + "?" +
"client_id=" + CLIENT_ID + "&" +
"response_type=code&" +
"scope=openid%20https://www.googleapis.com/auth/drive&" +
"redirect_uri=" + REDIRECT_URL;
protected Token mToken;
public String getAuthCodeUrl() {
return AUTH_CODE_URL;
}
public void setupToken(Token token) {
mToken = token;
}
public Token refreshToken(final Token token) {
try {
HttpURLConnection connection = prepareTokenRequest(REFRESH_TOKEN, new HashMap<String, String>() {{
put(REFRESH_TOKEN, token.getRefreshToken());
}});
int responseCode = connection.getResponseCode();
if (responseCode == 201 || responseCode == 200) {
return new Token(streamToString(connection.getInputStream()), token.getRefreshToken());
}
} catch (JSONException e) {
throw new ResponseException(R.string.response_error);
}
// TODO: Exceptions
catch (Exception e) {
e.printStackTrace();
}
return null;
}
public Token getAuthToken(String url) {
final String code = extractAuthCode(url);
try {
HttpURLConnection connection = prepareTokenRequest(AUTHORIZATION_CODE, new HashMap<String, String>() {{
put(CODE, code);
put(Fields.REDIRECT_URI, REDIRECT_URL);
}});
int responseCode = connection.getResponseCode();
if (responseCode == 201 || responseCode == 200) {
return new Token(streamToString(connection.getInputStream()));
}
} catch (JSONException e) {
throw new ResponseException(R.string.response_error);
}
// TODO: Exceptions
catch (Exception e) {
e.printStackTrace();
}
return null;
}
public About getAbout(Token token) throws Exception {
HttpURLConnection connection = (HttpURLConnection) new URL(ABOUT_URL + "?" + getAuth(token)).openConnection();
connection.setRequestProperty("Cache-Control", "no-cache");
int responseCode = connection.getResponseCode();
if (isTokenExpired(responseCode, connection.getResponseMessage())) {
setupToken(refreshToken(mToken));
return getAbout(mToken);
}
if (responseCode == 201 || responseCode == 200) {
return new About(streamToString(connection.getInputStream()));
}
return null;
}
private HttpURLConnection prepareTokenRequest(String grantType, HashMap<String, String> params) throws Exception {
HttpURLConnection connection = (HttpURLConnection) new URL(TOKEN_URL).openConnection();
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
connection.setRequestProperty("Cache-Control", "no-cache");
connection.setRequestMethod(METHOD_POST);
params.put(GRANT_TYPE, grantType);
params.put(Fields.CLIENT_ID, CLIENT_ID);
OutputStream os = connection.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
writer.write(getPostDataString(params));
writer.flush();
writer.close();
MultipartUtility.closeStream(writer);
MultipartUtility.closeStream(os);
return connection;
}
private String getPostDataString(HashMap<String, String> params) throws UnsupportedEncodingException {
StringBuilder result = new StringBuilder();
boolean first = true;
for(Map.Entry<String, String> entry : params.entrySet()){
if (first) {
first = false;
} else {
result.append("&");
}
result.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
result.append("=");
result.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
}
return result.toString();
}
protected String getAuth() {
return getAuth(mToken);
}
private String getAuth(final Token token) {
try {
return getPostDataString(new HashMap<String, String>() {{
put(ACCESS_TOKEN, token.getAccessToken());
}});
} catch (Exception e) {
return null;
}
}
public String extractAuthCode(String url) {
int pos = url.indexOf("code=");
return url.substring(pos + 5, pos + url.indexOf("&", pos) - pos);
}
protected boolean isTokenExpired(int statusCode, String message) {
return statusCode == 401 && message.equals("Unauthorized");
}
protected String streamToString(InputStream is) {
BufferedReader br = null;
StringBuilder sb = new StringBuilder();
String line;
try {
br = new BufferedReader(new InputStreamReader(is));
while ((line = br.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return sb.toString();
}
}