package com.artfess.file.util;

import com.deepoove.poi.data.PictureRenderData;
import com.deepoove.poi.exception.RenderException;
import com.deepoove.poi.policy.AbstractRenderPolicy;
import com.deepoove.poi.render.RenderContext;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.xmlbeans.XmlException;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObject;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDrawing;

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 签章图片套打插件
 *
 * @company 阿特菲斯信息技术有限公司
 * @author zhangxw
 * @email zhangxw@jee-soft.cn
 * @date 2020年12月16日
 */
public class SignaturePictureRenderPolicy extends AbstractRenderPolicy<PictureRenderData> {

    @Override
    protected boolean validate(PictureRenderData data) {
        return (null != data && (null != data.getData() || null != data.getPath()));
    }

    @Override
    public void doRender(RenderContext<PictureRenderData> context) throws Exception {
        Helper.renderPicture(context.getRun(), context.getData());
    }

    @Override
    protected void afterRender(RenderContext<PictureRenderData> context) {
        clearPlaceholder(context, false);
    }

    @Override
    protected void reThrowException(RenderContext<PictureRenderData> context, Exception e) {
        logger.info("Render picture " + context.getEleTemplate() + " error: {}", e.getMessage());
        context.getRun().setText(context.getData().getAltMeta(), 0);
    }

    public static class Helper {
        public static final int EMU = 9525;

        public static void renderPicture(XWPFRun run, PictureRenderData picture) throws Exception {
            int suggestFileType = suggestFileType(picture.getPath());
            try (InputStream ins = null == picture.getData()
                    ? new FileInputStream(picture.getPath())
                    : new ByteArrayInputStream(picture.getData())) {
                run.addPicture(ins, suggestFileType, "Generated", picture.getWidth() * EMU,
                        picture.getHeight() * EMU);

                //此处之外代码为源码PictureRenderPolicy类代码，此处做特殊处理，签章打印的图片需置于文字下方
                String pictureText = run.getText(0);
                //解析签章套打占位符字段标示及下标
                String regEx="[`{#}]";
                Pattern p = Pattern.compile(regEx);
                Matcher m = p.matcher(pictureText);
                pictureText = m.replaceAll("").trim();
                String[] strArray = pictureText.split("_");
                int idx = Integer.valueOf(strArray[1]);
                //签章图片与文档左侧的距离，由于同一签章字段可能有多个签章图片，所以leftWidth需根据签章图片下标改变，防止图片重叠
                int leftWidth = 35;
                if(idx>0){
                	leftWidth += picture.getWidth()*idx;
                }
                CTDrawing drawing = run.getCTR().getDrawingArray(0);
                CTGraphicalObject graphicalobject = drawing.getInlineArray(0).getGraphic();

                //拿到新插入的图片替换添加CTAnchor 设置浮动属性 删除inline属性
                CTAnchor anchor = getAnchorWithGraphic(graphicalobject, pictureText,
                        Units.toEMU(picture.getWidth()), Units.toEMU(picture.getHeight()),//图片大小
                        Units.toEMU(leftWidth), Units.toEMU(-5), true);//相对当前段落位置 需要计算段落已有内容的左偏移
                drawing.setAnchorArray(new CTAnchor[]{anchor});//添加浮动属性
                drawing.removeInline(0);//删除行内属性
            }
        }

        public static int suggestFileType(String imgFile) {
            int format = 0;

            if (imgFile.endsWith(".emf")) format = XWPFDocument.PICTURE_TYPE_EMF;
            else if (imgFile.endsWith(".wmf")) format = XWPFDocument.PICTURE_TYPE_WMF;
            else if (imgFile.endsWith(".pict")) format = XWPFDocument.PICTURE_TYPE_PICT;
            else if (imgFile.endsWith(".jpeg") || imgFile.endsWith(".jpg"))
                format = XWPFDocument.PICTURE_TYPE_JPEG;
            else if (imgFile.endsWith(".png")) format = XWPFDocument.PICTURE_TYPE_PNG;
            else if (imgFile.endsWith(".dib")) format = XWPFDocument.PICTURE_TYPE_DIB;
            else if (imgFile.endsWith(".gif")) format = XWPFDocument.PICTURE_TYPE_GIF;
            else if (imgFile.endsWith(".tiff")) format = XWPFDocument.PICTURE_TYPE_TIFF;
            else if (imgFile.endsWith(".eps")) format = XWPFDocument.PICTURE_TYPE_EPS;
            else if (imgFile.endsWith(".bmp")) format = XWPFDocument.PICTURE_TYPE_BMP;
            else if (imgFile.endsWith(".wpg")) format = XWPFDocument.PICTURE_TYPE_WPG;
            else {
                throw new RenderException("Unsupported picture: " + imgFile
                        + ". Expected emf|wmf|pict|jpeg|png|dib|gif|tiff|eps|bmp|wpg");
            }
            return format;
        }

        /**
         * @param ctGraphicalObject 图片数据
         * @param deskFileName      图片描述
         * @param width             宽
         * @param height            高
         * @param leftOffset        水平偏移 left
         * @param topOffset         垂直偏移 top
         * @param behind            文字上方，文字下方
         * @return
         * @throws Exception
         */
        public static CTAnchor getAnchorWithGraphic(CTGraphicalObject ctGraphicalObject,
                                                    String deskFileName, int width, int height,
                                                    int leftOffset, int topOffset, boolean behind) {
            String anchorXML =
                    "<wp:anchor xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\" "
                            + "simplePos=\"0\" relativeHeight=\"0\" behindDoc=\"" + ((behind) ? 1 : 0) + "\" locked=\"0\" layoutInCell=\"1\" allowOverlap=\"1\">"
                            + "<wp:simplePos x=\"0\" y=\"0\"/>"
                            + "<wp:positionH relativeFrom=\"column\">"
                            + "<wp:posOffset>" + leftOffset + "</wp:posOffset>"
                            + "</wp:positionH>"
                            + "<wp:positionV relativeFrom=\"paragraph\">"
                            + "<wp:posOffset>" + topOffset + "</wp:posOffset>" +
                            "</wp:positionV>"
                            + "<wp:extent cx=\"" + width + "\" cy=\"" + height + "\"/>"
                            + "<wp:effectExtent l=\"0\" t=\"0\" r=\"0\" b=\"0\"/>"
                            + "<wp:wrapNone/>"
                            + "<wp:docPr id=\"1\" name=\"Drawing 0\" descr=\"" + deskFileName + "\"/><wp:cNvGraphicFramePr/>"
                            + "</wp:anchor>";

            CTDrawing drawing = null;
            try {
                drawing = CTDrawing.Factory.parse(anchorXML);
            } catch (XmlException e) {
                e.printStackTrace();
            }
            CTAnchor anchor = drawing.getAnchorArray(0);
            anchor.setGraphic(ctGraphicalObject);
            return anchor;
        }

    }
}
