com.bellman.bible.android.control.link.LinkControl.java Source code

Java tutorial

Introduction

Here is the source code for com.bellman.bible.android.control.link.LinkControl.java

Source

package com.bellman.bible.android.control.link;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

import com.bellman.bible.android.activity.R;
import com.bellman.bible.android.control.ControlFactory;
import com.bellman.bible.android.control.page.CurrentPageManager;
import com.bellman.bible.android.control.page.window.WindowControl;
import com.bellman.bible.android.control.search.SearchControl;
import com.bellman.bible.android.control.search.SearchControl.SearchBibleSection;
import com.bellman.bible.android.view.activity.base.CurrentActivityHolder;
import com.bellman.bible.android.view.activity.base.Dialogs;
import com.bellman.bible.android.view.activity.search.SearchIndex;
import com.bellman.bible.android.view.activity.search.SearchResults;
import com.bellman.bible.service.common.CommonUtils;
import com.bellman.bible.service.sword.SwordDocumentFacade;

import org.apache.commons.lang3.StringUtils;
import org.crosswire.jsword.book.Book;
import org.crosswire.jsword.book.BookException;
import org.crosswire.jsword.book.FeatureType;
import org.crosswire.jsword.book.basic.AbstractPassageBook;
import org.crosswire.jsword.index.IndexStatus;
import org.crosswire.jsword.index.search.SearchType;
import org.crosswire.jsword.passage.Key;
import org.crosswire.jsword.passage.NoSuchKeyException;
import org.crosswire.jsword.passage.PassageKeyFactory;
import org.crosswire.jsword.versification.Versification;

import java.net.URLDecoder;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Control traversal via links pressed by user in a browser e.g. to Strongs
 *
 * @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.
 */
public class LinkControl {

    private static final Pattern IBT_SPECIAL_CHAR_RE = Pattern.compile("_(\\d+)_");
    private static final String TAG = "LinkControl";
    private WindowControl windowControl;

    public LinkControl(WindowControl windowControl) {
        this.windowControl = windowControl;
    }

    /**
     * Currently the only uris handled are for Strongs refs
     * see OSISToHtmlSaxHandler.getStrongsUrl for format of uri
     *
     * @param uri
     * @return true if successfully changed to Strongs ref
     */
    public boolean loadApplicationUrl(String uri) {
        try {
            Log.d(TAG, "Loading: " + uri);

            // Prevent occasional class loading errors on Samsung devices
            Thread.currentThread().setContextClassLoader(getClass().getClassLoader());

            UriAnalyzer uriAnalyzer = new UriAnalyzer();
            if (uriAnalyzer.analyze(uri)) {
                switch (uriAnalyzer.getDocType()) {
                case BIBLE:
                    showBible(uriAnalyzer.getKey());
                    break;
                case GREEK_DIC:
                    showStrongs(SwordDocumentFacade.getInstance().getDefaultStrongsGreekDictionary(),
                            uriAnalyzer.getKey());
                    break;
                case HEBREW_DIC:
                    showStrongs(SwordDocumentFacade.getInstance().getDefaultStrongsHebrewDictionary(),
                            uriAnalyzer.getKey());
                    break;
                case ROBINSON:
                    showRobinsonMorphology(uriAnalyzer.getKey());
                    break;
                case ALL_GREEK:
                    showAllOccurrences(uriAnalyzer.getKey(), SearchBibleSection.ALL, "g");
                    break;
                case ALL_HEBREW:
                    showAllOccurrences(uriAnalyzer.getKey(), SearchBibleSection.ALL, "h");
                    break;
                case SPECIFIC_DOC:
                    showSpecificDocRef(uriAnalyzer.getBook(), uriAnalyzer.getKey());
                    break;
                default:
                    return false;
                }

            }
            // handled this url (or at least attempted to)
            return true;
        } catch (Exception e) {
            Log.e(TAG, "Error going to link", e);
            return false;
        }
    }

    private void showSpecificDocRef(String initials, String ref) throws NoSuchKeyException {
        if (StringUtils.isEmpty(initials)) {
            showBible(ref);
        } else {
            Book document = SwordDocumentFacade.getInstance().getDocumentByInitials(initials);
            if (document == null) {
                // tell user to install book
                Dialogs.getInstance().showErrorMsg(R.string.document_not_installed, initials);
            } else {
                //Foreign language keys may have been URLEncoded so need to URLDecode them e.g. UZV module at Matthew 1. The first link is "David" (looks a bit like DOBYA)
                ref = URLDecoder.decode(ref);

                //According to the OSIS schema, the osisRef attribute can contain letters and "_", but NOT punctuation and NOT spaces
                //IBT dictionary entries sometimes contain spaces but osisrefs can't so _32_ is used
                // e.g.  UZV Matthew 1:18: The link to "Holy Spirit" (Muqaddas Ruhdan)
                ref = replaceIBTSpecialCharacters(ref);

                Key bookKey = document.getKey(ref);
                showLink(document, bookKey);
            }
        }
    }

    /**
     * IBT use _nn_ for punctuation chars in references to dictionaries e.g. _32_ represents a space so 'Holy_32_Spirit' should be converted to 'Holy Spirit'
     *
     * @param ref Key e.g. dictionary key
     * @return ref with _nn_ replaced by punctuation
     */
    private String replaceIBTSpecialCharacters(String ref) {
        Matcher refIBTSpecialCharMatcher = IBT_SPECIAL_CHAR_RE.matcher(ref);
        StringBuffer output = new StringBuffer();
        while (refIBTSpecialCharMatcher.find()) {
            String specialChar = Character.toString((char) Integer.parseInt(refIBTSpecialCharMatcher.group(1)));
            refIBTSpecialCharMatcher.appendReplacement(output, specialChar);
        }
        refIBTSpecialCharMatcher.appendTail(output);
        return output.toString();
    }

