package com.liang.common.utils;

import com.liang.entity.*;
import com.spire.doc.FileFormat;
import org.apache.poi.xwpf.converter.pdf.PdfConverter;
import org.apache.poi.xwpf.converter.pdf.PdfOptions;
import org.apache.poi.xwpf.usermodel.XWPFDocument;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.Version;
import org.apache.poi.openxml4j.util.ZipSecureFile;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlOptions;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Author
 * @Description 文件合并 只支持.docx
 * @Date 2023/6/17 16:30
 * @Version 1.0
 */
public class WordUtils {

    /**
     * 把多个docx文件合并成一个
     */
    public static boolean appendDocx(String outfile, List<String> targetFile) {
        String result = outfile;
        if (targetFile.size() == 0)
            return false;

        com.spire.doc.Document mergerDoc = new com.spire.doc.Document(targetFile.get(0));
        targetFile.remove(0);

        for (String fileName : targetFile) {
            mergerDoc.insertTextFromFile(fileName, FileFormat.Docx.Docx_2010);
        }

        mergerDoc.saveToFile(outfile, FileFormat.Docx_2010);
        return true;
    }

    public static boolean docxConvertPdf(String source, String pdfDestination) {
        try {
            InputStream inputStream = new FileInputStream(source);
            XWPFDocument document = new XWPFDocument(inputStream);
            OutputStream outputStream = new FileOutputStream(pdfDestination);
            PdfOptions options = PdfOptions.create();
            PdfConverter.getInstance().convert(document, outputStream, options);
            inputStream.close();
            outputStream.close();
            return true;
        } catch (IOException ex) {
            return false;
        }
    }

    public static void appendBody(XWPFDocument src, XWPFDocument append) throws Exception {
        CTBody src1Body = src.getDocument().getBody();
        CTBody src2Body = append.getDocument().getBody();

        List<XWPFPictureData> allPictures = append.getAllPictures();
        // 记录图片合并前及合并后的ID
        Map<String, String> map = new HashMap<>();
        for (XWPFPictureData picture : allPictures) {
            String before = append.getRelationId(picture);
            //将原文档中的图片加入到目标文档中
            String after = src.addPictureData(picture.getData(), Document.PICTURE_TYPE_PNG);
            map.put(before, after);
        }
        //这个代码主要解决合并word报错，解析抛出压缩炸弹
        ZipSecureFile.setMinInflateRatio(-1.0d);
        appendBody(src1Body, src2Body, map);

    }

    private static void appendBody(CTBody src, CTBody append, Map<String, String> map) throws Exception {
        XmlOptions optionsOuter = new XmlOptions();
        optionsOuter.setSaveOuter();
        String appendString = append.xmlText(optionsOuter);

        String srcString = src.xmlText();
        String prefix = srcString.substring(0, srcString.indexOf(">") + 1);
        String mainPart = srcString.substring(srcString.indexOf(">") + 1, srcString.lastIndexOf("<"));
        String sufix = srcString.substring(srcString.lastIndexOf("<"));
        String addPart = appendString.substring(appendString.indexOf(">") + 1, appendString.lastIndexOf("<"));
        //下面这部分可以去掉，我加上的原因是合并的时候，有时候出现打不开的情况，对照document.xml将某些标签去掉就可以正常打开了
        addPart = addPart.replaceAll("w14:paraId=\"[A-Za-z0-9]{1,10}\"", "");
        addPart = addPart.replaceAll("w14:textId=\"[A-Za-z0-9]{1,10}\"", "");
        addPart = addPart.replaceAll("w:rsidP=\"[A-Za-z0-9]{1,10}\"", "");
        addPart = addPart.replaceAll("w:rsidRPr=\"[A-Za-z0-9]{1,10}\"", "");
        addPart = addPart.replace("<w:headerReference r:id=\"rId8\" w:type=\"default\"/>", "");
        addPart = addPart.replace("<w:footerReference r:id=\"rId9\" w:type=\"default\"/>", "");
        addPart = addPart.replace("xsi:nil=\"true\"", "");

        if (map != null && !map.isEmpty()) {
            //对xml字符串中图片ID进行替换
            for (Map.Entry<String, String> set : map.entrySet()) {
                addPart = addPart.replace(set.getKey(), set.getValue());
            }
        }
        //将两个文档的xml内容进行拼接
        CTBody makeBody = CTBody.Factory.parse(prefix + mainPart + addPart + sufix);

        src.set(makeBody);
    }

