package yuku.alkitabconverter.util; import yuku.alkitab.model.FootnoteEntry; import yuku.bintex.BintexWriter; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; public class FootnoteDb { public static interface FootnoteProcessor { void process(FootnoteEntry fe, int ari, int entryIndex); } final Map<Integer, List<FootnoteEntry>> map = new TreeMap<>(); public FootnoteDb() {} public FootnoteDb(final LinkedHashMap<Integer, FootnoteEntry> footnoteEntries) { // make sure it's sorted for (final Map.Entry<Integer, FootnoteEntry> entry : new TreeMap<>(footnoteEntries).entrySet()) { final int arif = entry.getKey(); final int ari = arif >> 8; List<FootnoteEntry> fes = map.get(ari); if (fes == null) { fes = new ArrayList<>(); map.put(ari, fes); } final FootnoteEntry fe = entry.getValue(); fes.add(fe); } } public LinkedHashMap<Integer, FootnoteEntry> toEntries() { final LinkedHashMap<Integer, FootnoteEntry> res = new LinkedHashMap<>(); processEach(new FootnoteProcessor() { @Override public void process(final FootnoteEntry fe, final int ari, final int entryIndex) { res.put(ari << 8 | (entryIndex + 1), fe); } }); return res; } /** * @return index of Footnote for this ari, starts from 0. */ public int addBegin(int ari) { List<FootnoteEntry> list = map.get(ari); if (list == null) { list = new ArrayList<>(); map.put(ari, list); } FootnoteEntry fe = new FootnoteEntry(); list.add(fe); return list.size() - 1; } /** must be after addBegin */ public void appendText(int ari, String text) { List<FootnoteEntry> list = map.get(ari); if (list == null) { throw new RuntimeException("Must be after addBegin (1)"); } final FootnoteEntry fe = list.get(list.size() - 1); if (fe.content != null) { fe.content += text; } else { fe.content = text; } } public void dump() { for (final Map.Entry<Integer, List<FootnoteEntry>> e: map.entrySet()) { final List<FootnoteEntry> fes = e.getValue(); for (int i = 0; i < fes.size(); i++) { FootnoteEntry fe = fes.get(i); System.out.printf("Footnote 0x%06x(%d): [%s]%n", e.getKey(), i + 1, fe.content); } } } public void processEach(FootnoteProcessor processor) { for (Map.Entry<Integer, List<FootnoteEntry>> e: map.entrySet()) { List<FootnoteEntry> fes = e.getValue(); for (int i = 0; i < fes.size(); i++) { FootnoteEntry fe = fes.get(i); processor.process(fe, e.getKey(), i); } } } public static void writeFootnoteEntriesTo(final LinkedHashMap<Integer, FootnoteEntry> footnoteEntries, final BintexWriter bw) throws IOException { // version bw.writeUint8(1); // entry_count bw.writeInt(footnoteEntries.size()); // int arif[entry_count] for (final Map.Entry<Integer, FootnoteEntry> entry: footnoteEntries.entrySet()) { bw.writeInt(entry.getKey()); } // try to calculate offset for each content. So we do the following ByteArrayOutputStream contents = new ByteArrayOutputStream(); BintexWriter contentsBw = new BintexWriter(contents); // int offsets[entry_count] for (final Map.Entry<Integer, FootnoteEntry> entry: footnoteEntries.entrySet()) { bw.writeInt(contentsBw.getPos()); contentsBw.writeValueString(entry.getValue().content); } // value<string> footnote_entry_contents[entry_count] bw.writeRaw(contents.toByteArray()); } }