    /**
     * user has selected a Bible verse link
     */
    private void showBible(String keyText) throws NoSuchKeyException {
        CurrentPageManager pageManager = getCurrentPageManager();
        Book bible = pageManager.getCurrentBible().getCurrentDocument();

        // get source versification
        Versification sourceDocumentVersification;
        Book currentDoc = pageManager.getCurrentPage().getCurrentDocument();
        if (currentDoc instanceof AbstractPassageBook) {
            sourceDocumentVersification = ((AbstractPassageBook) currentDoc).getVersification();
        } else {
            // default to v11n of current Bible.
            //TODO av11n issue.  GenBooks have no v11n and this default would be used for links from GenBooks which would only sometimes be correct
            sourceDocumentVersification = ((AbstractPassageBook) bible).getVersification();
        }

        // create Passage with correct source Versification
        Key key = PassageKeyFactory.instance().getKey(sourceDocumentVersification, keyText);

        // Bible not specified so use the default Bible version
        showLink(null, key);

        return;
    }

    /**
     * user has selected a Strong's Number link so show Strong's page for key in link
     */
    private void showStrongs(Book book, String key) throws NoSuchKeyException {

        // valid Strongs uri but Strongs refs not installed
        if (book == null) {
            Dialogs.getInstance().showErrorMsg(R.string.strongs_not_installed);
            // this uri request was handled by showing an error message
            return;
        }

        Key strongsNumberKey = book.getKey(key);
        showLink(book, strongsNumberKey);
    }

    /**
     * user has selected a morphology link so show morphology page for key in link
     */
    private void showRobinsonMorphology(String key) throws NoSuchKeyException {
        Book robinson = SwordDocumentFacade.getInstance().getDocumentByInitials("robinson");
        // valid Strongs uri but Strongs refs not installed
        if (robinson == null) {
            Dialogs.getInstance().showErrorMsg(R.string.morph_robinson_not_installed);
            // this uri request was handled by showing an error message
            return;
        }

        Key robinsonNumberKey = robinson.getKey(key);
        showLink(robinson, robinsonNumberKey);
    }

    private void showAllOccurrences(String ref, SearchBibleSection biblesection, String refPrefix) {
        Book currentBible = getCurrentPageManager().getCurrentBible().getCurrentDocument();
        Book strongsBible = null;

        // if current bible has no Strongs refs then try to find one that has
        if (currentBible.hasFeature(FeatureType.STRONGS_NUMBERS)) {
            strongsBible = currentBible;
        } else {
            strongsBible = SwordDocumentFacade.getInstance().getDefaultBibleWithStrongs();
        }

        // possibly no Strong's bible or it has not been indexed
        boolean needToDownloadIndex = false;
        if (strongsBible == null) {
            Dialogs.getInstance().showErrorMsg(R.string.no_indexed_bible_with_strongs_ref);
            return;
        } else if (currentBible.equals(strongsBible) && !checkStrongs(currentBible)) {
            Log.d(TAG, "Index status is NOT DONE");
            needToDownloadIndex = true;
        }

        // The below uses ANY_WORDS because that does not add anything to the search string
        //String noLeadingZeroRef = StringUtils.stripStart(ref, "0");
        String searchText = ControlFactory.getInstance().getSearchControl()
                .decorateSearchString("strong:" + refPrefix + ref, SearchType.ANY_WORDS, biblesection, null);
        Log.d(TAG, "Search text:" + searchText);

        Activity activity = CurrentActivityHolder.getInstance().getCurrentActivity();
        Bundle searchParams = new Bundle();
        searchParams.putString(SearchControl.SEARCH_TEXT, searchText);
        searchParams.putString(SearchControl.SEARCH_DOCUMENT, strongsBible.getInitials());
        searchParams.putString(SearchControl.TARGET_DOCUMENT, currentBible.getInitials());

        Intent intent = null;
        if (needToDownloadIndex) {
            intent = new Intent(activity, SearchIndex.class);
        } else {
            //If an indexed Strong's module is in place then do the search - the normal situation
            intent = new Intent(activity, SearchResults.class);
        }

        intent.putExtras(searchParams);
        activity.startActivity(intent);

        return;
    }

    /**
     * ensure a book is indexed and the index contains typical Greek or Hebrew Strongs Numbers
     */
    private boolean checkStrongs(Book bible) {
        try {
            return bible.getIndexStatus().equals(IndexStatus.DONE)
                    && (bible.find("+[Gen 1:1] strong:h7225").getCardinality() > 0
                            || bible.find("+[John 1:1] strong:g746").getCardinality() > 0
                            || bible.find("+[Gen 1:1] strong:g746").getCardinality() > 0);
        } catch (BookException be) {
            Log.e(TAG, "Error checking strongs numbers", be);
            return false;
        }
    }

    private void showLink(Book document, Key key) {
        // ask window controller to open link in dedicated Links window
        if (openLinksInDedicatedWindow()) {
            if (document == null) {
                windowControl.showLinkUsingDefaultBible(key);
            } else {
                windowControl.showLink(document, key);
            }
        } else {
            // old style - open links in current window
            CurrentPageManager currentPageManager = getCurrentPageManager();
            if (document == null) {
                document = currentPageManager.getCurrentBible().getCurrentDocument();
            }
            currentPageManager.setCurrentDocumentAndKey(document, key);
        }
    }

    private boolean openLinksInDedicatedWindow() {
        return CommonUtils.getSharedPreferences().getBoolean("open_links_in_special_window_pref", true);
    }

    private CurrentPageManager getCurrentPageManager() {
        return ControlFactory.getInstance().getCurrentPageControl();
    }
}