package com.gettingmobile.google.reader.sync;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteStatement;
import com.gettingmobile.google.reader.ElementId;
import com.gettingmobile.google.reader.ItemState;
import com.gettingmobile.google.reader.ItemTagChangeEvent;
import com.gettingmobile.google.reader.TagChangeOperation;
import com.gettingmobile.google.reader.db.ItemDatabaseAdapter;
import com.gettingmobile.google.reader.db.ItemTagChangeDatabaseAdapter;
import com.gettingmobile.google.reader.db.ItemTagChangeEventDatabaseAdapter;
import com.gettingmobile.google.reader.db.ItemTagChangeEventDatabaseAdapter.Group;
import com.gettingmobile.google.reader.rest.ChangeItemTagRequest;
import com.gettingmobile.google.reader.rest.GetEditTokenRequest;
import com.gettingmobile.rest.RequestCallback;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public final class PushSynchronizer extends AbstractSynchronizer {
private final ItemDatabaseAdapter itemAdapter;
private final ItemTagChangeEventDatabaseAdapter itemTagChangeEventAdapter;
public PushSynchronizer(SyncContext context) {
super(context);
/*
* create database adapters
*/
itemAdapter = new ItemDatabaseAdapter();
itemTagChangeEventAdapter = new ItemTagChangeEventDatabaseAdapter();
}
public boolean isPushRequired() {
return ItemTagChangeDatabaseAdapter.hasGlobalChanges(getDbHelper().getDatabase());
}
@Override
public int forecastMaxProgress() {
return
1 + // requesting edit token
1; // generating read state events
}
@Override
protected void doSync(SyncCallbackHelper callback) throws URISyntaxException, SyncException {
/*
* generate change events for read state
*/
createReadStateChangeEvents(callback);
callback.incrementProgress();
/*
* request edit token if required
*/
requestEditTokenIfRequired(callback);
/*
* send the change events to google reader
*/
boolean send = true;
while (send) {
throwCancelledIfApplicable();
send = sendNextItemTagChangeRequest(callback);
}
settings.updateLastSuccessfulPushTimestamp();
}
protected void requestEditTokenIfRequired(final SyncCallbackHelper callback) throws URISyntaxException, SyncException {
if (authenticator.hasValidEditToken()) {
callback.incrementProgress();
} else {
sendRequest(new GetEditTokenRequest(authenticator),
new RequestCallback<GetEditTokenRequest, String>() {
@Override
public void onRequestProcessed(GetEditTokenRequest request, String result, Throwable error) {
authenticator.setEditToken(result);
callback.incrementProgress();
}
});
}
}
private void insertReadStateChangePart(
SQLiteStatement statement, ItemDatabaseAdapter.ReadStateChange r, boolean invert, ItemState state) {
itemTagChangeEventAdapter.insert(statement, new ItemTagChangeEvent(
r.itemId, r.feedId, invert ? !r.read : r.read, state.getId()));
}
protected void createReadStateChangeEvents(SyncCallbackHelper callback) {
final SQLiteDatabase db = getDbHelper().getDatabase();
db.beginTransaction();
try {
final SQLiteStatement s = itemTagChangeEventAdapter.compileInsertStatement(db);
final List<ItemDatabaseAdapter.ReadStateChange> readStateChanges = itemAdapter.readReadStateChanges(db);
for (ItemDatabaseAdapter.ReadStateChange r : readStateChanges) {
insertReadStateChangePart(s, r, false, ItemState.READ);
insertReadStateChangePart(s, r, true, ItemState.KEPT_UNREAD);
insertReadStateChangePart(s, r, true, ItemState.TRACKING_KEPT_UNREAD);
}
itemAdapter.updateSyncedRead(db);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
callback.addMaxProgress(itemTagChangeEventAdapter.readGroupCount(getDbHelper().getDatabase(), ChangeItemTagRequest.MAX_ITEMS));
callback.incrementProgress();
}
protected boolean sendNextItemTagChangeRequest(SyncCallbackHelper callback) throws URISyntaxException, SyncException {
/*
* retrieve next items to be adjusted
*/
final SQLiteDatabase db = getDbHelper().getDatabase();
final Group g = itemTagChangeEventAdapter.readFirstGroup(db);
if (g == null) {
return false;
}
final List<ItemTagChangeEvent> events =
itemTagChangeEventAdapter.readByTagAndOperation(db, g.tag, g.operation, ChangeItemTagRequest.MAX_ITEMS);
final List<ElementId> feedIds = new ArrayList<ElementId>(events.size());
final List<ElementId> itemIds = new ArrayList<ElementId>(events.size());
for (ItemTagChangeEvent e : events) {
feedIds.add(e.getFeedId());
itemIds.add(e.getItemId());
}
/*
* build and send request
*/
final boolean add = TagChangeOperation.ADD == g.operation;
sendRequest(new ChangeItemTagRequest(
authenticator, feedIds, itemIds, add ? g.tag : null, add ? null : g.tag));
cleanUpItemTagChangeEvents(itemIds, g.operation, g.tag);
callback.incrementProgress();
return true;
}
protected void cleanUpItemTagChangeEvents(Collection<ElementId> itemIds, TagChangeOperation operation, ElementId tag) {
final SQLiteDatabase db = getDbHelper().getDatabase();
db.beginTransaction();
try {
for (ElementId itemId : itemIds) {
itemTagChangeEventAdapter.delete(db, itemId, tag, operation);
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
}