package com.thebluealliance.androidclient.datafeed;
import com.google.gson.JsonObject;
import com.appspot.tbatv_prod_hrd.Favorites;
import com.appspot.tbatv_prod_hrd.Model;
import com.appspot.tbatv_prod_hrd.Subscriptions;
import com.appspot.tbatv_prod_hrd.Tbamobile;
import com.appspot.tbatv_prod_hrd.model.ModelsMobileApiMessagesBaseResponse;
import com.appspot.tbatv_prod_hrd.model.ModelsMobileApiMessagesFavoriteCollection;
import com.appspot.tbatv_prod_hrd.model.ModelsMobileApiMessagesFavoriteMessage;
import com.appspot.tbatv_prod_hrd.model.ModelsMobileApiMessagesModelPreferenceMessage;
import com.appspot.tbatv_prod_hrd.model.ModelsMobileApiMessagesRegistrationRequest;
import com.appspot.tbatv_prod_hrd.model.ModelsMobileApiMessagesSubscriptionCollection;
import com.appspot.tbatv_prod_hrd.model.ModelsMobileApiMessagesSubscriptionMessage;
import com.thebluealliance.androidclient.Constants;
import com.thebluealliance.androidclient.R;
import com.thebluealliance.androidclient.TbaLogger;
import com.thebluealliance.androidclient.Utilities;
import com.thebluealliance.androidclient.accounts.AccountController;
import com.thebluealliance.androidclient.database.Database;
import com.thebluealliance.androidclient.database.tables.FavoritesTable;
import com.thebluealliance.androidclient.database.tables.SubscriptionsTable;
import com.thebluealliance.androidclient.datafeed.gce.GceAuthController;
import com.thebluealliance.androidclient.gcm.GcmController;
import com.thebluealliance.androidclient.helpers.ConnectionDetector;
import com.thebluealliance.androidclient.helpers.JSONHelper;
import com.thebluealliance.androidclient.helpers.ModelNotificationFavoriteSettings;
import com.thebluealliance.androidclient.helpers.MyTBAHelper;
import com.thebluealliance.androidclient.models.Favorite;
import com.thebluealliance.androidclient.models.Subscription;
import com.thebluealliance.androidclient.mytba.ModelPrefsResult;
import com.thebluealliance.androidclient.types.ModelType;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.database.sqlite.SQLiteDatabaseLockedException;
import android.os.Handler;
import android.widget.Toast;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import retrofit2.Response;
import rx.Observable;
@Singleton
public class MyTbaDatafeed {
private static final String LAST_FAVORITES_UPDATE = "last_mytba_favorites_update_%s";
private static final String LAST_SUBSCRIPTIONS_UPDATE = "last_mytba_subscriptions_update_%s";
private final Context mApplicationContext;
private final Resources mRes;
private final SharedPreferences mPrefs;
private final Database mDb;
private final Tbamobile mTbaMobile;
private final Favorites mFavoriteApi;
private final Subscriptions mSubscriptionApi;
private final Model mModelApi;
private final GceAuthController mAuthController;
private final AccountController mAccountController;
private final GcmController mGcmController;
@Inject
public MyTbaDatafeed(
Context context,
GceAuthController authController,
GcmController gcmController,
Tbamobile tbaMobile,
Favorites favoriteApi,
Subscriptions subscriptionApi,
Model modelApi,
Resources res,
SharedPreferences prefs,
AccountController accountController,
Database db) {
mApplicationContext = context.getApplicationContext();
mAuthController = authController;
mGcmController = gcmController;
mTbaMobile = tbaMobile;
mFavoriteApi = favoriteApi;
mSubscriptionApi = subscriptionApi;
mModelApi = modelApi;
mRes = res;
mPrefs = prefs;
mDb = db;
mAccountController = accountController;
}
public boolean register(String regId) {
TbaLogger.d("Registering for GCM");
if (!ConnectionDetector.isConnectedToInternet(mApplicationContext)) {
return false;
}
String authHeader = mAuthController.getAuthHeader();
ModelsMobileApiMessagesRegistrationRequest request = new ModelsMobileApiMessagesRegistrationRequest();
request.mobile_id = regId;
request.operating_system = GcmController.OS_ANDROID;
request.device_uuid = Utilities.getDeviceUUID(mApplicationContext);
Response<ModelsMobileApiMessagesBaseResponse> response = null;
try {
response = mTbaMobile.register(authHeader, request).execute();
} catch (IOException e) {
e.printStackTrace();
}
return (response != null && (response.code() == 200 || response.code() == 304));
}
public boolean unregister() {
TbaLogger.d("Unregistering for GCM");
if (!ConnectionDetector.isConnectedToInternet(mApplicationContext)) {
return false;
}
String authHeader = mAuthController.getAuthHeader();
ModelsMobileApiMessagesRegistrationRequest request = new ModelsMobileApiMessagesRegistrationRequest();
request.mobile_id = mGcmController.getRegistrationId();
request.operating_system = GcmController.OS_ANDROID;
request.device_uuid = Utilities.getDeviceUUID(mApplicationContext);
Response<ModelsMobileApiMessagesBaseResponse> response = null;
try {
response = mTbaMobile.unregister(authHeader, request).execute();
} catch (IOException e) {
e.printStackTrace();
}
return (response != null && (response.code() == 200 || response.code() == 304));
}
public void updateUserFavorites() {
List<Favorite> favoriteModels = new ArrayList<>();
String currentUser = mAccountController.getSelectedAccount();
String prefString = String.format(LAST_FAVORITES_UPDATE, currentUser);
Date now = new Date();
Date futureTime = new Date(mPrefs.getLong(prefString, 0) + Constants.MY_TBA_UPDATE_TIMEOUT);
if (now.before(futureTime)) {
TbaLogger.d("Not updating myTBA subscriptions. Too soon since last update");
return;
}
if (!ConnectionDetector.isConnectedToInternet(mApplicationContext)) {
return;
}
TbaLogger.d("Updating myTBA favorites");
if (!mAccountController.isMyTbaEnabled()) {
TbaLogger.e("MyTBA is not enabled");
Handler mainHandler = new Handler(mApplicationContext.getMainLooper());
mainHandler.post(() -> Toast.makeText(mApplicationContext, mRes.getString(R.string.mytba_error_no_account), Toast.LENGTH_SHORT).show());
return;
}
String authHeader = mAuthController.getAuthHeader();
Response<ModelsMobileApiMessagesFavoriteCollection> favoriteResponse;
try {
favoriteResponse = mFavoriteApi.list(authHeader).execute();
} catch (IOException e) {
TbaLogger.w("Unable to update myTBA favorites");
e.printStackTrace();
return;
}
if (favoriteResponse != null) {
try {
ModelsMobileApiMessagesFavoriteCollection favoriteCollection = favoriteResponse
.body();
if (favoriteCollection != null && favoriteCollection.favorites != null) {
FavoritesTable favorites = mDb.getFavoritesTable();
favorites.recreate(currentUser);
for (int i = 0; i < favoriteCollection.favorites.size(); i++) {
ModelsMobileApiMessagesFavoriteMessage f = favoriteCollection.favorites
.get(i);
favoriteModels.add(new Favorite(currentUser, f.model_key, f.model_type));
}
favorites.add(favoriteModels);
TbaLogger.d("Added " + favoriteModels.size() + " favorites");
}
mPrefs.edit().putLong(prefString, now.getTime()).apply();
} catch (Exception ex) {
if (ex instanceof SQLiteDatabaseLockedException) {
TbaLogger.i("Database locked: " + ex.getMessage());
} else {
TbaLogger.e("Unable to update mytba favorites", ex);
}
}
}
}
public void updateUserSubscriptions() {
String currentUser = mAccountController.getSelectedAccount();
String prefString = String.format(LAST_SUBSCRIPTIONS_UPDATE, currentUser);
Date now = new Date();
Date futureTime = new Date(mPrefs.getLong(prefString, 0) + Constants.MY_TBA_UPDATE_TIMEOUT);
if (now.before(futureTime)) {
TbaLogger.d("Not updating myTBA subscriptions. Too soon since last update");
return;
}
if (!ConnectionDetector.isConnectedToInternet(mApplicationContext)) {
return;
}
TbaLogger.d("Updating myTBA subscriptions");
if (!mAccountController.isMyTbaEnabled()) {
TbaLogger.e("MyTBA is not enabled");
Handler mainHandler = new Handler(mApplicationContext.getMainLooper());
mainHandler.post(() -> Toast.makeText(mApplicationContext, mRes.getString(R.string.mytba_error_no_account), Toast.LENGTH_SHORT).show());
return;
}
String authHeader = mAuthController.getAuthHeader();
Response<ModelsMobileApiMessagesSubscriptionCollection> subscriptionResponse;
try {
subscriptionResponse = mSubscriptionApi.list(authHeader).execute();
} catch (IOException e) {
TbaLogger.w("Unable to update myTBA favorites");
e.printStackTrace();
return;
}
List<Subscription> subscriptionModels = new ArrayList<>();
if (subscriptionResponse != null) {
try {
ModelsMobileApiMessagesSubscriptionCollection subscriptionCollection = subscriptionResponse.body();
if (subscriptionCollection != null
&& subscriptionCollection.subscriptions != null) {
SubscriptionsTable subscriptions = mDb.getSubscriptionsTable();
subscriptions.recreate(currentUser);
for (int i = 0; i < subscriptionCollection.subscriptions.size(); i++) {
ModelsMobileApiMessagesSubscriptionMessage s = subscriptionCollection
.subscriptions
.get(i);
subscriptionModels.add(new Subscription(currentUser,
s.model_key,
s.notifications,
s.model_type));
}
subscriptions.add(subscriptionModels);
TbaLogger.d("Added " + subscriptionModels.size() + " subscriptions");
}
mPrefs.edit().putLong(prefString, now.getTime()).apply();
} catch (Exception ex) {
if (ex instanceof SQLiteDatabaseLockedException) {
TbaLogger.i("Database locked: " + ex.getMessage());
} else {
TbaLogger.e("Unable to update mytba subscriptions", ex);
}
}
}
}
public ModelPrefsResult updateModelSettings(Context context,
ModelNotificationFavoriteSettings settings) {
String modelKey = settings.modelKey;
List<String> notifications = settings.enabledNotifications;
boolean isFavorite = settings.isFavorite;
String user = mAccountController.getSelectedAccount();
String key = MyTBAHelper.createKey(user, modelKey);
ModelType modelType = settings.modelType;
ModelsMobileApiMessagesModelPreferenceMessage request =
new ModelsMobileApiMessagesModelPreferenceMessage();
request.model_key = modelKey;
request.device_key = mGcmController.getRegistrationId();
request.notifications = notifications;
request.favorite = isFavorite;
request.model_type = modelType.getEnum();
SubscriptionsTable subscriptionsTable = mDb.getSubscriptionsTable();
FavoritesTable favoritesTable = mDb.getFavoritesTable();
// Determine if we have to do anything
List<String> existingNotificationsList = new ArrayList<>();
Subscription existingSubscription = subscriptionsTable.get(key);
if (existingSubscription != null) {
existingNotificationsList = existingSubscription.getNotificationList();
}
Collections.sort(notifications);
Collections.sort(existingNotificationsList);
TbaLogger.d("New notifications: " + notifications.toString());
TbaLogger.d("Existing notifications: " + existingNotificationsList.toString());
boolean notificationsHaveChanged = !(notifications.equals(existingNotificationsList));
// If the user is requesting a favorite and is already a favorite,
// or if the user is requesting an unfavorite and it is already not a favorite,
// and if the existing notification mSettings equal the new ones, do nothing.
if (((isFavorite && favoritesTable.exists(key))
|| (!isFavorite && !favoritesTable.exists(key))) && !notificationsHaveChanged) {
// nothing has changed, no-op
return ModelPrefsResult.NOOP;
} else {
try {
String authHeader = mAuthController.getAuthHeader();
Response<ModelsMobileApiMessagesBaseResponse> response = mModelApi
.setPreferences(authHeader, request)
.execute();
if (response == null || !response.isSuccessful()) {
return ModelPrefsResult.ERROR;
}
ModelsMobileApiMessagesBaseResponse prefResponse = response.body();
TbaLogger.d("Result: " + prefResponse.code + "/" + prefResponse.message);
if (response.code() == 401) {
TbaLogger.e(prefResponse.message);
return ModelPrefsResult.ERROR;
}
JsonObject responseJson = JSONHelper.getasJsonObject(prefResponse.message);
if (responseJson == null || responseJson.isJsonNull()) {
return ModelPrefsResult.ERROR;
}
JsonObject fav = responseJson.get("favorite").getAsJsonObject(),
sub = responseJson.get("subscription").getAsJsonObject();
int favCode = fav.get("code").getAsInt(),
subCode = sub.get("code").getAsInt();
if (subCode == 200) {
// Request was successful, update the local databases
if (notifications.isEmpty()) {
subscriptionsTable.remove(key);
} else if (subscriptionsTable.exists(key)) {
subscriptionsTable.update(key,
new Subscription(user,
modelKey,
notifications,
modelType.getEnum()));
} else {
subscriptionsTable.add(new Subscription(user,
modelKey,
notifications,
modelType.getEnum()));
}
} else if (subCode == 500) {
Toast.makeText(context,
String.format(context.getString(R.string.mytba_error),
subCode,
sub.get("message").getAsString()),
Toast.LENGTH_SHORT).show();
}
// otherwise, we tried to add a favorite that already exists/remove one that didn't
// so the database doesn't need to be changed
if (favCode == 200) {
if (!isFavorite) {
favoritesTable.remove(key);
} else if (!favoritesTable.exists(key)) {
favoritesTable.add(new Favorite(user, modelKey, modelType.getEnum()));
}
} else if (favCode == 500) {
Toast.makeText(context,
String.format(context.getString(R.string.mytba_error),
favCode,
fav.get("message").getAsString()),
Toast.LENGTH_SHORT).show();
}
return ModelPrefsResult.SUCCESS;
} catch (IOException e) {
TbaLogger.e("IO Exception while updating model preferences!");
e.printStackTrace();
return ModelPrefsResult.ERROR;
}
}
}
public Observable<List<Subscription>> fetchLocalSubscriptions() {
return Observable.create((observer) -> {
try {
String account = mAccountController.getSelectedAccount();
List<Subscription> subscriptions = mDb.getSubscriptionsTable().getForUser(account);
observer.onNext(subscriptions);
observer.onCompleted();
} catch (Exception e) {
observer.onError(e);
}
});
}
public Observable<List<Favorite>> fetchLocalFavorites() {
return Observable.create((observer) -> {
try {
String account = mAccountController.getSelectedAccount();
List<Favorite> favorites = mDb.getFavoritesTable().getForUser(account);
observer.onNext(favorites);
observer.onCompleted();
} catch (Exception e) {
observer.onError(e);
}
});
}
}