/*
* Copyright (C) 2010-2011 Geometer Plus <contact@geometerplus.com>
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
package org.geometerplus.android.fbreader.network;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import android.os.Message;
import android.os.Handler;
import org.geometerplus.fbreader.network.INetworkLink;
import org.geometerplus.fbreader.network.NetworkItem;
abstract class ItemsLoadingHandler extends Handler {
private static final int WHAT_UPDATE_ITEMS = 0;
private static final int WHAT_FINISHED = 1;
private final LinkedList<NetworkItem> myItems = new LinkedList<NetworkItem>();
private final HashMap<INetworkLink, LinkedList<NetworkItem>> myUncommitedItems = new HashMap<INetworkLink, LinkedList<NetworkItem>>();
private final Object myItemsMonitor = new Object();
private volatile boolean myFinishProcessed;
private final Object myFinishMonitor = new Object();
public final void addItem(INetworkLink link, NetworkItem item) {
synchronized (myItemsMonitor) {
myItems.add(item);
LinkedList<NetworkItem> uncommited = myUncommitedItems.get(link);
if (uncommited == null) {
uncommited = new LinkedList<NetworkItem>();
myUncommitedItems.put(link, uncommited);
}
uncommited.add(item);
}
}
public final void commitItems(INetworkLink link) {
synchronized (myItemsMonitor) {
LinkedList<NetworkItem> uncommited = myUncommitedItems.get(link);
if (uncommited != null) {
uncommited.clear();
}
}
}
public final void ensureItemsProcessed() {
synchronized (myItemsMonitor) {
while (myItems.size() > 0) {
try {
myItemsMonitor.wait();
} catch (InterruptedException e) {
}
}
}
}
private final void doUpdateItems() {
synchronized (myItemsMonitor) {
onUpdateItems(myItems);
myItems.clear();
myItemsMonitor.notifyAll(); // wake up process, that waits for finish condition (see ensureFinish() method)
}
afterUpdateItems();
}
public final void ensureFinishProcessed() {
synchronized (myFinishMonitor) {
while (!myFinishProcessed) {
try {
myFinishMonitor.wait();
} catch (InterruptedException e) {
}
}
}
}
private final void doProcessFinish(String errorMessage, boolean interrupted) {
HashSet<NetworkItem> uncommitedItems = new HashSet<NetworkItem>();
synchronized (myUncommitedItems) {
for (LinkedList<NetworkItem> items: myUncommitedItems.values()) {
uncommitedItems.addAll(items);
}
}
synchronized (myFinishMonitor) {
onFinish(errorMessage, interrupted, uncommitedItems);
myFinishProcessed = true;
myFinishMonitor.notifyAll(); // wake up process, that waits for finish condition (see ensureFinish() method)
}
}
// sending messages methods
public final void sendUpdateItems() {
sendEmptyMessage(WHAT_UPDATE_ITEMS);
}
public final void sendFinish(String errorMessage, boolean interrupted) {
int arg1 = interrupted ? 1 : 0;
sendMessage(obtainMessage(WHAT_FINISHED, arg1, 0, errorMessage));
}
// callbacks
public abstract void onUpdateItems(List<NetworkItem> items);
public abstract void afterUpdateItems();
public abstract void onFinish(String errorMessage, boolean interrupted, Set<NetworkItem> uncommitedItems);
@Override
public final void handleMessage(Message message) {
switch (message.what) {
case WHAT_UPDATE_ITEMS:
doUpdateItems();
break;
case WHAT_FINISHED:
doProcessFinish((String) message.obj, message.arg1 != 0);
break;
}
}
}