package com.tyndalehouse.step.tools.conversion;
import com.tyndalehouse.step.core.utils.StringUtils;
import org.crosswire.jsword.passage.NoSuchKeyException;
import org.crosswire.jsword.passage.Passage;
import org.crosswire.jsword.passage.PassageKeyFactory;
import org.crosswire.jsword.versification.BibleBook;
import org.crosswire.jsword.versification.system.Versifications;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
/**
* @author chrisburrell
*/
public class OsisConversionUtils {
private static final String ERROR = "<!-- ERROR -->";
private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(OsisConversionUtils.class);
private static Queue<Object> title = new LinkedBlockingQueue<>();
private static boolean inChapter = false;
private static boolean inVerse = false;
private static int currentPsalm = -1;
private static int currentChapter;
private static String acrosticTitle;
private static String acrosticLetter;
private static boolean inRealChapter = false;
private static String currentBook;
private static String currentChapterId;
private static String currentVerseId;
private OsisConversionUtils() {
//no implementation
}
public static String toTitleCase(String title) {
return StringUtils.toTitleCase(title, true);
}
public static String convertBookToOsis(final String bookAbbreviation) {
switch (bookAbbreviation) {
case "GEN":
return BibleBook.GEN.getOSIS();
case "EXO":
return BibleBook.EXOD.getOSIS();
case "LEV":
return BibleBook.LEV.getOSIS();
case "NUM":
return BibleBook.NUM.getOSIS();
case "DEU":
return BibleBook.DEUT.getOSIS();
case "JOS":
return BibleBook.JOSH.getOSIS();
case "JDG":
return BibleBook.JUDG.getOSIS();
case "RUT":
return BibleBook.RUTH.getOSIS();
case "1SA":
return BibleBook.SAM1.getOSIS();
case "2SA":
return BibleBook.SAM2.getOSIS();
case "1KI":
return BibleBook.KGS1.getOSIS();
case "2KI":
return BibleBook.KGS2.getOSIS();
case "1CH":
return BibleBook.CHR1.getOSIS();
case "2CH":
return BibleBook.CHR2.getOSIS();
case "EZR":
return BibleBook.EZRA.getOSIS();
case "NEH":
return BibleBook.NEH.getOSIS();
case "EST":
return BibleBook.ESTH.getOSIS();
case "JOB":
return BibleBook.JOB.getOSIS();
case "PSA":
return BibleBook.PS.getOSIS();
case "PRO":
return BibleBook.PROV.getOSIS();
case "ECC":
return BibleBook.ECCL.getOSIS();
case "SNG":
return BibleBook.SONG.getOSIS();
case "ISA":
return BibleBook.ISA.getOSIS();
case "JER":
return BibleBook.JER.getOSIS();
case "LAM":
return BibleBook.LAM.getOSIS();
case "EZK":
return BibleBook.EZEK.getOSIS();
case "DAN":
return BibleBook.DAN.getOSIS();
case "HOS":
return BibleBook.HOS.getOSIS();
case "JOL":
return BibleBook.JOEL.getOSIS();
case "AMO":
return BibleBook.AMOS.getOSIS();
case "OBA":
return BibleBook.OBAD.getOSIS();
case "JON":
return BibleBook.JONAH.getOSIS();
case "MIC":
return BibleBook.MIC.getOSIS();
case "NAM":
return BibleBook.NAH.getOSIS();
case "HAB":
return BibleBook.HAB.getOSIS();
case "ZEP":
return BibleBook.ZEPH.getOSIS();
case "HAG":
return BibleBook.HAG.getOSIS();
case "ZEC":
return BibleBook.ZECH.getOSIS();
case "MAL":
return BibleBook.MAL.getOSIS();
case "MAT":
return BibleBook.MATT.getOSIS();
case "MRK":
return BibleBook.MARK.getOSIS();
case "LUK":
return BibleBook.LUKE.getOSIS();
case "JHN":
return BibleBook.JOHN.getOSIS();
case "ACT":
return BibleBook.ACTS.getOSIS();
case "ROM":
return BibleBook.ROM.getOSIS();
case "1CO":
return BibleBook.COR1.getOSIS();
case "2CO":
return BibleBook.COR2.getOSIS();
case "GAL":
return BibleBook.GAL.getOSIS();
case "EPH":
return BibleBook.EPH.getOSIS();
case "PHP":
return BibleBook.PHIL.getOSIS();
case "COL":
return BibleBook.COL.getOSIS();
case "1TH":
return BibleBook.THESS1.getOSIS();
case "2TH":
return BibleBook.THESS2.getOSIS();
case "1TI":
return BibleBook.TIM1.getOSIS();
case "2TI":
return BibleBook.TIM2.getOSIS();
case "TIT":
return BibleBook.TITUS.getOSIS();
case "PHM":
return BibleBook.PHLM.getOSIS();
case "HEB":
return BibleBook.HEB.getOSIS();
case "JAS":
return BibleBook.JAS.getOSIS();
case "1PE":
return BibleBook.PET1.getOSIS();
case "2PE":
return BibleBook.PET2.getOSIS();
case "1JN":
return BibleBook.JOHN1.getOSIS();
case "2JN":
return BibleBook.JOHN2.getOSIS();
case "3JN":
return BibleBook.JOHN3.getOSIS();
case "JUD":
return BibleBook.JUDE.getOSIS();
case "REV":
return BibleBook.REV.getOSIS();
}
throw new ConversionException("Unable to convert book: " + bookAbbreviation);
}
public static String openUSXChapter(final String chapterID) {
markChapterStart(Integer.parseInt(chapterID));
//USX chapters only contain numbers, so append book name and return
currentChapterId = convertBookToOsis(currentBook) + "." + chapterID;
return currentChapterId;
}
public static String closeUSXChapter() {
markChapterEnd();
return currentChapterId;
}
public static String convertChapterToOsis(final String chapterID) {
//assuming all chapters are roughly the same, remove the first part
return stripIdAndConvertBook(chapterID);
}
public static String openUSXVerse(final String verseNumber) {
if(verseNumber.indexOf('-') != -1) {
//we have a range
final String[] split = StringUtils.split(verseNumber, "-");
if(split.length != 2) {
throw new RuntimeException("Unable to parse range of verses");
}
int start = Integer.parseInt(split[0]);
int end = Integer.parseInt(split[1]);
StringBuilder ref = new StringBuilder();
for(int ii = start; ii <= end; ii++) {
ref.append(currentBook);
ref.append('.');
ref.append(currentChapter);
ref.append('.');
ref.append(ii);
if(ii != end) {
ref.append('_');
}
}
currentVerseId = ref.toString();
} else {
currentVerseId = String.format("%s.%d.%s", currentBook, currentChapter, verseNumber);
}
inVerse = true;
return currentVerseId;
}
public static String closeUSXVerse() {
inVerse = false;
return currentVerseId;
}
public static boolean isInVerse() {
return inVerse;
}
public static String convertVerseToOsis(final String s) {
return stripIdAndConvertBook(s);
}
public static String convertNoteScopeToOsis(final String s) {
if (s == null || s.length() == 0) {
return s;
}
int hasRef = s.indexOf("-");
if (hasRef != -1) {
//convert each part and form a ref
String left = s.substring(0, hasRef);
String right = s.substring(hasRef + 1);
return getOsisFromBiblicaSingleRef(left) + '-' + getOsisFromBiblicaSingleRef(right);
} else {
return getOsisFromBiblicaSingleRef(s);
}
}
public static String convertNoteType(final String noteType) {
switch (noteType) {
case "allusion":
return "allusion";
case "alternative":
return "alternative";
case "background":
return "background";
case "citation":
return "citation";
case "crossReference":
return "crossReference";
case "exegesis":
return "exegesis";
case "explanation":
return "explanation";
case "study":
return "study";
case "translation":
return "translation";
case "variant":
return "variant";
case "literal":
return "background";
case "general":
return "background";
case "versification":
return "background";
case "typeversification":
return "background";
}
throw new ConversionException("Unable to convert note type" + noteType);
}
private static String stripIdAndConvertBook(final String chapterID) {
//strip the ID from the front
final String biblicaChapter = chapterID.substring(chapterID.indexOf('.') + 1);
return getOsisFromBiblicaSingleRef(biblicaChapter);
}
private static String getOsisFromBiblicaSingleRef(final String biblicaChapter) {
final int startOfChapterProper = biblicaChapter.indexOf('.');
final String bookName = biblicaChapter.substring(0, startOfChapterProper);
final String leftOver = biblicaChapter.substring(biblicaChapter.indexOf('.'));
return convertBookToOsis(bookName) + leftOver;
}
public static void markBookStart(final String code) {
currentBook = code;
}
public static void markChapterStart(int chapterNumber) {
inChapter = true;
currentChapter = chapterNumber;
inRealChapter = true;
}
public static void markPsalmStart(int psalmNumber) {
inChapter = true;
currentPsalm = psalmNumber;
}
public static boolean isCurrentChapterAlignedToPsalm() {
return currentChapter == currentPsalm;
}
public static void markChapterEnd() {
inChapter = false;
inRealChapter = false;
currentChapter = -1;
}
public static boolean isInChapter() {
return inChapter;
}
public static boolean isInRealChapter() {
return inRealChapter;
}
public static void pushAcrosticTitle(final String title, final String letter) {
acrosticTitle = title;
acrosticLetter = letter;
}
public static String pullAcrosticTitle() {
try {
if (acrosticTitle != null) {
return acrosticTitle;
}
} finally {
acrosticTitle = null;
}
return "";
}
public static String pullAcrosticTitleLetter() {
try {
if (acrosticLetter != null) {
return acrosticLetter;
}
} finally {
acrosticLetter = null;
}
return null;
}
public static String langRefToRef(String v11n, String langRef) {
try {
final Passage key = PassageKeyFactory.instance().getKey(Versifications.instance().getVersification(v11n), langRef);
return key.getOsisRef();
} catch (NoSuchKeyException e) {
// e.printStackTrace(); silently ignore, because there can be all sorts of things in there...
return "##error##";
}
}
public static void pushTitle(Object o) throws ParserConfigurationException, TransformerException {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.newDocument();
doc.appendChild(((Node) o).cloneNode(true));
StringWriter sw = new StringWriter();
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.transform(new DOMSource(doc), new StreamResult(sw));
title.add(sw.toString());
}
public static String pullTitle() throws ParserConfigurationException {
if (title.size() == 0) {
return "";
}
return (String) title.poll();
}
}