package org.wikipedia.readinglist;
import android.database.Cursor;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import org.wikipedia.WikipediaApp;
import org.wikipedia.concurrency.CallbackTask;
import org.wikipedia.database.DatabaseClient;
import org.wikipedia.database.contract.ReadingListContract;
import org.wikipedia.readinglist.database.ReadingListRow;
import org.wikipedia.readinglist.page.ReadingListPage;
import org.wikipedia.readinglist.page.database.ReadingListPageDao;
import java.util.ArrayList;
import java.util.List;
public final class ReadingListData {
private static final ReadingListData INSTANCE = new ReadingListData();
public static ReadingListData instance() {
return INSTANCE;
}
public void queryMruLists(@Nullable final String searchQuery,
@NonNull CallbackTask.Callback<List<ReadingList>> callback) {
CallbackTask.execute(new CallbackTask.Task<List<ReadingList>>() {
@Override public List<ReadingList> execute() {
return queryMruLists(searchQuery);
}
}, callback);
}
public List<ReadingList> queryMruLists(@Nullable String searchQuery) {
List<ReadingList> rows = new ArrayList<>();
Cursor cursor = lists(searchQuery);
try {
while (cursor.moveToNext()) {
rows.add(ReadingList.fromCursor(cursor));
}
} finally {
cursor.close();
}
return rows;
}
@NonNull public Cursor lists(@Nullable String searchQuery) {
Uri uri = ReadingListContract.ListWithPagesAndDisk.URI;
String selection = null;
String[] selectionArgs = null;
String searchStr = searchQuery;
if (!TextUtils.isEmpty(searchStr)) {
String titleCol = ReadingListContract.List.TITLE.qualifiedName();
searchStr = searchStr.replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_");
selection = "UPPER(" + titleCol + ") LIKE UPPER(?) ESCAPE '\\'";
selectionArgs = new String[]{"%" + searchStr + "%"};
}
String order = ReadingListContract.ListWithPagesAndDisk.ORDER_KEY + ','
+ ReadingListContract.ListWithPagesAndDisk.ORDER_MRU;
return listClient().select(uri, selection, selectionArgs, order);
}
public void addListAsync(@NonNull final ReadingList list) {
CallbackTask.execute(new CallbackTask.Task<Void>() {
@Override public Void execute() {
addList(list);
return null;
}
});
}
public synchronized void addList(@NonNull ReadingList list) {
listClient().persist(list);
for (ReadingListPage page : list.getPages()) {
page.addListKey(list.key());
ReadingListPageDao.instance().upsert(page);
ReadingListPageDao.instance().markOutdated(page);
}
}
public void removeListAsync(@NonNull final ReadingList list) {
CallbackTask.execute(new CallbackTask.Task<Void>() {
@Override public Void execute() {
removeList(list);
return null;
}
});
}
public void makeListMostRecent(@NonNull final ReadingList list) {
long now = System.currentTimeMillis();
list.atime(now);
CallbackTask.execute(new CallbackTask.Task<Void>() {
@Override public Void execute() {
saveListInfo(list);
return null;
}
});
}
public void saveListInfoAsync(@NonNull final ReadingList list) {
CallbackTask.execute(new CallbackTask.Task<Void>() {
@Override public Void execute() {
saveListInfo(list);
return null;
}
});
}
public void addTitleToList(@NonNull final ReadingList list,
@NonNull final ReadingListPage page,
boolean undo) {
list.add(page);
page.addListKey(list.key());
if (!undo) {
setPageOffline(page, true);
}
saveListInfo(list, page);
}
public void removeTitleFromList(@NonNull final ReadingList list,
@NonNull final ReadingListPage page) {
list.remove(page);
page.removeListKey(list.key());
saveListInfo(list, page);
}
public void listContainsTitleAsync(@NonNull final ReadingList list,
@NonNull final ReadingListPage page,
@NonNull CallbackTask.Callback<Boolean> callback) {
CallbackTask.execute(new CallbackTask.Task<Boolean>() {
@Override public Boolean execute() {
return listContainsTitle(list.key(), page.key());
}
}, callback);
}
public void anyListContainsTitleAsync(@NonNull final String key,
@NonNull CallbackTask.Callback<ReadingListPage> callback) {
CallbackTask.execute(new CallbackTask.Task<ReadingListPage>() {
@Override public ReadingListPage execute() {
return findPageInAnyList(key);
}
}, callback);
}
public synchronized void saveListInfo(@NonNull ReadingList list) {
listClient().persist(list);
}
public synchronized void renameAndSaveListInfo(@NonNull ReadingList list, String title) {
List<ReadingListPage> pages = list.getPages();
String oldKey = list.key();
listClient().delete(list, listClient().getPrimaryKeySelectionArgs(list));
list.setTitle(title);
listClient().persist(list);
for (ReadingListPage page : pages) {
page.removeListKey(oldKey);
page.addListKey(list.key());
ReadingListPageDao.instance().upsert(page);
}
}
public synchronized void setPageOffline(@NonNull ReadingListPage page, boolean offline) {
page.setOffline(offline);
ReadingListPageDao.instance().upsert(page);
}
public synchronized void removeList(@NonNull ReadingList list) {
listClient().delete(list, listClient().getPrimaryKeySelectionArgs(list));
for (ReadingListPage page : list.getPages()) {
page.removeListKey(list.key());
ReadingListPageDao.instance().upsert(page);
}
}
@Nullable
private synchronized ReadingListPage findPageInAnyList(String key) {
Cursor cursor = ReadingListPageDao.instance().page(key);
try {
if (cursor.getCount() != 0) {
cursor.moveToFirst();
return ReadingListPage.fromCursor(cursor);
}
} finally {
cursor.close();
}
return null;
}
private synchronized void saveListInfo(@NonNull ReadingList list, @NonNull ReadingListPage page) {
listClient().persist(list);
ReadingListPageDao.instance().upsert(page);
}
private synchronized boolean listContainsTitle(@NonNull String listKey, @NonNull String key) {
Cursor cursor = ReadingListPageDao.instance().pages(listKey);
try {
while (cursor.moveToNext()) {
ReadingListPage page = ReadingListPage.fromCursor(cursor);
if (page.key().equals(key)) {
return true;
}
}
return false;
} finally {
cursor.close();
}
}
private DatabaseClient<ReadingListRow> listClient() {
return client(ReadingListRow.class);
}
private <T> DatabaseClient<T> client(Class<T> clazz) {
return WikipediaApp.getInstance().getDatabaseClient(clazz);
}
}