package org.jabref.logic.citationstyle;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.jabref.logic.l10n.Localization;
import org.jabref.model.entry.BibEntry;
import de.undercouch.citeproc.CSL;
import de.undercouch.citeproc.bibtex.BibTeXConverter;
import de.undercouch.citeproc.csl.CSLItemData;
import de.undercouch.citeproc.output.Bibliography;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jbibtex.BibTeXEntry;
import org.jbibtex.DigitStringValue;
import org.jbibtex.Key;
import org.jbibtex.TokenMgrException;
/**
* WARNING: the citation is generated using JavaScript which may take some time, better call it from outside the main Thread
*/
public class CitationStyleGenerator {
private static final Log LOGGER = LogFactory.getLog(CitationStyleGenerator.class);
private static final BibTeXConverter BIBTEX_CONVERTER = new BibTeXConverter();
private CitationStyleGenerator() {
}
/**
* WARNING: the citation is generated using JavaScript which may take some time, better call it from outside the main Thread
* Generates a Citation based on the given entry and style
*/
protected static String generateCitation(BibEntry entry, CitationStyle style) {
return generateCitation(entry, style.getSource(), CitationStyleOutputFormat.HTML);
}
/**
* WARNING: the citation is generated using JavaScript which may take some time, better call it from outside the main Thread
* Generates a Citation based on the given entry and style
*/
protected static String generateCitation(BibEntry entry, String style) {
return generateCitation(entry, style, CitationStyleOutputFormat.HTML);
}
/**
* WARNING: the citation is generated using JavaScript which may take some time, better call it from outside the main Thread
* Generates a Citation based on the given entry, style, and output format
*/
protected static String generateCitation(BibEntry entry, String style, CitationStyleOutputFormat outputFormat) {
return generateCitations(Collections.singletonList(entry), style, outputFormat).get(0);
}
/**
* WARNING: the citation is generated using JavaScript which may take some time, better call it from outside the main Thread
* Generates the citation for multiple entries at once. This is useful when the Citation Style has an increasing number
*/
public static List<String> generateCitations(List<BibEntry> bibEntries, String style, CitationStyleOutputFormat outputFormat) {
try {
CSLItemData[] cslItemData = new CSLItemData[bibEntries.size()];
for (int i = 0; i < bibEntries.size(); i++) {
cslItemData[i] = bibEntryToCSLItemData(bibEntries.get(i));
}
Bibliography bibliography = CSL.makeAdhocBibliography(style, outputFormat.getFormat(), cslItemData);
return Arrays.asList(bibliography.getEntries());
} catch (IOException | ArrayIndexOutOfBoundsException e) {
LOGGER.error("Could not generate BibEntry citation", e);
return Collections.singletonList(Localization.lang("Cannot generate preview based on selected citation style."));
} catch (TokenMgrException e) {
LOGGER.error("Bad character inside BibEntry", e);
// sadly one cannot easily retrieve the bad char from the TokenMgrError
return Collections.singletonList(new StringBuilder()
.append(Localization.lang("Cannot generate preview based on selected citation style."))
.append(outputFormat.getLineSeparator())
.append(Localization.lang("Bad character inside entry"))
.append(outputFormat.getLineSeparator())
.append(e.getLocalizedMessage())
.toString());
}
}
/**
* Converts the {@link BibEntry} into {@link CSLItemData}.
*/
private static CSLItemData bibEntryToCSLItemData(BibEntry bibEntry) {
String citeKey = bibEntry.getCiteKeyOptional().orElse("");
BibTeXEntry bibTeXEntry = new BibTeXEntry(new Key(bibEntry.getType()), new Key(citeKey));
// Not every field is already generated into latex free fields
for (String key : bibEntry.getFieldMap().keySet()) {
Optional<String> latexFreeField = bibEntry.getLatexFreeField(key);
latexFreeField.ifPresent(value -> bibTeXEntry.addField(new Key(key), new DigitStringValue(value)));
}
return BIBTEX_CONVERTER.toItemData(bibTeXEntry);
}
}