package org.limewire.ui.swing.friends.refresh;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import javax.swing.AbstractAction;
import javax.swing.Timer;
import org.limewire.core.api.library.RemoteLibraryManager;
import org.limewire.core.api.search.SearchResult;
import org.limewire.core.api.search.browse.BrowseSearch;
import org.limewire.inject.EagerSingleton;
import org.limewire.ui.swing.search.DefaultSearchRepeater;
import org.limewire.ui.swing.search.SearchRepeater;
import org.limewire.ui.swing.search.model.SearchResultsModel;
import ca.odell.glazedlists.event.ListEvent;
import ca.odell.glazedlists.event.ListEventListener;
import com.google.inject.Inject;
@EagerSingleton
public class AllFriendsRefreshManager implements SearchRepeater{
/**
* The amount of time before a second refresh status update is fired
*/
private static final long DELAY = 10 * 1000;
private final RemoteLibraryManager remoteLibraryManager;
/**The earliest time a status change can be fired. Initialized to January 1, 1970.*/
private long earliestPossibleFiringTime = 0;
private boolean hasInsert = false;
private boolean hasDelete = false;
private BrowseSearch allFriendsBrowse;
private SearchResultsModel allFriendsModel;
private final Timer delayTimer = new DelayTimer();
private ArrayList<BrowseRefreshStatusListener> statusListeners = new ArrayList<BrowseRefreshStatusListener>();
@Inject
public AllFriendsRefreshManager(RemoteLibraryManager remoteLibraryManager){
this.remoteLibraryManager = remoteLibraryManager;
}
@Inject
public void register(){
remoteLibraryManager.getAllFriendsFileList().getSwingModel().addListEventListener(new ListEventListener<SearchResult>() {
public void listChanged(ListEvent<SearchResult> listChanges) {
while(listChanges.next()) {
if(listChanges.getType() == ListEvent.INSERT) {
hasInsert = true;
} else if (listChanges.getType() == ListEvent.DELETE){
hasDelete = true;
}
if(hasInsert & hasDelete) {
break;
}
}
fireCurrentStatus();
};
});
}
public void addBrowseRefreshStatusListener(BrowseRefreshStatusListener listener){
statusListeners.add(listener);
}
public void removeBrowseRefreshStatusListener(BrowseRefreshStatusListener listener){
statusListeners.remove(listener);
}
/**
* Fires the current status immediately if more time than DELAY has elapsed since the previous status change.
* Fires with a delay otherwise.
*/
private void fireCurrentStatus(){
if (!delayTimer.isRunning()) {
long delayRemaining = earliestPossibleFiringTime - System.currentTimeMillis();
if (delayRemaining <= 0) {
fireCurrentStatusNow();
} else {
delayTimer.setInitialDelay((int)(delayRemaining));
delayTimer.start();
}
}
}
private void fireCurrentStatusNow() {
// we only have an insert if there is currently something in the library
hasInsert = hasInsert && hasSharedFiles();
if (hasInsert && hasDelete) {
fireRefreshStatusChange(BrowseRefreshStatus.CHANGED);
} else if (hasInsert) {
fireRefreshStatusChange(BrowseRefreshStatus.ADDED);
} else if (hasDelete) {
fireRefreshStatusChange(BrowseRefreshStatus.REMOVED);
}
}
public void registerBrowseSearch(BrowseSearch allFriendsBrowse, SearchResultsModel allFriendsModel){
this.allFriendsBrowse = allFriendsBrowse;
this.allFriendsModel = allFriendsModel;
//We have a new BrowseSearch because a new one just started. This means we are refreshed.
fireRefreshed();
}
public void clearBrowseSearch(){
this.allFriendsBrowse = null;
this.allFriendsModel = null;
}
@Override
public void refresh() {
if (needsRefresh()) {
new DefaultSearchRepeater(allFriendsBrowse, allFriendsModel).refresh();
fireRefreshed();
}
}
private void fireRefreshed(){
hasInsert = false;
hasDelete = false;
delayTimer.stop();
fireRefreshStatusChange(BrowseRefreshStatus.REFRESHED);
}
private void fireRefreshStatusChange(BrowseRefreshStatus status){
earliestPossibleFiringTime = System.currentTimeMillis() + DELAY;
for(BrowseRefreshStatusListener listener : statusListeners){
listener.statusChanged(status);
}
}
public boolean needsRefresh() {
return hasInsert || hasDelete;
}
public boolean hasSharedFiles(){
return remoteLibraryManager.getAllFriendsFileList().getSwingModel().size() > 0;
}
private class DelayTimer extends Timer {
public DelayTimer() {
super(0, new FireStatusChangeAction());
setRepeats(false);
}
}
private class FireStatusChangeAction extends AbstractAction {
@Override
public void actionPerformed(ActionEvent e) {
fireCurrentStatusNow();
}
}
}