package com.pqs9000.util;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import cn.hutool.core.collection.CollUtil;
import com.njcn.utils.ClearPathUtil;
import org.apache.poi.xwpf.usermodel.*;

import com.njcn.utils.PubUtils;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFonts;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class WordUtil2 {
    // 日志记录
    private static final Logger logger = LoggerFactory.getLogger(WordUtil2.class);

    public void getWord(String path, Map<String, Object> params, String fileName, HttpServletResponse response, HttpSession session)
            throws Exception {
        path = ClearPathUtil.cleanString(path);
        File file = new File(path);
        InputStream inStream = null;
        CustomXWPFDocument doc = null;
        //读取报告模板
        try {
            inStream = new FileInputStream(file);
            doc = new CustomXWPFDocument(inStream);
            this.replaceInTable(doc, params); // 替换表格里面的变量
            this.replaceInPara(doc, params); // 替换文本里面的变量
            //获取页眉，判断页眉是否为空
            List<XWPFHeader> pageHeaders = doc.getHeaderList();
            //当合同文本有页眉时，内容不为空，将原内容进行替换
            for (XWPFHeader pageHeader : pageHeaders) {
                List<XWPFParagraph> paragraphs = pageHeader.getParagraphs();
                for (XWPFParagraph paragraph : paragraphs) {
                    List<XWPFRun> runs = paragraph.getRuns();
                    //BOTH 之前的也会保留
                    //MEDIUM_KASHIDA 之前的也会保留
                    //DISTRIBUTE 两端对齐
                    //NUM_TAB 两端
                    //合同有页眉，但是内容可能为空，对照上面第2 点
                    //((XWPFParagraph) pageHeader.bodyElements.get(0)).getRuns()
                    if (!runs.isEmpty()) {
                            //设置成一个run
                            XWPFRun run = runs.get(0);
                            run.addBreak();
                            //这里就是我们需要替换的内容
                            run.setText(params.get("$bd_name$").toString()+"_"+params.get("$monitor_base$").toString(), 0);
                    }
                }
            }



        } catch (IOException e) {
            logger.error("获取报告模板异常，原因为：" + e.toString());
        } finally {
            if (null != inStream) {
                inStream.close();
            }
        }
        //读取配置文件
        Properties pros = PubUtils.readProperties(getClass().getClassLoader(), "java.properties");
		String tmpPath = pros.get("TMP_PATH").toString() +File.separator+ "offlinereoprt";
		tmpPath= ClearPathUtil.cleanString(tmpPath);
		OutputStream os = null;
		File tmpfile = new File(tmpPath);
		if(!tmpfile.exists()){
			tmpfile.mkdir();
		}
		tmpPath = tmpPath +File.separator+ fileName;
		tmpPath= ClearPathUtil.cleanString(tmpPath);
		File tmp = new File(tmpPath);
		if(tmp.exists()){
			tmp.delete();
		}
		PubUtils.createFile(tmpPath);
        try {
            os = new FileOutputStream(tmpPath);
            if (doc != null) {
                doc.write(os);
            }
            session.setAttribute("tmpPath", tmpPath);
            session.setAttribute("fileName", fileName);
        } catch (Exception e) {
            session.setAttribute("tmpPath", "");
            session.setAttribute("fileName", "");
            logger.error("输出稳态报告异常，原因为：" + e.toString());
        } finally {
            if (os != null) {
               os.close();
            }
        }
    }






    /**
     * 替换段落里面的变量
     *
     * @param doc    要替换的文档
     * @param params 参数
     */
    private void replaceInPara(CustomXWPFDocument doc, Map<String, Object> params) {
        Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();
        List<XWPFParagraph> paragraphList = new ArrayList<>();
        XWPFParagraph para;
        while (iterator.hasNext()) {
            para = iterator.next();
            paragraphList.add(para);
        }
        processParagraphs(paragraphList, params, doc);
    }

    private void replaceInTable(CustomXWPFDocument doc, Map<String, Object> params) {
        Iterator<XWPFTable> it = doc.getTablesIterator();
        while (it.hasNext()) {
            XWPFTable table = it.next();
            List<XWPFTableRow> rows = table.getRows();
            for (XWPFTableRow row : rows) {
                List<XWPFTableCell> cells = row.getTableCells();
                for (XWPFTableCell cell : cells) {
                    List<XWPFParagraph> paragraphListTable = cell.getParagraphs();
                    processParagraphs(paragraphListTable, params, doc);
                }
            }
        }
    }

    public static void processParagraphs(List<XWPFParagraph> paragraphList, Map<String, Object> param,
                                         CustomXWPFDocument doc) {
        if (paragraphList != null && paragraphList.size() > 0) {
            for (XWPFParagraph paragraph : paragraphList) {
                List<XWPFRun> runs = paragraph.getRuns();
                if (runs.size() > 0) {
                    for (XWPFRun run : runs) {
                        String bflag = "";
                        String text = run.getText(0);
                        if (text != null) {
                            boolean isSetText = false;
                            for (Entry<String, Object> entry : param.entrySet()) {
                                String key = entry.getKey();
                                if (text.indexOf(key) != -1) {
                                    isSetText = true;
                                    Object value = entry.getValue();
                                    if (value instanceof String) {// 文本替换
                                        text = text.replace(key, value.toString());
                                    } else if (value instanceof Map) {// 图片替换
                                        text = text.replace(key, "");
                                        Map pic = (Map) value;
                                        int width = Integer.parseInt(pic.get("width").toString());
                                        int height = Integer.parseInt(pic.get("height").toString());
                                        int picType = getPictureType(pic.get("type").toString());
                                        byte[] byteArray = (byte[]) pic.get("content");
                                        ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteArray);
                                        try {
                                            doc.addPictureData(byteInputStream, picType);
                                            doc.createPicture(doc.getAllPictures().size() - 1, width, height,
                                                    paragraph);
                                            bflag = "break";
                                        } catch (Exception e) {
                                            logger.error("文本替换发生异常，异常是" + e.getMessage());
                                        }
                                    }
                                }
                            }
                            if (isSetText) {
                                run.setText(text, 0);
                            }
                        }
                        if (bflag == "break") {
                            break;
                        }
                    }
                }
            }
        }
    }

    /**
     * 替换段落里面的变量
     *
     * @param para   要替换的段落
     * @param params 参数
     */
    private void replaceInPara(XWPFParagraph para, Map<String, Object> params, CustomXWPFDocument doc) {
        List<XWPFRun> runs;
        Matcher matcher;
        // if (this.matcher(para.getParagraphText()).find()) {
        runs = para.getRuns();
        int start = -1;
        int end = -1;
        String str = "";
        for (int i = 0; i < runs.size(); i++) {
            XWPFRun run = runs.get(i);
            String runText = run.toString();
            if ('$' == runText.charAt(0) && '{' == runText.charAt(1)) {
                start = i;
            }
            if ((start != -1)) {
                str += runText;
            }
            if ('}' == runText.charAt(runText.length() - 1)) {
                if (start != -1) {
                    end = i;
                    break;
                }
            }
        }

        for (int i = start; i <= end; i++) {
            para.removeRun(i);
            i--;
            end--;
        }

        for (Map.Entry<String, Object> entry : params.entrySet()) {
            String key = entry.getKey();
            if (str.indexOf(key) != -1) {
                Object value = entry.getValue();
                if (value instanceof String) {
                    str = str.replace(key, value.toString());
                    para.createRun().setText(str, 0);
                    break;
                } else if (value instanceof Map) {
                    str = str.replace(key, "");
                    Map pic = (Map) value;
                    int width = Integer.parseInt(pic.get("width").toString());
                    int height = Integer.parseInt(pic.get("height").toString());
                    int picType = getPictureType(pic.get("type").toString());
                    byte[] byteArray = (byte[]) pic.get("content");
                    ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteArray);
                    try {
                        // int ind = doc.addPicture(byteInputStream,picType);
                        // doc.createPicture(ind, width , height,para);
                        doc.addPictureData(byteInputStream, picType);
                        doc.createPicture(doc.getAllPictures().size() - 1, width, height, para);
                        para.createRun().setText(str, 0);
                        break;
                    } catch (Exception e) {
                        logger.error("文件替换发生异常，异常是" + e.getMessage());
                    }
                }
            }
        }
        // }
    }

    /**
     * 为表格插入数据，行数不够添加新行
     *
     * @param table     需要插入数据的表格
     * @param tableList 插入数据集合
     */
    private static void insertTable(XWPFTable table, List<String[]> tableList) {
        // 创建行,根据需要插入的数据添加新行，不处理表头
        for (int i = 0; i < tableList.size(); i++) {
            XWPFTableRow row = table.createRow();
        }
        // 遍历表格插入数据
        List<XWPFTableRow> rows = table.getRows();
        int length = table.getRows().size();
        for (int i = 1; i < length - 1; i++) {
            XWPFTableRow newRow = table.getRow(i);
            List<XWPFTableCell> cells = newRow.getTableCells();
            for (int j = 0; j < cells.size(); j++) {
                XWPFTableCell cell = cells.get(j);
                String s = tableList.get(i - 1)[j];
                cell.setText(s);
            }
        }
    }

    /**
     * 替换表格里面的变量
     *
     * @param doc    要替换的文档
     * @param params 参数
     */
    private void replaceInTable(CustomXWPFDocument doc, Map<String, Object> params, List<String[]> tableList) {
        Iterator<XWPFTable> iterator = doc.getTablesIterator();
        XWPFTable table;
        List<XWPFTableRow> rows;
        List<XWPFTableCell> cells;
        List<XWPFParagraph> paras;
        while (iterator.hasNext()) {
            table = iterator.next();
            if (table.getRows().size() > 1) {
                // 判断表格是需要替换还是需要插入，判断逻辑有$为替换，表格无$为插入
                if (this.matcher(table.getText()).find()) {
                    rows = table.getRows();
                    for (XWPFTableRow row : rows) {
                        cells = row.getTableCells();
                        for (XWPFTableCell cell : cells) {
                            paras = cell.getParagraphs();
                            for (XWPFParagraph para : paras) {
                                this.replaceInPara(para, params, doc);
                            }
                        }
                    }
                } else {
                    insertTable(table, tableList); // 插入数据
                }
            }
        }
    }

    /**
     * 正则匹配字符串
     *
     * @param str
     * @return
     */
    private Matcher matcher(String str) {
        Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}", Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(str);
        return matcher;
    }

    /**
     * 根据图片类型，取得对应的图片类型代码
     *
     * @param picType
     * @return int
     */
    private static int getPictureType(String picType) {
        int res = CustomXWPFDocument.PICTURE_TYPE_PICT;
        if (picType != null) {
            if (picType.equalsIgnoreCase("image/png")) {
                res = CustomXWPFDocument.PICTURE_TYPE_PNG;
            } else if (picType.equalsIgnoreCase("image/dib")) {
                res = CustomXWPFDocument.PICTURE_TYPE_DIB;
            } else if (picType.equalsIgnoreCase("image/emf")) {
                res = CustomXWPFDocument.PICTURE_TYPE_EMF;
            } else if (picType.equalsIgnoreCase("image/jpg") || picType.equalsIgnoreCase("image/jpeg")) {
                res = CustomXWPFDocument.PICTURE_TYPE_JPEG;
            } else if (picType.equalsIgnoreCase("image/wmf")) {
                res = CustomXWPFDocument.PICTURE_TYPE_WMF;
            }
        }
        return res;
    }

    /**
     * 关闭输入流
     *
     * @param is
     */
    private void close(InputStream is) {
        if (is != null) {
            try {
                is.close();
            } catch (IOException e) {
                logger.error("关闭输入流发生异常，异常是" + e.getMessage());
            }
        }
    }

    /**
     * 关闭输出流
     *
     * @param os
     */
    private void close(OutputStream os) {
        if (os != null) {
            try {
                os.close();
            } catch (IOException e) {
                logger.error("关闭输出流发生异常，异常是" + e.getMessage());
            }
        }
    }
}
