/* Copyright (C) 2014 Prasanna Thirumalai This file is part of StackX. StackX is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. StackX is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with StackX. If not, see <http://www.gnu.org/licenses/>. */ package com.prasanna.android.stacknetwork.service; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import android.content.Intent; import android.database.SQLException; import android.os.Bundle; import android.os.ResultReceiver; import com.prasanna.android.http.AbstractHttpException; import com.prasanna.android.stacknetwork.model.Account; import com.prasanna.android.stacknetwork.model.Answer; import com.prasanna.android.stacknetwork.model.InboxItem; import com.prasanna.android.stacknetwork.model.Question; import com.prasanna.android.stacknetwork.model.Site; import com.prasanna.android.stacknetwork.model.StackXPage; import com.prasanna.android.stacknetwork.model.User; import com.prasanna.android.stacknetwork.sqlite.ProfileDAO; import com.prasanna.android.stacknetwork.sqlite.SiteDAO; import com.prasanna.android.stacknetwork.sqlite.UserAccountsDAO; import com.prasanna.android.stacknetwork.utils.AppUtils; import com.prasanna.android.stacknetwork.utils.DbRequestThreadExecutor; import com.prasanna.android.stacknetwork.utils.SharedPreferencesUtil; import com.prasanna.android.stacknetwork.utils.StackXIntentAction.UserIntentAction; import com.prasanna.android.stacknetwork.utils.StringConstants; import com.prasanna.android.utils.LogWrapper; public class UserIntentService extends AbstractIntentService { private static final String TAG = UserIntentService.class.getSimpleName(); public static final int GET_USER_PROFILE = 0x1; public static final int GET_USER_QUESTIONS = 0x2; public static final int GET_USER_ANSWERS = 0x3; public static final int GET_USER_INBOX = 0x4; public static final int GET_USER_UNREAD_INBOX = 0x5; public static final int GET_USER_SITES = 0x6; public static final int GET_USER_FAVORITES = 0x7; public static final int GET_USER_REP_HISTORY_FULL = 0x8; public static final int DEAUTH_APP = 0x201; private UserServiceHelper userService = UserServiceHelper.getInstance(); public UserIntentService() { this(TAG); } public UserIntentService(String name) { super(name); } @Override protected void onHandleIntent(Intent intent) { final ResultReceiver receiver = intent.getParcelableExtra(StringConstants.RESULT_RECEIVER); final int action = intent.getIntExtra(StringConstants.ACTION, -1); final int page = intent.getIntExtra(StringConstants.PAGE, 1); final boolean me = intent.getBooleanExtra(StringConstants.ME, false); final long userId = intent.getLongExtra(StringConstants.USER_ID, -1); final Bundle bundle = new Bundle(); try { super.onHandleIntent(intent); switch (action) { case GET_USER_PROFILE: String site = intent.getStringExtra(StringConstants.SITE); boolean refresh = intent.getBooleanExtra(StringConstants.REFRESH, false); StackXPage<User> userDetail = getUserDetail(me, userId, refresh, site, page); bundle.putSerializable(StringConstants.USER, userDetail); bundle.putSerializable(StringConstants.USER_ACCOUNTS, getUserAccounts(me, userDetail)); receiver.send(GET_USER_PROFILE, bundle); break; case GET_USER_QUESTIONS: bundle.putSerializable(StringConstants.QUESTIONS, getQuestions(me, userId, page)); receiver.send(GET_USER_QUESTIONS, bundle); break; case GET_USER_ANSWERS: bundle.putSerializable(StringConstants.ANSWERS, getAnswers(me, userId, page)); receiver.send(GET_USER_ANSWERS, bundle); break; case GET_USER_INBOX: bundle.putSerializable(StringConstants.INBOX_ITEMS, userService.getInbox(page, 25)); receiver.send(GET_USER_INBOX, bundle); break; case GET_USER_UNREAD_INBOX: getUnreadInboxItems(intent); break; case GET_USER_SITES: bundle.putSerializable(StringConstants.SITES, getUserSites(receiver, intent.getBooleanExtra(StringConstants.AUTHENTICATED, me))); receiver.send(GET_USER_SITES, bundle); break; case GET_USER_FAVORITES: bundle.putSerializable(StringConstants.QUESTIONS, getFavorites(me, userId, page)); receiver.send(GET_USER_FAVORITES, bundle); break; case GET_USER_REP_HISTORY_FULL: bundle.putSerializable(StringConstants.REP_HISTORY, userService.reputationHistoryFull(page)); receiver.send(GET_USER_REP_HISTORY_FULL, bundle); break; case DEAUTH_APP: deauthenticateApp(intent.getStringExtra(StringConstants.ACCESS_TOKEN)); break; default: LogWrapper.e(TAG, "Unknown action: " + action); break; } } catch (AbstractHttpException e) { if (receiver != null) { bundle.putSerializable(StringConstants.EXCEPTION, e); receiver.send(ERROR, bundle); } } } private StackXPage<User> getUserDetail(boolean me, long userId, boolean refresh, String site, int page) { if (me) { final ProfileDAO profileDAO = new ProfileDAO(getApplicationContext()); StackXPage<User> userPage = null; try { profileDAO.open(); User myProfile = null; if (!refresh) myProfile = profileDAO.getMe(site); if (myProfile == null) userPage = getUserProfile(profileDAO, site); else { if (AppUtils.aHalfAnHourSince(myProfile.lastUpdateTime)) syncUserProfile(site); userPage = new StackXPage<User>(); userPage.items = new ArrayList<User>(); userPage.items.add(myProfile); } } catch (SQLException e) { LogWrapper.e(TAG, e.getMessage()); } finally { profileDAO.close(); } return userPage; } else return userService.getUserById(userId, site); } private void syncUserProfile(final String site) { AppUtils.runOnBackgroundThread(new Runnable() { @Override public void run() { ProfileDAO profileDAO = new ProfileDAO(getApplicationContext()); try { profileDAO.open(); getUserProfile(profileDAO, site); } catch (SQLException e) { LogWrapper.e(TAG, e.getMessage()); } finally { profileDAO.close(); } } }); } private HashMap<String, Account> getUserAccounts(boolean me, StackXPage<User> userDetail) { if (me) return getMyAccounts(); if (userDetail != null && userDetail.items != null && !userDetail.items.isEmpty()) return userService.getAccount(userDetail.items.get(0).accountId); return null; } private HashMap<String, Account> getMyAccounts() { long accountId = SharedPreferencesUtil.getLong(getApplicationContext(), StringConstants.ACCOUNT_ID, -1); if (accountId != -1) { ArrayList<Account> accounts = UserAccountsDAO.get(getApplicationContext(), accountId); if (accounts == null) return userService.getMyAccount(); HashMap<String, Account> accountsMap = new HashMap<String, Account>(); if (accounts != null) { for (Account account : accounts) accountsMap.put(account.siteUrl, account); } return accountsMap; } return null; } private StackXPage<Question> getQuestions(boolean me, long userId, int page) { return me ? userService.getMyQuestions(page) : userService.getQuestionsByUser(userId, page); } private StackXPage<Answer> getAnswers(boolean me, long userId, int page) { return me ? userService.getMyAnswers(page) : userService.getAnswersByUser(userId, page); } private StackXPage<Question> getFavorites(boolean me, long userId, int page) { return me ? userService.getMyFavorites(page) : userService.getFavoritesByUser(userId, page); } private void getUnreadInboxItems(Intent intent) { int totalNewMsgs = 0; int page = intent.getIntExtra(StringConstants.PAGE, 1); StackXPage<InboxItem> pageObj = userService.getUnreadItemsInInbox(page); if (pageObj != null && pageObj != null && !pageObj.items.isEmpty()) { LogWrapper.d(TAG, "New unread inbox items found. Notifying reeiver"); totalNewMsgs += pageObj.items.size(); broadcastUnreadItemsCount(totalNewMsgs, pageObj); } } private void broadcastUnreadItemsCount(int totalNewMsgs, StackXPage<InboxItem> unreadInboxItems) { Intent broadcastIntent = new Intent(); broadcastIntent.setAction(UserIntentAction.NEW_MSG.getAction()); broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT); broadcastIntent.putExtra(UserIntentAction.NEW_MSG.getAction(), unreadInboxItems); sendBroadcast(broadcastIntent); } private ArrayList<Site> getUserSites(ResultReceiver receiver, boolean forAuthenicatedUser) { ArrayList<Site> sites = getSites(); if (sites != null && !sites.isEmpty()) return sites; LinkedHashMap<String, Site> linkSitesMap = userService.getAllSitesInNetwork(); if (!forAuthenicatedUser) return persistAndGetList(linkSitesMap); LinkedHashMap<String, Site> regSitesFirstMap = new LinkedHashMap<String, Site>(); HashMap<String, Account> linkAccountsMap = userService.getMyAccount(); if (linkAccountsMap != null && linkSitesMap != null) { long accountId = SharedPreferencesUtil.getLong(getApplicationContext(), StringConstants.ACCOUNT_ID, -1); if (accountId == -1 && !linkAccountsMap.isEmpty()) { accountId = linkAccountsMap.values().iterator().next().id; LogWrapper.d(TAG, "Setting account id in shared preferences: " + accountId); SharedPreferencesUtil.setLong(getApplicationContext(), StringConstants.ACCOUNT_ID, accountId); SharedPreferencesUtil.setLong(getApplicationContext(), StringConstants.ACCOUNTS_LAST_UPDATED, System.currentTimeMillis()); DbRequestThreadExecutor.persistAccounts(getApplicationContext(), new ArrayList<Account>(linkAccountsMap.values())); } for (String siteUrl : linkAccountsMap.keySet()) { if (linkSitesMap.containsKey(siteUrl)) { LogWrapper.d("Usertype for " + siteUrl, linkAccountsMap.get(siteUrl).userType.name()); Site site = linkSitesMap.get(siteUrl); site.userId = linkAccountsMap.get(siteUrl).userId; site.userType = linkAccountsMap.get(siteUrl).userType; regSitesFirstMap.put(siteUrl, site); linkSitesMap.remove(siteUrl); } } regSitesFirstMap.putAll(linkSitesMap); } return persistAndGetList(regSitesFirstMap); } private ArrayList<Site> getSites() { SiteDAO siteDAO = new SiteDAO(getApplicationContext()); try { siteDAO.open(); return siteDAO.getSites(); } catch (SQLException e) { LogWrapper.e(TAG, e.getMessage()); } finally { siteDAO.close(); } return null; } private ArrayList<Site> persistAndGetList(LinkedHashMap<String, Site> linkSitesMap) { ArrayList<Site> sites = new ArrayList<Site>(linkSitesMap.values()); DbRequestThreadExecutor.persistSites(getApplicationContext(), sites); return sites; } private void deauthenticateApp(String accessToken) { Intent broadcastIntent = new Intent(); broadcastIntent.setAction(UserIntentAction.LOGOUT.getAction()); broadcastIntent.putExtra(UserIntentAction.LOGOUT.getAction(), userService.logout(accessToken)); broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT); sendBroadcast(broadcastIntent); } protected StackXPage<User> getUserProfile(final ProfileDAO profileDAO, String site) { StackXPage<User> userPage = userService.getMe(site); if (userPage != null && userPage.items != null && !userPage.items.isEmpty()) { profileDAO.deleteMe(site); profileDAO.insert(site, userPage.items.get(0), true); SharedPreferencesUtil.setLong(getApplicationContext(), StringConstants.USER_ID, userPage.items.get(0).id); } return userPage; } }