package net.bible.android.control.bookmark;
import android.app.Activity;
import android.content.Intent;
import android.support.design.widget.Snackbar;
import android.util.Log;
import android.view.View;
import net.bible.android.activity.R;
import net.bible.android.common.resource.ResourceProvider;
import net.bible.android.control.ApplicationScope;
import net.bible.android.control.page.CurrentBiblePage;
import net.bible.android.control.page.CurrentPageManager;
import net.bible.android.control.page.window.ActiveWindowPageManagerProvider;
import net.bible.android.view.activity.base.CurrentActivityHolder;
import net.bible.android.view.activity.base.Dialogs;
import net.bible.android.view.activity.base.IntentHelper;
import net.bible.android.view.activity.bookmark.BookmarkLabels;
import net.bible.service.common.CommonUtils;
import net.bible.service.db.bookmark.BookmarkDBAdapter;
import net.bible.service.db.bookmark.BookmarkDto;
import net.bible.service.db.bookmark.LabelDto;
import net.bible.service.sword.SwordContentFacade;
import org.crosswire.jsword.passage.Key;
import org.crosswire.jsword.passage.VerseRange;
import org.crosswire.jsword.versification.Versification;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
/**
* @author Martin Denham [mjdenham at gmail dot com]
* @see gnu.lgpl.License for license details.<br>
* The copyright to this program is held by it's author.
*/
@ApplicationScope
public class BookmarkControl {
public static final String BOOKMARK_IDS_EXTRA = "bookmarkIds";
public static final String LABEL_NO_EXTRA = "labelNo";
private final LabelDto LABEL_ALL;
private final LabelDto LABEL_UNLABELLED;
private static final String BOOKMARK_SORT_ORDER = "BookmarkSortOrder";
private final SwordContentFacade swordContentFacade;
private final ActiveWindowPageManagerProvider activeWindowPageManagerProvider;
private static final String TAG = "BookmarkControl";
@Inject
public BookmarkControl(SwordContentFacade swordContentFacade, ActiveWindowPageManagerProvider activeWindowPageManagerProvider, ResourceProvider resourceProvider) {
this.swordContentFacade = swordContentFacade;
this.activeWindowPageManagerProvider = activeWindowPageManagerProvider;
LABEL_ALL = new LabelDto(-999L, resourceProvider.getString(R.string.all), null);
LABEL_UNLABELLED = new LabelDto(-998L, resourceProvider.getString(R.string.label_unlabelled), null);
}
public boolean toggleBookmarkForVerseRange(VerseRange verseRange) {
boolean bOk = false;
if (isCurrentDocumentBookmarkable()) {
BookmarkDto bookmarkDto = getBookmarkByKey(verseRange);
final Activity currentActivity = CurrentActivityHolder.getInstance().getCurrentActivity();
final View currentView = currentActivity.findViewById(android.R.id.content);
if (bookmarkDto !=null) {
if (deleteBookmark(bookmarkDto)) {
Snackbar.make(currentView, R.string.bookmark_deleted, Snackbar.LENGTH_SHORT).show();
} else {
Dialogs.getInstance().showErrorMsg(R.string.error_occurred);
}
} else {
// prepare new bookmark and add to db
bookmarkDto = new BookmarkDto();
bookmarkDto.setVerseRange(verseRange);
final BookmarkDto newBookmark = addBookmark(bookmarkDto);
if (newBookmark!=null) {
// success
int actionTextColor = CommonUtils.getResourceColor(R.color.snackbar_action_text);
Snackbar.make(currentView, R.string.bookmark_added, Snackbar.LENGTH_LONG).setActionTextColor(actionTextColor).setAction(R.string.assign_labels, new View.OnClickListener() {
@Override
public void onClick(View v) {
showBookmarkLabelsActivity(currentActivity, newBookmark);
}
}).show();
bOk = true;
} else {
Dialogs.getInstance().showErrorMsg(R.string.error_occurred);
}
}
}
return bOk;
}
// Label related methods
public void editBookmarkLabelsForVerseRange(VerseRange verseRange) {
if (isCurrentDocumentBookmarkable()) {
BookmarkDto bookmarkDto = getBookmarkByKey(verseRange);
final Activity currentActivity = CurrentActivityHolder.getInstance().getCurrentActivity();
if (bookmarkDto != null) {
// Show label view for new bookmark
showBookmarkLabelsActivity(currentActivity, bookmarkDto);
}
}
}
public String getBookmarkVerseKey(BookmarkDto bookmark) {
String keyText = "";
try {
Versification versification = activeWindowPageManagerProvider.getActiveWindowPageManager().getCurrentBible().getVersification();
keyText = bookmark.getVerseRange(versification).getName();
} catch (Exception e) {
Log.e(TAG, "Error getting verse text", e);
}
return keyText;
}
public String getBookmarkVerseText(BookmarkDto bookmark) {
String verseText = "";
try {
CurrentBiblePage currentBible = activeWindowPageManagerProvider.getActiveWindowPageManager().getCurrentBible();
Versification versification = currentBible.getVersification();
verseText = swordContentFacade.getPlainText(currentBible.getCurrentDocument(), bookmark.getVerseRange(versification), 1);
verseText = CommonUtils.limitTextLength(verseText);
} catch (Exception e) {
Log.e(TAG, "Error getting verse text", e);
}
return verseText;
}
// pure bookmark methods
/** get all bookmarks */
public List<BookmarkDto> getAllBookmarks() {
BookmarkDBAdapter db = new BookmarkDBAdapter();
List<BookmarkDto> bookmarkList = null;
try {
db.open();
bookmarkList = db.getAllBookmarks();
bookmarkList = getSortedBookmarks(bookmarkList);
} finally {
db.close();
}
return bookmarkList;
}
/** create a new bookmark */
public BookmarkDto addBookmark(BookmarkDto bookmark) {
BookmarkDBAdapter db = new BookmarkDBAdapter();
BookmarkDto newBookmark = null;
try {
db.open();
newBookmark = db.insertBookmark(bookmark);
} finally {
db.close();
}
return newBookmark;
}
/** get all bookmarks */
public List<BookmarkDto> getBookmarksById(long[] ids) {
List<BookmarkDto> bookmarks = new ArrayList<>();
BookmarkDBAdapter db = new BookmarkDBAdapter();
try {
db.open();
for (long id : ids) {
BookmarkDto bookmark = db.getBookmarkDto(id);
if (bookmark != null) {
bookmarks.add(bookmark);
}
}
} finally {
db.close();
}
return bookmarks;
}
public boolean isBookmarkForKey(Key key) {
return key!=null && getBookmarkByKey(key)!=null;
}
/** get bookmark with the same start verse as this key if it exists or return null */
private BookmarkDto getBookmarkByKey(Key key) {
BookmarkDBAdapter db = new BookmarkDBAdapter();
BookmarkDto bookmark = null;
try {
db.open();
bookmark = db.getBookmarkByStartKey(key.getOsisRef());
} finally {
db.close();
}
return bookmark;
}
/** delete this bookmark (and any links to labels) */
public boolean deleteBookmark(BookmarkDto bookmark) {
boolean bOk = false;
if (bookmark!=null && bookmark.getId()!=null) {
BookmarkDBAdapter db = new BookmarkDBAdapter();
try {
db.open();
bOk = db.removeBookmark(bookmark);
} finally {
db.close();
}
}
return bOk;
}
/** get bookmarks with the given label */
public List<BookmarkDto> getBookmarksWithLabel(LabelDto label) {
BookmarkDBAdapter db = new BookmarkDBAdapter();
List<BookmarkDto> bookmarkList = null;
try {
db.open();
if (LABEL_ALL.equals(label)) {
bookmarkList = db.getAllBookmarks();
} else if (LABEL_UNLABELLED.equals(label)) {
bookmarkList = db.getUnlabelledBookmarks();
} else {
bookmarkList = db.getBookmarksWithLabel(label);
}
assert bookmarkList!=null;
bookmarkList = getSortedBookmarks(bookmarkList);
} finally {
db.close();
}
return bookmarkList;
}
/** get bookmarks associated labels */
public List<LabelDto> getBookmarkLabels(BookmarkDto bookmark) {
List<LabelDto> labels;
BookmarkDBAdapter db = new BookmarkDBAdapter();
try {
db.open();
labels = db.getBookmarkLabels(bookmark);
} finally {
db.close();
}
return labels;
}
/** label the bookmark with these and only these labels */
public void setBookmarkLabels(BookmarkDto bookmark, List<LabelDto> labels) {
// never save LABEL_ALL
labels.remove(LABEL_ALL);
labels.remove(LABEL_UNLABELLED);
BookmarkDBAdapter db = new BookmarkDBAdapter();
try {
db.open();
List<LabelDto> prevLabels = db.getBookmarkLabels(bookmark);
//find those which have been deleted and remove them
Set<LabelDto> deleted = new HashSet<>(prevLabels);
deleted.removeAll(labels);
for (LabelDto label : deleted) {
db.removeBookmarkLabelJoin(bookmark, label);
}
//find those which are new and persist them
Set<LabelDto> added = new HashSet<>(labels);
added.removeAll(prevLabels);
for (LabelDto label : added) {
db.insertBookmarkLabelJoin(bookmark, label);
}
} finally {
db.close();
}
}
public LabelDto saveOrUpdateLabel(LabelDto label) {
BookmarkDBAdapter db = new BookmarkDBAdapter();
LabelDto retLabel = null;
try {
db.open();
if (label.getId()==null) {
retLabel = db.insertLabel(label);
} else {
retLabel = db.updateLabel(label);
}
} finally {
db.close();
}
return retLabel;
}
/** delete this bookmark (and any links to labels) */
public boolean deleteLabel(LabelDto label) {
boolean bOk = false;
if (label!=null && label.getId()!=null && !LABEL_ALL.equals(label) && !LABEL_UNLABELLED.equals(label)) {
BookmarkDBAdapter db = new BookmarkDBAdapter();
try {
db.open();
bOk = db.removeLabel(label);
} finally {
db.close();
}
}
return bOk;
}
public List<LabelDto> getAllLabels() {
List<LabelDto> labelList = getAssignableLabels();
// add special label that is automatically associated with all-bookmarks
labelList.add(0, LABEL_UNLABELLED);
labelList.add(0, LABEL_ALL);
return labelList;
}
public List<LabelDto> getAssignableLabels() {
BookmarkDBAdapter db = new BookmarkDBAdapter();
List<LabelDto> labelList = new ArrayList<>();
try {
db.open();
labelList.addAll(db.getAllLabels());
} finally {
db.close();
}
Collections.sort(labelList);
return labelList;
}
public void changeBookmarkSortOrder() {
if (getBookmarkSortOrder().equals(BookmarkSortOrder.BIBLE_BOOK)) {
setBookmarkSortOrder(BookmarkSortOrder.DATE_CREATED);
} else {
setBookmarkSortOrder(BookmarkSortOrder.BIBLE_BOOK);
}
}
private BookmarkSortOrder getBookmarkSortOrder() {
String bookmarkSortOrderStr = CommonUtils.getSharedPreference(BOOKMARK_SORT_ORDER, BookmarkSortOrder.BIBLE_BOOK.toString());
return BookmarkSortOrder.valueOf(bookmarkSortOrderStr);
}
private void setBookmarkSortOrder(BookmarkSortOrder bookmarkSortOrder) {
CommonUtils.saveSharedPreference(BOOKMARK_SORT_ORDER, bookmarkSortOrder.toString());
}
public String getBookmarkSortOrderDescription() {
if (BookmarkSortOrder.BIBLE_BOOK.equals(getBookmarkSortOrder())) {
return CommonUtils.getResourceString(R.string.sort_by_bible_book);
} else {
return CommonUtils.getResourceString(R.string.sort_by_date);
}
}
private List<BookmarkDto> getSortedBookmarks(List<BookmarkDto> bookmarkList) {
Comparator<BookmarkDto> comparator;
switch (getBookmarkSortOrder()) {
case DATE_CREATED:
comparator = new BookmarkCreationDateComparator();
break;
case BIBLE_BOOK:
default:
comparator = new BookmarkDtoBibleOrderComparator(bookmarkList);
break;
}
// the new Java 7 sort is stricter and occasionally generates errors, so prevent total crash on listing bookmarks
try {
Collections.sort(bookmarkList, comparator);
} catch (Exception e) {
Dialogs.getInstance().showErrorMsg(R.string.error_occurred, e);
}
return bookmarkList;
}
private boolean isCurrentDocumentBookmarkable() {
CurrentPageManager currentPageControl = activeWindowPageManagerProvider.getActiveWindowPageManager();
return currentPageControl.isBibleShown() || currentPageControl.isCommentaryShown();
}
private void showBookmarkLabelsActivity(Activity currentActivity, BookmarkDto bookmarkDto) {
// Show label view for new bookmark
final Intent intent = new Intent(currentActivity, BookmarkLabels.class);
intent.putExtra(BOOKMARK_IDS_EXTRA, new long[] {bookmarkDto.getId()});
currentActivity.startActivityForResult(intent, IntentHelper.REFRESH_DISPLAY_ON_FINISH);
}
}