// Path: cat-boot-report-pdf/src/main/java/cc/catalysts/boot/report/pdf/utils/PdfFontContext.java
// public class PdfFontContext implements AutoCloseable {
// 
//     private static ThreadLocal<PdfFontContext> pdfFontContexts = new ThreadLocal<>();
// 
//     /**
//      * Fonts currently loaded.
//      */
//     private Map<String, PdfFont> type0Fonts = new HashMap<>();
// 
//     /**
//      * Fallback fonts to use when a target font doesn't support a given glyph.
//      */
//     private List<PDFont> fallbackFonts = new ArrayList();
// 
//     private PdfFontEncodingExceptionHandler fontEncodingExceptionHandler = null;
// 
//     public static PdfFontContext create() {
//         final PdfFontContext oldContext = current();
//         if (oldContext != null) {
//             oldContext.close();
//         }
// 
//         PdfFontContext context = new PdfFontContext();
//         pdfFontContexts.set(context);
//         return context;
//     }
// 
//     /**
//      * Gets the currently set stylesheet from the context or null if none set
//      */
//     public static PdfFontContext current() {
//         return pdfFontContexts.get();
//     }
// 
//     public static PdfFontContext currentOrCreate() {
//         final PdfFontContext current = current();
//         if (current == null) {
//             return create();
//         }
//         return current;
//     }
// 
//     private PdfFontContext() {
//     }
// 
//     public PdfFont getFont(String fontName) {
//         return type0Fonts.get(fontName);
//     }
// 
//     public Collection<String> getAllFontNames() {
//         return type0Fonts.keySet();
//     }
// 
//     /**
//      * Finds a font (PDFont not PdfFont wrapper) by name or returns null if not found.
//      */
//     public PDFont getInternalFont(String name) {
//         return type0Fonts.values()
//                 .stream()
//                 .map(it -> it.getStyleByFontName(name))
//                 .filter(Objects::nonNull)
//                 .findFirst()
//                 .orElseGet(() -> PdfFont.getInternalFont(name));
//     }
// 
//     public PdfFont registerFont(PDType0Font font) {
//         String fontBaseName = font.getName();
//         String fontStyle = "regular";
// 
//         if (font.getDescendantFont() instanceof PDCIDFontType2) {
//             PDCIDFontType2 tmpFont = (PDCIDFontType2) font.getDescendantFont();
//             NamingTable ttfNamingTable = (NamingTable) tmpFont.getTrueTypeFont().getTableMap().get("name");
// 
//             fontBaseName = ttfNamingTable.getFontFamily();
//             fontStyle = ttfNamingTable.getFontSubFamily().toLowerCase();
//         }
// 
//         PdfFont f;
//         if (type0Fonts.containsKey(fontBaseName)) {
//             f = type0Fonts.get(fontBaseName);
//             f.addStyle(fontStyle, font);
//         } else {
//             f = new PdfFont(fontBaseName);
//             f.addStyle(fontStyle, font);
//             type0Fonts.put(fontBaseName, f);
//         }
// 
//         return f;
//     }
// 
//     /**
//      * Set global fallback fonts.
//      */
//     public void setFallbackFonts(List<PDFont> fallbacks) {
//         if (fallbacks.stream().anyMatch(it -> it == null)) {
//             throw new IllegalArgumentException("Must not pass null fonts.");
//         }
//         this.fallbackFonts.clear();
//         this.fallbackFonts.addAll(fallbacks);
//     }
// 
//     public List<PDFont> getPossibleFonts(PDFont font) {
//         List<PDFont> fonts = new ArrayList();
//         fonts.add(font);
//         fonts.addAll(fallbackFonts);
//         return fonts;
//     }
// 
//     /**
//      * Register a custom font encoding exception handler which gives the program a chance to either
//      * replace the problematic codepoints or simply log/throw custom exceptions.
//      */
//     public void registerFontEncodingExceptionHandler(PdfFontEncodingExceptionHandler handler) {
//         this.fontEncodingExceptionHandler = handler;
//     }
// 
//     public String handleFontEncodingException(String text, String codePointString, int start, int end) {
//         if (this.fontEncodingExceptionHandler != null) {
//             return this.fontEncodingExceptionHandler.handleFontEncodingException(text, codePointString, start, end);
//         }
//         throw new PdfBoxHelperException("Cannot encode '" + codePointString + "' in '" + text + "'.");
//     }
// 
// 
//     @Override
//     public void close() {
//         type0Fonts.clear();
// 
//         pdfFontContexts.remove();
//     }
// 
// }


