package com.piusvelte.sonet.social;
import android.app.Activity;
import android.content.Context;
import android.content.IntentSender;
import android.database.Cursor;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.plus.Moments;
import com.google.android.gms.plus.People;
import com.google.android.gms.plus.Plus;
import com.google.android.gms.plus.model.moments.ItemScope;
import com.google.android.gms.plus.model.moments.Moment;
import com.google.android.gms.plus.model.moments.MomentBuffer;
import com.google.android.gms.plus.model.people.Person;
import com.google.android.gms.plus.model.people.PersonBuffer;
import com.piusvelte.sonet.BuildConfig;
import com.piusvelte.sonet.R;
import com.piusvelte.sonet.SonetCrypto;
import com.piusvelte.sonet.SonetHttpClient;
import com.piusvelte.sonet.provider.Notifications;
import com.squareup.okhttp.Request;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
import static com.piusvelte.sonet.Sonet.Sactor;
import static com.piusvelte.sonet.Sonet.Scontent;
import static com.piusvelte.sonet.Sonet.SdisplayName;
import static com.piusvelte.sonet.Sonet.Sid;
import static com.piusvelte.sonet.Sonet.Simage;
import static com.piusvelte.sonet.Sonet.Sitems;
import static com.piusvelte.sonet.Sonet.Sobject;
import static com.piusvelte.sonet.Sonet.SoriginalContent;
import static com.piusvelte.sonet.Sonet.Spublished;
import static com.piusvelte.sonet.Sonet.Sreplies;
import static com.piusvelte.sonet.Sonet.StotalItems;
import static com.piusvelte.sonet.Sonet.Surl;
/**
* Created by bemmanuel on 2/15/15.
*/
public class GooglePlus extends Client {
private static final String GOOGLEPLUS_BASE_URL = "https://www.googleapis.com/plus/v1/";
private static final String GOOGLEPLUS_ACTIVITIES = "%speople/%s/activities/%s?maxResults=%s&access_token=%s";
private static final String GOOGLEPLUS_ACTIVITY = "%sactivities/%s?access_token=%s";
private static final String GOOGLEPLUS_PROFILE = "https://plus.google.com/%s";
private static final String GOOGLEPLUS_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ";
private static GoogleApiClient sGoogleApiClient;
/** ConnectionResult used for resolving connection failure */
private ConnectionResult mConnectionResult;
public GooglePlus(Context context, String token, String secret, String accountEsid, int network) {
super(context, token, secret, accountEsid, network);
}
private boolean connectClient() {
if (BuildConfig.DEBUG) {
Log.d(mTag, "GoogleApiClient connect, is connected?" + (sGoogleApiClient != null && sGoogleApiClient.isConnected()));
}
if (sGoogleApiClient == null) {
sGoogleApiClient = new GoogleApiClient.Builder(mContext)
.addApi(Plus.API)
.addScope(Plus.SCOPE_PLUS_LOGIN)
.addScope(Plus.SCOPE_PLUS_PROFILE)
.setAccountName(mAccountEsid)
.build();
mConnectionResult = sGoogleApiClient.blockingConnect();
if (mConnectionResult.isSuccess()) {
if (BuildConfig.DEBUG) {
Log.d(mTag, "GoogleApiClient connected");
}
mConnectionResult = null;
return true;
} else {
if (BuildConfig.DEBUG) {
Log.d(mTag, "GoogleApiClient connect failed; code=" + mConnectionResult.getErrorCode() + ", " + mConnectionResult.toString());
}
}
sGoogleApiClient = null;
return false;
} else if (!sGoogleApiClient.isConnected()) {
sGoogleApiClient = null;
return connectClient();
}
return true;
}
@Override
public boolean hasConnectionError() {
return mConnectionResult != null;
}
@Override
public boolean resolveConnectionError(@NonNull Activity activity, int requestCode) {
if (hasConnectionError()) {
try {
mConnectionResult.startResolutionForResult(activity, requestCode);
mConnectionResult = null;
return true;
} catch (IntentSender.SendIntentException e) {
if (BuildConfig.DEBUG) {
Log.e(mTag, "error resolving connection error", e);
}
mConnectionResult = null;
return false;
}
}
return false;
}
@Nullable
@Override
public String getProfileUrl(@NonNull String esid) {
return String.format(GOOGLEPLUS_PROFILE, esid);
}
@Nullable
@Override
public String getProfilePhotoUrl() {
synchronized (GooglePlus.class) {
if (connectClient()) {
Person person = Plus.PeopleApi.getCurrentPerson(sGoogleApiClient);
if (person.hasImage()) {
Person.Image image = person.getImage();
if (image.hasUrl()) {
return image.getUrl();
}
}
}
}
return null;
}
@Nullable
@Override
public String getProfilePhotoUrl(String esid) {
String url = null;
synchronized (GooglePlus.class) {
if (connectClient()) {
People.LoadPeopleResult result = Plus.PeopleApi.load(sGoogleApiClient, esid).await();
if (result != null && result.getStatus().isSuccess()) {
PersonBuffer buffer = result.getPersonBuffer();
if (buffer.getCount() > 0) {
Person person = buffer.get(0);
if (person.hasImage()) {
Person.Image image = person.getImage();
if (image.hasUrl()) {
url = image.getUrl();
}
}
}
buffer.close();
}
}
}
return url;
}
@Nullable
@Override
public Uri getCallback() {
return null;
}
@Override
String getRequestUrl() {
return null;
}
@Override
String getAccessUrl() {
return null;
}
@Override
String getAuthorizeUrl() {
return null;
}
@Override
public String getCallbackUrl() {
return null;
}
@Nullable
private String getAccessToken(@NonNull String refreshToken) {
return null;
}
@Override
public MemberAuthentication getMemberAuthentication(@NonNull String authenticatedUrl) {
synchronized (GooglePlus.class) {
if (connectClient()) {
Person person = Plus.PeopleApi.getCurrentPerson(sGoogleApiClient);
if (BuildConfig.DEBUG) {
Log.d(mTag, "getMemberAuthentication; person=" + person);
}
if (person != null) {
MemberAuthentication memberAuthentication = new MemberAuthentication();
memberAuthentication.username = person.getDisplayName();
// person.getId() is the "id", but the @gmail account is what's required to authenticate
memberAuthentication.id = mAccountEsid;
memberAuthentication.network = mNetwork;
return memberAuthentication;
}
}
}
return null;
}
@Nullable
@Override
public String getAuthUrl() {
return null;
}
@Nullable
@Override
public Set<String> getNotificationStatusIds(long account, String[] notificationMessage) {
Set<String> notificationSids = new HashSet<>();
Cursor currentNotifications = getContentResolver().query(Notifications.getContentUri(mContext),
new String[] { Notifications._ID, Notifications.SID, Notifications.UPDATED, Notifications.CLEARED, Notifications.ESID },
Notifications.ACCOUNT + "=?", new String[] { Long.toString(account) }, null);
// loop over notifications
if (currentNotifications.moveToFirst()) {
while (!currentNotifications.isAfterLast()) {
long notificationId = currentNotifications.getLong(0);
String sid = SonetCrypto.getInstance(mContext).Decrypt(currentNotifications.getString(1));
long updated = currentNotifications.getLong(2);
boolean cleared = currentNotifications.getInt(3) == 1;
// store sids, to avoid duplicates when requesting the latest feed
if (!notificationSids.contains(sid)) {
notificationSids.add(sid);
}
// TODO
// get comments for current notifications
// String response = SonetHttpClient.httpResponse(String.format(GOOGLEPLUS_ACTIVITY, GOOGLEPLUS_BASE_URL, sid,
// access_token)));
//
// if (!TextUtils.isEmpty(response)) {
// // check for a newer post, if it's the user's own, then set CLEARED=0
// try {
// JSONObject item = new JSONObject(response);
//
// if (item.has(Sobject)) {
// JSONObject object = item.getJSONObject(Sobject);
//
// if (object.has(Sreplies)) {
// int commentCount = 0;
// JSONObject replies = object.getJSONObject(Sreplies);
//
// if (replies.has(StotalItems)) {
// commentCount = replies.getInt(StotalItems);
// }
// }
// }
// } catch (JSONException e) {
// // TODO
// }
// }
currentNotifications.moveToNext();
}
}
currentNotifications.close();
return notificationSids;
}
@Override
public String getFeed(int appWidgetId,
String widget,
long account,
int status_count,
boolean time24hr,
boolean display_profile,
int notifications) {
String[] notificationMessage = new String[1];
Set<String> notificationSids = null;
boolean doNotify = notifications != 0;
if (doNotify) {
notificationSids = getNotificationStatusIds(account, notificationMessage);
}
synchronized (GooglePlus.class) {
if (connectClient()) {
Moments.LoadMomentsResult result = Plus.MomentsApi.load(sGoogleApiClient).await();
if (BuildConfig.DEBUG) {
Log.d(mTag, "feed result=" + result);
}
if (result != null && result.getStatus().isSuccess()) {
MomentBuffer buffer = result.getMomentBuffer();
int parseCount = Math.min(buffer.getCount(), status_count);
if (BuildConfig.DEBUG) {
Log.d(mTag, "feed count=" + parseCount);
}
if (parseCount > 0) {
removeOldStatuses(widget, Long.toString(account));
for (int i = 0; i < parseCount; i++) {
Moment moment = buffer.get(i);
if (BuildConfig.DEBUG) {
Log.d(mTag, "moment=" + moment.toString());
}
String statusId = moment.getId();
long date = parseDate(moment.getStartDate(), GOOGLEPLUS_DATE_FORMAT);
ItemScope creator = moment.getResult();
String entityId = creator.getId();
String name = creator.getGivenName() + " " + creator.getFamilyName();
String image = creator.getImage();
String content = creator.getDescription();
addStatusItem(date,
name,
image,
String.format(getString(R.string.messageWithCommentCount), content, 0),
time24hr,
appWidgetId,
account,
statusId,
entityId,
new ArrayList<String[]>());
}
}
buffer.close();
}
}
}
if (doNotify) {
getNotificationMessage(account, notificationMessage);
return notificationMessage[0];
}
return null;
}
@Nullable
@Override
public String getFeedResponse(int status_count) {
return null;
}
@Nullable
@Override
public JSONArray parseFeed(@NonNull String response) throws JSONException {
return null;
}
@Override
public void addFeedItem(@NonNull JSONObject item,
boolean display_profile,
boolean time24hr,
int appWidgetId,
long account,
Set<String> notificationSids,
String[] notificationMessage,
boolean doNotify) throws JSONException {
// NO-OP
}
@Override
public void getNotificationMessage(long account, String[] notificationMessage) {
// NO-OP
}
@Override
public void getNotifications(long account, String[] notificationMessage) {
// deprecated
Cursor currentNotifications = getContentResolver().query(Notifications.getContentUri(mContext),
new String[] { Notifications._ID, Notifications.SID, Notifications.UPDATED, Notifications.CLEARED, Notifications.ESID },
Notifications.ACCOUNT + "=?", new String[] { Long.toString(account) }, null);
if (currentNotifications.moveToFirst()) {
Set<String> notificationSids = new HashSet<>();
String accessToken = getAccessToken(mToken);
try {
if (!TextUtils.isEmpty(accessToken)) {
String response;
while (!currentNotifications.isAfterLast()) {
long notificationId = currentNotifications.getLong(0);
String sid = SonetCrypto.getInstance(mContext).Decrypt(currentNotifications.getString(1));
long updated = currentNotifications.getLong(2);
boolean cleared = currentNotifications.getInt(3) == 1;
// store sids, to avoid duplicates when requesting the latest feed
if (!notificationSids.contains(sid)) {
notificationSids.add(sid);
}
// get comments for current notifications
Request request = new Request.Builder()
.url(String.format(GOOGLEPLUS_ACTIVITY, GOOGLEPLUS_BASE_URL, sid, accessToken))
.build();
response = SonetHttpClient.getResponse(request);
if (!TextUtils.isEmpty(response)) {
// check for a newer post, if it's the user's own, then set CLEARED=0
try {
JSONObject item = new JSONObject(response);
if (item.has(Sobject)) {
JSONObject object = item.getJSONObject(Sobject);
if (object.has(Sreplies)) {
int commentCount = 0;
JSONObject replies = object.getJSONObject(Sreplies);
if (replies.has(StotalItems)) {
//TODO: notifications
}
}
}
} catch (JSONException e) {
if (BuildConfig.DEBUG) Log.e(mTag, e.toString());
}
}
currentNotifications.moveToNext();
}
Request request = new Request.Builder()
.url(String.format(GOOGLEPLUS_ACTIVITIES, GOOGLEPLUS_BASE_URL, "me", "public", 20, accessToken))
.build();
response = SonetHttpClient.getResponse(request);
// get new feed
if (!TextUtils.isEmpty(response)) {
JSONObject r = new JSONObject(response);
if (r.has(Sitems)) {
JSONArray items = r.getJSONArray(Sitems);
for (int i1 = 0, i2 = items.length(); i1 < i2; i1++) {
JSONObject item = items.getJSONObject(i1);
if (item.has(Sactor) && item.has(Sobject)) {
JSONObject actor = item.getJSONObject(Sactor);
JSONObject object = item.getJSONObject(Sobject);
if (item.has(Sid) && actor.has(Sid) && actor.has(SdisplayName) && item.has(Spublished) && object
.has(Sreplies) && object.has(SoriginalContent)) {
String sid = item.getString(Sid);
String esid = actor.getString(Sid);
String friend = actor.getString(SdisplayName);
String originalContent = object.getString(SoriginalContent);
if ((originalContent == null) || (originalContent.length() == 0)) {
originalContent = object.getString(Scontent);
}
String photo = null;
if (actor.has(Simage)) {
JSONObject image = actor.getJSONObject(Simage);
if (image.has(Surl)) {
photo = image.getString(Surl);
}
}
long date = parseDate(item.getString(Spublished), GOOGLEPLUS_DATE_FORMAT);
int commentCount = 0;
JSONObject replies = object.getJSONObject(Sreplies);
String notification = null;
if (replies.has(StotalItems)) {
// Log.d(TAG, Sreplies + ":" + replies.toString());
commentCount = replies.getInt(StotalItems);
}
if (notification != null) {
// new notification
addNotification(sid, esid, friend, originalContent, date, account, notification);
}
}
}
}
}
}
}
} catch (JSONException e) {
if (BuildConfig.DEBUG) Log.e(mTag, e.toString());
}
}
currentNotifications.close();
}
@Override
public boolean createPost(String message, String placeId, String latitude, String longitude, String photoPath, String[] tags) {
return false;
}
@Override
public boolean isLikeable(String statusId) {
return true;
}
@Override
public boolean isLiked(String statusId, String accountId) {
return false;
}
@Override
public boolean likeStatus(String statusId, String accountId, boolean doLike) {
return false;
}
@Override
public String getLikeText(boolean isLiked) {
return "+1";
}
@Override
public boolean isCommentable(String statusId) {
return true;
}
@Override
public String getCommentPretext(String accountId) {
return null;
}
@Override
public void onDelete() {
synchronized (GooglePlus.class) {
if (connectClient()) {
Plus.AccountApi.revokeAccessAndDisconnect(sGoogleApiClient).await();
}
}
}
@Nullable
@Override
public String getCommentsResponse(String statusId) {
return null;
}
@Nullable
@Override
public JSONArray parseComments(@NonNull String response) throws JSONException {
return null;
}
@Nullable
@Override
public HashMap<String, String> parseComment(@NonNull String statusId, @NonNull JSONObject jsonComment, boolean time24hr) throws JSONException {
return null;
}
@Override
public LinkedHashMap<String, String> getLocations(String latitude, String longitude) {
return null;
}
@Override
public boolean sendComment(@NonNull String statusId, @NonNull String message) {
return false;
}
@Override
public List<HashMap<String, String>> getFriends() {
return null;
}
@Override
String getApiKey() {
return BuildConfig.GOOGLECLIENT_ID;
}
@Override
String getApiSecret() {
return BuildConfig.GOOGLECLIENT_SECRET;
}
}