AltContentRecorder.java

package pro.verron.asciidoc.docx;

import org.docx4j.TextUtils;
import org.docx4j.com.microsoft.schemas.office.word.x2010.wordprocessingShape.CTTextboxInfo;
import org.docx4j.com.microsoft.schemas.office.word.x2010.wordprocessingShape.CTWordprocessingShape;
import org.docx4j.dml.Graphic;
import org.docx4j.dml.wordprocessingDrawing.Anchor;
import org.docx4j.mce.AlternateContent;
import org.docx4j.mce.AlternateContent.Choice;
import org.docx4j.mce.AlternateContent.Fallback;
import org.docx4j.vml.CTRoundRect;
import org.docx4j.vml.CTShadow;
import org.docx4j.vml.CTTextbox;
import org.docx4j.wml.Drawing;
import org.docx4j.wml.P;
import org.docx4j.wml.Pict;
import pro.verron.asciidoc.core.*;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import static org.docx4j.XmlUtils.unwrap;

public class AltContentRecorder {
    List<AlternateContent> alternateContents = new ArrayList<>();

    public int add(AlternateContent ac) {
        alternateContents.add(ac);
        return alternateContents.size();
    }

    public Collection<OpenBlock> all() {
        List<OpenBlock> list = new ArrayList<>();
        for (int i = 0; i < alternateContents.size(); i++) {
            AlternateContent index = alternateContents.get(i);
            OpenBlock block = asBlock(i + 1, index);
            list.add(block);
        }
        return list;

    }

    private OpenBlock asBlock(int index, AlternateContent alts) {
        var header = List.of("alternateContent", "anchor=" + index);

        var content = new ArrayList<Block>();
        for (Choice c : alts.getChoice()) content.add(asParagraph(c));
        content.add(asParagraph(alts.getFallback()));

        return new OpenBlock(header, content);
    }

    private Paragraph asParagraph(Object o) {
        var obj = unwrap(o);
        return new Paragraph(switch (obj) {
            case Fallback fb -> asContent(fb);
            case Choice c -> asContent(c);
            case Object objobj -> throw new IllegalArgumentException(
                    "Unsupported object: " + objobj);
        });
    }

    private List<Inline> asContent(Fallback fb) {
        var inlines = new ArrayList<Inline>();
        inlines.add(new Text("fallback\n"));
        inlines.addAll(asContent(fb.getAny(), 1));
        return inlines;
    }

    private List<Inline> asContent(Choice c) {
        var inlines = new ArrayList<Inline>();
        inlines.add(new Text("choice " + c.getRequires() + "\n"));
        inlines.addAll(asContent(c.getAny(), 1));
        return inlines;
    }

    private List<Inline> asContent(List<?> list, int depth) {
        var inlines = new ArrayList<Inline>();
        for (var object : list) {
            inlines.addAll(asContent(object, depth));
        }
        return inlines;
    }

    private List<Inline> asContent(Drawing drawing, int depth) {
        var inlines = new ArrayList<Inline>();
        for (var i = 0; i < depth; i++) {
            inlines.add(new Tab());
        }
        inlines.add(new Text("drawing\n"));
        inlines.addAll(asContent(drawing.getAnchorOrInline(), depth + 1));
        return inlines;
    }

    private List<Inline> asContent(Anchor anchor, int depth) {
        var inlines = new ArrayList<Inline>();
        for (var i = 0; i < depth; i++) {
            inlines.add(new Tab());
        }
        inlines.add(new Text("anchor\n"));
        inlines.addAll(asContent(anchor.getGraphic(), depth + 1));
        return inlines;
    }

    private List<Inline> asContent(CTWordprocessingShape shape, int depth) {
        var inlines = new ArrayList<Inline>();
        for (var i = 0; i < depth; i++) {
            inlines.add(new Tab());
        }
        inlines.add(new Text("wordprocessingshape\n"));
        inlines.addAll(asContent(shape.getTxbx(), depth + 1));
        return inlines;
    }

    private List<Inline> asContent(CTTextboxInfo tbi, int depth) {
        var inlines = new ArrayList<Inline>();
        for (var i = 0; i < depth; i++) {
            inlines.add(new Tab());
        }
        inlines.add(new Text("textbox\n"));
        inlines.addAll(asContent(tbi.getTxbxContent()
                                    .getContent(), depth + 1));
        return inlines;
    }

    private List<Inline> asContent(CTTextbox tb, int depth) {
        var inlines = new ArrayList<Inline>();
        for (var i = 0; i < depth; i++) {
            inlines.add(new Tab());
        }
        inlines.add(new Text("textbox\n"));
        inlines.addAll(asContent(tb.getTxbxContent()
                                   .getContent(), depth + 1));
        return inlines;
    }

    private List<Inline> asContent(P p, int depth) {
        var inlines = new ArrayList<Inline>();
        for (var i = 0; i < depth; i++) {
            inlines.add(new Tab());
        }
        inlines.add(new Text(TextUtils.getText(p)));
        return inlines;
    }

    private List<Inline> asContent(Pict pict, int depth) {
        var inlines = new ArrayList<Inline>();
        for (var i = 0; i < depth; i++) {
            inlines.add(new Tab());
        }
        inlines.add(new Text("pict\n"));
        inlines.addAll(asContent(pict.getAnyAndAny(), depth + 1));
        return inlines;
    }

    private List<Inline> asContent(CTRoundRect rr, int depth) {
        var inlines = new ArrayList<Inline>();
        for (var i = 0; i < depth; i++) {
            inlines.add(new Tab());
        }
        inlines.add(new Text("roundrect\n"));
        inlines.addAll(asContent(rr.getEGShapeElements(), depth + 1));
        return inlines;
    }

    private List<Inline> asContent(CTShadow ignored, int depth) {
        var inlines = new ArrayList<Inline>();
        for (var i = 0; i < depth; i++) {
            inlines.add(new Tab());
        }
        inlines.add(new Text("shadow\n"));
        return inlines;
    }

    private List<Inline> asContent(Graphic graphic, int depth) {
        var inlines = new ArrayList<Inline>();
        for (var i = 0; i < depth; i++) {
            inlines.add(new Tab());
        }
        var graphicData = graphic.getGraphicData();
        inlines.add(new Text("graphic\n"));
        inlines.addAll(asContent(graphicData.getAny(), depth + 1));
        return inlines;
    }

    private List<Inline> asContent(Object obj, int depth) {
        var o = unwrap(obj);
        var inlines = new ArrayList<Inline>();
        inlines.addAll(switch (o) {
            case Anchor a -> asContent(a, depth);
            case P p -> asContent(p, depth);
            case CTTextboxInfo tbi -> asContent(tbi, depth);
            case CTWordprocessingShape ws -> asContent(ws, depth);
            case CTShadow s -> asContent(s, depth);
            case CTTextbox tb -> asContent(tb, depth);
            case Pict p -> asContent(p, depth);
            case Graphic g -> asContent(g, depth);
            case Drawing d -> asContent(d, depth);
            case CTRoundRect rr -> asContent(rr, depth);
            case Object oo -> throw new RuntimeException(oo.getClass()
                                                           .getName());
        });
        return inlines;
    }
}