/*
Copyright (C) 2013 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.Iterator;
import java.util.LinkedHashMap;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import com.prasanna.android.http.AbstractHttpException;
import com.prasanna.android.stacknetwork.StackNetworkListActivity;
import com.prasanna.android.stacknetwork.model.Account;
import com.prasanna.android.stacknetwork.model.Site;
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.SharedPreferencesUtil;
import com.prasanna.android.stacknetwork.utils.StringConstants;
import com.prasanna.android.utils.LogWrapper;
public class AccountSyncService extends AbstractStackxService {
private static final String TAG = AccountSyncService.class.getSimpleName();
private final static class ServiceHandler extends Handler {
private OnHandlerComplete onHandlerComplete;
private Context context;
public ServiceHandler(Looper looper, Context context, OnHandlerComplete onHandlerComplete) {
super(looper);
this.context = context;
this.onHandlerComplete = onHandlerComplete;
}
@Override
public void handleMessage(Message msg) {
boolean newThingsFound = false;
try {
HashMap<String, Site> sites = SiteDAO.getAll(context);
if (sites != null && AppUtils.isNetworkAvailable(context)) {
long sitesLastUpdated = SiteDAO.getLastUpdateTime(context);
if (AppUtils.aDaySince(sitesLastUpdated)) refreshSiteList(sites);
long accountsLastUpdated = SharedPreferencesUtil.getLong(context, StringConstants.ACCOUNTS_LAST_UPDATED, 0L);
if (AppUtils.aHalfAnHourSince(accountsLastUpdated)) newThingsFound = syncAccounts(sites);
}
onHandlerComplete.onHandleMessageFinish(msg, newThingsFound);
} catch (AbstractHttpException e) {
LogWrapper.e(TAG, e.getMessage());
}
}
private boolean syncAccounts(HashMap<String, Site> sites) {
boolean accountsAdded = false;
boolean accountsDeleted = false;
LogWrapper.d(TAG, "Syncing user accounts");
long accountId = SharedPreferencesUtil.getLong(context, StringConstants.ACCOUNT_ID, 0L);
HashMap<String, Account> retrievedAccounts = UserServiceHelper.getInstance().getMyAccount();
ArrayList<Account> existingAccounts = UserAccountsDAO.get(context, accountId);
if (existingAccounts == null) {
LogWrapper.d(TAG, "User with no accounts has accounts");
addNewAccounts(sites, retrievedAccounts);
accountsAdded = true;
} else {
if (retrievedAccounts != null) {
accountsDeleted =
checkAndUpdateForDeletedAccounts(new HashMap<String, Account>(retrievedAccounts), new ArrayList<Account>(
existingAccounts));
accountsAdded =
checkAndUpdateNewAccounts(sites, new HashMap<String, Account>(retrievedAccounts), new ArrayList<Account>(
existingAccounts));
}
}
SharedPreferencesUtil.setLong(context, StringConstants.ACCOUNTS_LAST_UPDATED, System.currentTimeMillis());
return accountsAdded || accountsDeleted;
}
private boolean checkAndUpdateForDeletedAccounts(HashMap<String, Account> retrievedAccounts,
ArrayList<Account> existingAccounts) {
int existingAccountsSize = existingAccounts.size();
Iterator<Account> existingAccountIter = existingAccounts.iterator();
while (existingAccountIter.hasNext()) {
Account existingAccount = existingAccountIter.next();
if (retrievedAccounts.containsKey(existingAccount.siteUrl)) {
LogWrapper.d(TAG, "Existing account: " + existingAccount.siteName);
existingAccountIter.remove();
}
}
if (existingAccounts.size() > 0 && existingAccountsSize != existingAccounts.size()) {
LogWrapper.d(TAG, "Removing accounts from DB");
removeAccounts(existingAccounts);
return true;
}
return false;
}
private void removeAccounts(ArrayList<Account> existingAccounts) {
UserAccountsDAO.delete(context, existingAccounts);
SiteDAO.updateSites(context, existingAccounts, false);
}
private boolean checkAndUpdateNewAccounts(HashMap<String, Site> sites, HashMap<String, Account> retrievedAccounts,
ArrayList<Account> existingAccounts) {
ArrayList<Account> newAccounts = null;
for (Account existingAccount : existingAccounts) {
if (retrievedAccounts.containsKey(existingAccount.siteUrl)) retrievedAccounts.remove(existingAccount.siteUrl);
}
if (!retrievedAccounts.isEmpty()) {
for (String key : retrievedAccounts.keySet()) {
LogWrapper.d(TAG, "New account : " + key);
if (newAccounts == null) newAccounts = new ArrayList<Account>();
newAccounts.add(retrievedAccounts.get(key));
}
if (newAccounts != null) {
UserAccountsDAO.insertAll(context, newAccounts);
SiteDAO.updateSites(context, newAccounts, true);
return true;
}
}
return false;
}
private void addNewAccounts(HashMap<String, Site> sites, HashMap<String, Account> retrievedAccounts) {
UserAccountsDAO.insertAll(context, new ArrayList<Account>(retrievedAccounts.values()));
}
private void refreshSiteList(HashMap<String, Site> sites) {
LinkedHashMap<String, Site> retrievedSites = UserServiceHelper.getInstance().getAllSitesInNetwork();
if (retrievedSites != null) {
boolean updateAuditEntry = true;
for (String key : retrievedSites.keySet()) {
if (!sites.containsKey(key)) {
SiteDAO.insert(context, retrievedSites.get(key));
if (updateAuditEntry) updateAuditEntry = false;
}
}
if (updateAuditEntry) SiteDAO.updateLastUpdateTime(context);
}
}
}
@Override
protected Handler getServiceHandler(Looper looper) {
return new ServiceHandler(looper, getApplicationContext(), new OnHandlerComplete() {
@Override
public void onHandleMessageFinish(Message message, Object... args) {
setRunning(false);
Boolean newThingsFound = (Boolean) args[0];
if (newThingsFound)
AccountSyncService.this.sendBroadcast(new Intent(StackNetworkListActivity.ACCOUNT_UPDATE_INTENT_FILTER));
AccountSyncService.this.stopSelf(message.arg1);
}
});
}
}