import cc.catalysts.boot.report.pdf.utils.PdfFontContext;
import com.google.common.base.Objects;
import com.google.common.collect.Streams;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.slf4j.Logger;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import static org.slf4j.LoggerFactory.getLogger;
        SYMBOL = new PdfFont("Symbol");
        SYMBOL.addStyle("regular", PDType1Font.SYMBOL);
        type1Fonts.put("Helvetica", SYMBOL);

        ZAPF_DINGBATS = new PdfFont("ZapfDingbats");
        ZAPF_DINGBATS.addStyle("regular", PDType1Font.ZAPF_DINGBATS);
        type1Fonts.put("Zapf-Dingbats", ZAPF_DINGBATS);
    }

    public PdfFont(String basename) {
        this.basename = basename;
    }

    public void addStyle(String style, PDFont pf) {
        styles.put(style.toLowerCase(), pf);
    }

    /**
     * NOTE: this is kind of a hack, but since PdfBox doesn't expose the constructor
     * org.apache.pdfbox.pdmodel.font.PDType1Font#PDType1Font(java.lang.String), it is necessary.
     *
     * @param fontName One of the standard 14 font names defined by PostScript or of a font registered with registerFont(PDFont)
     * @return The appropriate PDFont
     */

    public static PdfFont getFont(String fontName) {
        if (type1Fonts.containsKey(fontName)) {
            return type1Fonts.get(fontName);
        }

// Path: cat-boot-report-pdf/src/main/java/cc/catalysts/boot/report/pdf/utils/PdfFontContext.java
// public class PdfFontContext implements AutoCloseable {
// 
//     private static ThreadLocal<PdfFontContext> pdfFontContexts = new ThreadLocal<>();
// 
//     /**
//      * Fonts currently loaded.
//      */
//     private Map<String, PdfFont> type0Fonts = new HashMap<>();
// 
//     /**
//      * Fallback fonts to use when a target font doesn't support a given glyph.
//      */
//     private List<PDFont> fallbackFonts = new ArrayList();
// 
//     private PdfFontEncodingExceptionHandler fontEncodingExceptionHandler = null;
// 
//     public static PdfFontContext create() {
//         final PdfFontContext oldContext = current();
//         if (oldContext != null) {
//             oldContext.close();
//         }
// 
//         PdfFontContext context = new PdfFontContext();
//         pdfFontContexts.set(context);
//         return context;
//     }
// 
//     /**
//      * Gets the currently set stylesheet from the context or null if none set
//      */
//     public static PdfFontContext current() {
//         return pdfFontContexts.get();
//     }
// 
//     public static PdfFontContext currentOrCreate() {
//         final PdfFontContext current = current();
//         if (current == null) {
//             return create();
//         }
//         return current;
//     }
// 
//     private PdfFontContext() {
//     }
// 
//     public PdfFont getFont(String fontName) {
//         return type0Fonts.get(fontName);
//     }
// 
//     public Collection<String> getAllFontNames() {
//         return type0Fonts.keySet();
//     }
// 
//     /**
//      * Finds a font (PDFont not PdfFont wrapper) by name or returns null if not found.
//      */
//     public PDFont getInternalFont(String name) {
//         return type0Fonts.values()
//                 .stream()
//                 .map(it -> it.getStyleByFontName(name))
//                 .filter(Objects::nonNull)
//                 .findFirst()
//                 .orElseGet(() -> PdfFont.getInternalFont(name));
//     }
// 
//     public PdfFont registerFont(PDType0Font font) {
//         String fontBaseName = font.getName();
//         String fontStyle = "regular";
// 
//         if (font.getDescendantFont() instanceof PDCIDFontType2) {
//             PDCIDFontType2 tmpFont = (PDCIDFontType2) font.getDescendantFont();
//             NamingTable ttfNamingTable = (NamingTable) tmpFont.getTrueTypeFont().getTableMap().get("name");
// 
//             fontBaseName = ttfNamingTable.getFontFamily();
//             fontStyle = ttfNamingTable.getFontSubFamily().toLowerCase();
//         }
// 
//         PdfFont f;
//         if (type0Fonts.containsKey(fontBaseName)) {
//             f = type0Fonts.get(fontBaseName);
//             f.addStyle(fontStyle, font);
//         } else {
//             f = new PdfFont(fontBaseName);
//             f.addStyle(fontStyle, font);
//             type0Fonts.put(fontBaseName, f);
//         }
// 
//         return f;
//     }
// 
//     /**
//      * Set global fallback fonts.
//      */
//     public void setFallbackFonts(List<PDFont> fallbacks) {
//         if (fallbacks.stream().anyMatch(it -> it == null)) {
//             throw new IllegalArgumentException("Must not pass null fonts.");
//         }
//         this.fallbackFonts.clear();
//         this.fallbackFonts.addAll(fallbacks);
//     }
// 
//     public List<PDFont> getPossibleFonts(PDFont font) {
//         List<PDFont> fonts = new ArrayList();
//         fonts.add(font);
//         fonts.addAll(fallbackFonts);
//         return fonts;
//     }
// 
//     /**
//      * Register a custom font encoding exception handler which gives the program a chance to either
//      * replace the problematic codepoints or simply log/throw custom exceptions.
//      */
//     public void registerFontEncodingExceptionHandler(PdfFontEncodingExceptionHandler handler) {
//         this.fontEncodingExceptionHandler = handler;
//     }
// 
//     public String handleFontEncodingException(String text, String codePointString, int start, int end) {
//         if (this.fontEncodingExceptionHandler != null) {
//             return this.fontEncodingExceptionHandler.handleFontEncodingException(text, codePointString, start, end);
//         }
//         throw new PdfBoxHelperException("Cannot encode '" + codePointString + "' in '" + text + "'.");
//     }
// 
// 
//     @Override
//     public void close() {
//         type0Fonts.clear();
// 
//         pdfFontContexts.remove();
//     }
// 
// }


// Path: cat-boot-report-pdf/src/main/java/cc/catalysts/boot/report/pdf/config/PdfFont.java
import cc.catalysts.boot.report.pdf.utils.PdfFontContext;
import com.google.common.base.Objects;
import com.google.common.collect.Streams;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.slf4j.Logger;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import static org.slf4j.LoggerFactory.getLogger;

        SYMBOL = new PdfFont("Symbol");
        SYMBOL.addStyle("regular", PDType1Font.SYMBOL);
        type1Fonts.put("Helvetica", SYMBOL);

        ZAPF_DINGBATS = new PdfFont("ZapfDingbats");
        ZAPF_DINGBATS.addStyle("regular", PDType1Font.ZAPF_DINGBATS);
        type1Fonts.put("Zapf-Dingbats", ZAPF_DINGBATS);
    }

    public PdfFont(String basename) {
        this.basename = basename;
    }

    public void addStyle(String style, PDFont pf) {
        styles.put(style.toLowerCase(), pf);
    }

    /**
     * NOTE: this is kind of a hack, but since PdfBox doesn't expose the constructor
     * org.apache.pdfbox.pdmodel.font.PDType1Font#PDType1Font(java.lang.String), it is necessary.
     *
     * @param fontName One of the standard 14 font names defined by PostScript or of a font registered with registerFont(PDFont)
     * @return The appropriate PDFont
     */

    public static PdfFont getFont(String fontName) {
        if (type1Fonts.containsKey(fontName)) {
            return type1Fonts.get(fontName);
        }

        final PdfFontContext currentContext = PdfFontContext.current();