/*******************************************************************************
* Copyright (c) 2012, Directors of the Tyndale STEP Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* Neither the name of the Tyndale House, Cambridge (www.TyndaleHouse.com)
* nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package com.tyndalehouse.step.core.xsl.impl;
import com.tyndalehouse.step.core.exceptions.StepInternalException;
import com.tyndalehouse.step.core.service.VocabularyService;
import com.tyndalehouse.step.core.service.jsword.JSwordVersificationService;
import com.tyndalehouse.step.core.utils.StringUtils;
import com.tyndalehouse.step.core.xsl.InterlinearProvider;
import com.tyndalehouse.step.core.xsl.MultiInterlinearProvider;
import org.crosswire.jsword.passage.Key;
import org.crosswire.jsword.passage.PassageKeyFactory;
import org.crosswire.jsword.versification.Versification;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
import static com.tyndalehouse.step.core.utils.StringUtils.areAnyBlank;
import static com.tyndalehouse.step.core.utils.StringUtils.isBlank;
import static com.tyndalehouse.step.core.utils.StringUtils.isNotBlank;
import static com.tyndalehouse.step.core.utils.StringUtils.split;
/**
* This implementation will support multiple versions, so each of the methods is keyed by version requested.
*
* @author chrisburrell
*/
public class MultiInterlinearProviderImpl implements MultiInterlinearProvider {
/**
* we separate by commas and spaces.
*/
static final String VERSION_SEPARATOR = ", ?";
private static final Logger LOGGER = LoggerFactory.getLogger(MultiInterlinearProviderImpl.class);
/**
* The interlinear providers.
*/
private final Map<String, InterlinearProvider> interlinearProviders = new HashMap<String, InterlinearProvider>();
private final JSwordVersificationService versificationService;
private String lastSeenOsisId;
/**
* sets up the interlinear provider with the correct version and text scope.
*
* @param masterVersion the master version
* @param versions the versions to use to set up the interlinear
* @param textScope the reference, or passage range that should be considered when setting up the
* interlinear provider
* @param versificationService the service for working with a book
* @param vocabProvider the provider of vocabulary
* @param stripGreekAccents true to ensure Greek accents are stripped off Hebrew texts
* @param stripHebrewAccents true to ensure Hebrew accents are stripped off Hebrew texts
* @param stripVowels true to ensure accents are stripped off Greek texts
*/
public MultiInterlinearProviderImpl(
final String masterVersion,
final Versification masterVersification,
String versions,
final String textScope,
final JSwordVersificationService versificationService, final VocabularyService vocabProvider,
final boolean stripGreekAccents, final boolean stripHebrewAccents, final boolean stripVowels) {
this.versificationService = versificationService;
// first check whether the values passed in are correct
if (areAnyBlank(versions, textScope)) {
return;
}
try {
final Map<String, String> hebrewDirectMapping = initHebrewDirectMapping();
final Map<String, String> hebrewIndirectMappings = initHebrewIndirectMappings();
final String[] differentVersions = split(versions, VERSION_SEPARATOR);
Key versifiedKey = PassageKeyFactory.instance().getKey(masterVersification, textScope);
for (final String version : differentVersions) {
if (isNotBlank(version)) {
final String normalisedVersion = version.trim();
this.interlinearProviders.put(normalisedVersion, new InterlinearProviderImpl(masterVersion, masterVersification,
versificationService, normalisedVersion, versifiedKey, hebrewDirectMapping,
hebrewIndirectMappings, vocabProvider, stripGreekAccents, stripHebrewAccents, stripVowels));
}
}
// CHECKSTYLE:OFF
// called by an XSLT so need to trap error and log, then throw up perhaps
} catch (final Exception ex) {
// CHECKSTYLE:ON
LOGGER.error(ex.getMessage(), ex);
throw new StepInternalException(ex.getMessage(), ex);
}
}
/**
* Inits the hebrew indirect mappings. These are used if no link is found.
*
* @return the mapping between the strong numbers and their corresponding English.
*/
private Map<String, String> initHebrewIndirectMappings() {
final Map<String, String> hebrewLexicon = new HashMap<String, String>(9);
hebrewLexicon.put("1961", "#to be");
hebrewLexicon.put("3588", "#that");
hebrewLexicon.put("996", "#between");
hebrewLexicon.put("413", "#to");
hebrewLexicon.put("834", "#that");
hebrewLexicon.put("3605", "#all");
hebrewLexicon.put("3606", "#all");
hebrewLexicon.put("5921", "#on");
hebrewLexicon.put("4480", "#from");
hebrewLexicon.put("3651", "#thus");
return hebrewLexicon;
}
/**
* Inits the hebrew direct mapping. The override, regardless of whether the interlineared text contains a mapping
*
* @return the mappings between strong numbers and the words that should appear
*/
private Map<String, String> initHebrewDirectMapping() {
final Map<String, String> blackList = new HashMap<String, String>(2);
blackList.put("853", "#the");
blackList.put("854", "#the");
return blackList;
}
@Override
public String getWord(final String version, final String verseNumber, final String strong,
final String morph) {
try {
return this.interlinearProviders.get(version).getWord(isBlank(verseNumber) ? lastSeenOsisId : verseNumber, strong, morph);
} catch (Exception ex) {
//we catch and deal with all exceptions here:
LOGGER.error(ex.getMessage(), ex);
return "";
}
}
@Override
public boolean isDisabled(final String version) {
final InterlinearProvider interlinearProvider = this.interlinearProviders.get(StringUtils.trim(version));
if (interlinearProvider != null) {
return interlinearProvider.isDisabled();
}
return false;
}
/**
* @param lastSeenOsisId the last seen osis ID, mainly used for out of verse elements
*/
public void setLastSeenOsisId(String lastSeenOsisId) {
this.lastSeenOsisId = lastSeenOsisId;
}
}