package com.distantfuture.videos.services;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import com.distantfuture.videos.activities.AuthActivity;
import com.distantfuture.videos.database.DatabaseAccess;
import com.distantfuture.videos.database.DatabaseTables;
import com.distantfuture.videos.database.YouTubeData;
import com.distantfuture.videos.misc.AppUtils;
import com.distantfuture.videos.misc.BusEvents;
import com.distantfuture.videos.misc.DUtils;
import com.distantfuture.videos.youtube.YouTubeAPI;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import de.greenrobot.event.EventBus;
public class ListServiceTask {
private Context context;
public ListServiceTask(Context context, final ListServiceRequest request, final boolean hasFetchedData, boolean refresh) {
this.context = context;
if (!refresh) {
if (!hasFetchedData) {
DatabaseAccess access = new DatabaseAccess(context, request.databaseTable());
Cursor cursor = access.getCursor(DatabaseTables.ALL_ITEMS, request.requestIdentifier());
if (!cursor.moveToFirst())
refresh = true;
cursor.close();
}
}
if (refresh) {
YouTubeAPI helper = new YouTubeAPI(context, false, true, new YouTubeAPI.YouTubeAPIListener() {
@Override
public void handleAuthIntent(final Intent authIntent) {
AuthActivity.show(ListServiceTask.this.context, authIntent, request.toBundle());
}
});
updateDataFromInternet(request, helper);
}
// notify that we handled an intent so pull to refresh can stop it's animation and other stuff
EventBus.getDefault().post(new BusEvents.YouTubeFragmentDataReady());
}
private List<YouTubeData> prepareDataFromNet(List<YouTubeData> inList, Set<String> currentListSavedData, String requestID) {
for (YouTubeData data : inList) {
// set the request id
data.mRequest = requestID;
if (currentListSavedData != null && currentListSavedData.size() > 0) {
String videoOrPl = data.mVideo == null ? data.mPlaylist : data.mVideo;
if (videoOrPl != null) {
if (currentListSavedData.contains(videoOrPl)) {
currentListSavedData.remove(videoOrPl); // faster?
data.setHidden(true);
}
}
}
}
return inList;
}
private Set<String> saveExistingListState(DatabaseAccess database, String requestIdentifier) {
Set<String> result = null;
// ask the database for the hidden items
List<YouTubeData> hiddenItems = database.getItems(DatabaseTables.HIDDEN_ITEMS, requestIdentifier, 0);
if (hiddenItems != null) {
result = new HashSet<String>();
for (YouTubeData data : hiddenItems) {
String videoOrPl = data.mVideo == null ? data.mPlaylist : data.mVideo;
if (videoOrPl != null) {
result.add(videoOrPl);
}
}
}
return result;
}
private void updateDataFromInternet(ListServiceRequest request, YouTubeAPI helper) {
String playlistID;
boolean removeAllFromDB = true;
List<YouTubeData> resultList = null;
// do we have internet access?
if (!AppUtils.instance(context).hasNetworkConnection()) {
DUtils.log("No internet connection. Method: " + DUtils.currentMethod());
return;
}
YouTubeAPI.BaseListResults listResults = null;
switch (request.type()) {
case RELATED:
YouTubeAPI.RelatedPlaylistType type = request.relatedType();
String channelID = request.channel();
playlistID = helper.relatedPlaylistID(type, channelID);
if (playlistID != null) // probably needed authorization and failed
resultList = retrieveVideoList(request, helper, playlistID, null, request.maxResults());
removeAllFromDB = false;
break;
case VIDEOS:
playlistID = request.playlist();
// can't use request.maxResults() since we have to get everything and sort it
resultList = retrieveVideoList(request, helper, playlistID, null, 0);
removeAllFromDB = false;
break;
case SEARCH:
String query = request.query();
listResults = helper.searchListResults(query, false);
break;
case LIKED:
listResults = helper.likedVideosListResults();
break;
case PLAYLISTS:
String channel = request.channel();
resultList = retrieveVideoList(request, helper, null, channel, request.maxResults());
// remove any playlists with 0 videos
Iterator<YouTubeData> iterator = resultList.iterator();
while (iterator.hasNext()) {
YouTubeData data = iterator.next();
if (data.mItemCount == 0) {
iterator.remove();
}
}
removeAllFromDB = false;
break;
case SUBSCRIPTIONS:
listResults = helper.subscriptionListResults(false);
break;
case CATEGORIES:
listResults = helper.categoriesListResults("US");
break;
}
if (resultList == null) {
if (listResults != null) {
resultList = listResults.getAllItems(request.maxResults());
}
}
if (resultList != null) {
DatabaseAccess database = new DatabaseAccess(context, request.databaseTable());
Set currentListSavedData = saveExistingListState(database, request.requestIdentifier());
resultList = prepareDataFromNet(resultList, currentListSavedData, request.requestIdentifier());
if (removeAllFromDB)
database.deleteAllRows(request.requestIdentifier());
database.insertItems(resultList);
}
}
private List<YouTubeData> retrieveVideoList(ListServiceRequest request, YouTubeAPI helper, String playlistID, String channelID, int maxResults) {
List<YouTubeData> result = new ArrayList<YouTubeData>();
YouTubeAPI.BaseListResults videoResults;
if (playlistID != null)
videoResults = helper.videosFromPlaylistResults(playlistID);
else
videoResults = helper.channelPlaylistsResults(channelID, false);
if (videoResults != null) {
List<YouTubeData> videoData = videoResults.getAllItems(maxResults);
// extract just the video ids from list
List<String> videoIds = YouTubeData.contentIdsList(videoData);
// remove videos that we already have...
videoIds = removeVideosWeAlreadyHave(request, videoIds);
final int limit = YouTubeAPI.youTubeMaxResultsLimit();
for (int n = 0; n < videoIds.size(); n += limit) {
int chunkSize = Math.min(videoIds.size(), n + limit);
List<String> chunk = videoIds.subList(n, chunkSize);
if (playlistID != null)
videoResults = helper.videoInfoListResults(chunk);
else
videoResults = helper.playlistInfoListResults(chunk);
result.addAll(videoResults.getItems(0));
}
}
return result;
}
private List<String> removeVideosWeAlreadyHave(ListServiceRequest request, List<String> newVideoIds) {
List<String> result = newVideoIds; // return same list if not modified
DatabaseAccess database = new DatabaseAccess(context, request.databaseTable());
List<YouTubeData> existingItems = database.getItems(DatabaseTables.CONTENT_ONLY, request.requestIdentifier(), 0);
if (existingItems != null) {
Set existingIds = new HashSet<String>(existingItems.size());
for (YouTubeData data : existingItems) {
String videoOrPl = data.mVideo == null ? data.mPlaylist : data.mVideo;
if (videoOrPl != null) {
existingIds.add(videoOrPl);
}
}
if (existingIds.size() > 0) {
result = new ArrayList<String>(newVideoIds.size());
for (String videoId : newVideoIds) {
if (!existingIds.contains(videoId)) {
result.add(videoId);
}
}
}
}
boolean debugging = false;
if (debugging) {
DUtils.log("removed: " + (newVideoIds.size() - result.size()));
DUtils.log("returning: " + result.size());
}
return result;
}
}