class FontUtils {

    public static List<String> wrapLines(String rawLabel, PDFont font, float fontSize, double maxWidth,
            PDDocument document) throws TaskIOException {
        List<String> lines = new ArrayList<>();

        String label = org.sejda.commons.util.StringUtils.normalizeWhitespace(rawLabel);

        StringBuilder currentString = new StringBuilder();
        double currentWidth = 0;

        List<TextWithFont> resolvedStringsToFonts = FontUtils.resolveFonts(label, font, document);

        for (TextWithFont stringAndFont : resolvedStringsToFonts) {
            try {

                PDFont resolvedFont = stringAndFont.getFont();
                String resolvedLabel = stringAndFont.getText();

                if (isNull(resolvedFont)) {
                    throw new UnsupportedTextException(
                            "Unable to find suitable font for string \"" + resolvedLabel + "\"",
                            resolvedLabel);
                }

                String[] words = visualToLogical(resolvedLabel).split("(?<=\\b)");
                for (String word : words) {
                    double textWidth = getSimpleStringWidth(word, resolvedFont, fontSize);

                    if (textWidth > maxWidth || word.length() > 10) {
                        // this is a giant word that has no breaks and exceeds max width

                        // check for each char if it can be added to current line, wrap on new line if not
                        Iterator<Integer> codePointIterator = word.codePoints().iterator();
                        while (codePointIterator.hasNext()) {
                            int codePoint = codePointIterator.next();

                            String ch = new String(Character.toChars(codePoint));
                            double chWidth = getSimpleStringWidth(ch, resolvedFont, fontSize);
                            if (currentWidth + chWidth > maxWidth) {
                                currentString.append("-");
                                lines.add(currentString.toString().trim());
                                currentString = new StringBuilder();
                                currentWidth = 0;
                            }

                            currentWidth += chWidth;
                            currentString.append(ch);
                        }
                    } else {
                        // regular scenario: check if word can be added to current line, wrap on new line if not
                        if (currentWidth + textWidth > maxWidth) {
                            lines.add(currentString.toString().trim());
                            currentString = new StringBuilder();
                            currentWidth = 0;
                        }

                        currentWidth += textWidth;
                        currentString.append(word);
                    }
                }

            } catch (IOException e) {
                throw new TaskIOException(e);
            }
        }

        if (!currentString.toString().isEmpty()) {
            lines.add(currentString.toString().trim());
        }

        return lines;
    }

    private  FontUtils();

}