    public static void setResponseHeader(HttpServletResponse response, String fileName) {
        try {
            try {
                fileName = new String(fileName.getBytes(), "ISO8859-1");
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            response.setContentType("application/octet-stream;charset=ISO8859-1");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            response.addHeader("Pargam", "no-cache");
            response.addHeader("Cache-Control", "no-cache");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 从输入流中获取字节数组
     *
     * @param inputStream
     * @return
     * @throws IOException
     */
    public static byte[] readInputStream(InputStream inputStream) throws IOException {
        byte[] buffer = new byte[1024];
        int len = 0;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        while ((len = inputStream.read(buffer)) != -1) {
            bos.write(buffer, 0, len);
        }
        bos.close();
        return bos.toByteArray();
    }

    public static String genWord(String fileName, String templatePath, String ftlName, Map<String, Object> mapData) throws IOException {
        String result = "";
        Configuration cfg = new Configuration(new Version("2.3.0"));
        cfg.setDirectoryForTemplateLoading(new File(templatePath));
        File docFile = new File(fileName);
        if (docFile.exists()) {
            docFile.delete();
        }
        Writer out = null;
        Template template = null;
        try {
            template = cfg.getTemplate(ftlName, "UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(docFile), StandardCharsets.UTF_8));
            template.process(mapData, out);
            out.close();
            result = fileName;

        } catch (IOException | TemplateException e) {
            e.printStackTrace();
        }
        return result;
    }

    public static Map<String, Object> getWord(StaFeasibilityreport report) {
        Map<String, Object> data = new HashMap<String, Object>();
        DateFormat dateFormat = new SimpleDateFormat("yyyy年MM月");

        ProjectToWordEntity word = new ProjectToWordEntity();
        if (report.getMc() == null)
            word.setMc("");
        else
            word.setMc(report.getMc());
        data.put("mc", word.getMc());
        if (report.getSqdwName() == null)
            word.setSqdwName("");
        else
            word.setSqdwName(report.getSqdwName());
        data.put("sqdwName", word.getSqdwName());

        String qs = "";
        String wc = "";

        if (report.getQs() == null)
            qs = "";
        else
            qs = dateFormat.format(report.getQs());
        if (report.getWc() == null)
            wc = "";
        else
            wc = dateFormat.format(report.getWc());
        word.setQzsj(qs + "至" + wc);
        data.put("qzsj", word.getQzsj());

        if (report.getXmfzrName() == null)
            word.setXmfzrName("");
        else
            word.setXmfzrName(report.getXmfzrName());
        data.put("xmfzrName", word.getXmfzrName());

        if (report.getTxdd() == null)
            word.setTxdd("");
        else
            word.setTxdd(report.getTxdd());
        data.put("txdd", word.getTxdd());

        if (report.getYzbm() == null)
            word.setYzbm("");
        else
            word.setYzbm(report.getYzbm());
        data.put("yzbm", word.getYzbm());

        if (report.getDh() == null)
            word.setDh("");
        else
            word.setDh(report.getDh());
        data.put("dh", word.getDh());

        if (report.getCz() == null)
            word.setCz("");
        else
            word.setCz(report.getCz());
        data.put("cz", word.getCz());
        String sqrq = "";
        if (report.getSqrq() == null)
            sqrq = "";
        else
            sqrq = dateFormat.format(report.getSqrq());

        data.put("sqrq", sqrq);
        return data;
    }

    public static String XMLOrHTMLEnc(String s) {
        // 替换&
        s = s.replace("&", "&amp;");
        // 替换<
        s = s.replace("<", "&lt;");
        // 替换>
        s = s.replace(">", "&gt;");
//        // 替换单引号'
//        s = s.replace("'", "&apos;");
//        // 替换双引号"
//        s = s.replace("\"", "&quot;");
        s = s.replace("\r\n", "<w:br/>");
        s = s.replace("\n", "<w:br/>");
        s = s.replace(" ", "&#160;");
        s = s.replace("\t", "&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;");
        return s;
    }

    /**
     * 字符串中剔除控制符
     */
    public static String rebuildStrMinusCTL(String str) {
        StringBuilder buff = new StringBuilder();
        char[] arr = str.toCharArray();//待处理字符串字符数组
        char[] ctl_arr = {(char) 0, (char) 1, (char) 2, (char) 3, (char) 4, (char) 5, (char) 6, (char) 7, (char) 8, (char) 9, (char) 10, (char) 11, (char) 12,
                (char) 13, (char) 14, (char) 15, (char) 16, (char) 17, (char) 18, (char) 19, (char) 20, (char) 21, (char) 22, (char) 23, (char) 24, (char) 25,
                (char) 26, (char) 27, (char) 28, (char) 29, (char) 30, (char) 31, (char) 127,}; //特殊字符数组
        List<Character> ls = new ArrayList<Character>();
        for (int i = 0; i < arr.length; i++) {
            char tmp = arr[i];
            //剔除特殊字符
            for (int j = 0; j < ctl_arr.length; j++) {
                if (j + 1 == ctl_arr.length) {
                    ls.add(tmp);
                } else if (tmp == ctl_arr[j]) {
                    ls.add('~');
                    break;
                }
            }
        }
        //重新拼接字符串
        for (int i = 0; i < ls.size(); i++) {
            buff.append((Character) ls.get(i));
        }
        return buff.toString();
    }
}


