package cn.report.template.sam;

import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlOptions;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

import java.io.*;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**生成页码 */
public class PoiTlUtil {



















	/////////////////////////////
	// 遍历文档中的表格
	private void iteratorTable(Map<String,Object> params,XWPFDocument document) throws IOException{
		List<XWPFTableRow> rows = null;
		List<XWPFTableCell> cells = null;
		// 获取文档中的表格内容
		List<XWPFTable> tables = document.getTables();
		for(XWPFTable table : tables){
			rows = table.getRows();
			// 遍历表格中的所有的行
			for(XWPFTableRow row : rows){
				cells = row.getTableCells();
				// 遍历这一行的单元格
				for(XWPFTableCell cell : cells){
					// 判断改单元格的内容是否是字符串字段
					//?xbm  if(strMatcher(cell.getText()).find()){
					//replaceInStr()替换字符串，可以多行也可以一行
					//?xbm    replaceInStr(cell,params,document);
					continue;
				}
			}
		}
	}


	private void iteratorParagraph(Map<String,Object> params,XWPFDocument document) throws  IOException{
		// 创建段落
		XWPFParagraph graph = null;
		// 在文档的基础上创建一个段落
		graph = document.createParagraph();
		List<XWPFParagraph> paragraphs = document.getParagraphs();
		for(int i =0;i<paragraphs.size();i++){
			// 获取每一个段落的内容
			XWPFParagraph graph1= paragraphs.get(i);
			//这里的“开始”就是一个标志
			if(graph1.getText().equals("开始")){
				// 在一个段落中新加一行
				XWPFRun row1 = graph.createRun();
				//addCarriageReturn()换行，row.addBreak()——这个也是换行
				row1.addCarriageReturn();
				// 省略很多内容.......
				String str = "";
				for (String k : params.keySet()){
					if(k == "description"){
						Object obj = params.get(k);
						str = obj.toString();
						break;
					}
				}
				StringBuilder stringBuilder = new StringBuilder();
				for(int j = 0; j< 64-str.length();j++){
					// 当后面不足时，添加空格内容
					stringBuilder.append("");
				}
				document.removeBodyElement(document.getPosOfParagraph(graph1));
			}
		}
	}

	/**
	 * 匹配传入信息集合与模板
	 * @param value 模板需要替换的区域
	 * @param textMap 传入信息集合
	 * @return 模板需要替换区域信息集合对应值
	 */
	public static String replaceWordContent(String value, Map<String, String> textMap){
		Set<Entry<String, String>> textSets = textMap.entrySet();
		for (Entry<String, String> textSet : textSets) {
			//匹配模板与替换值 格式${key}
			String key = "${"+textSet.getKey()+"}";
			if(value.contains(key)){
				value = textSet.getValue();
			}
		}
		//模板未匹配到区域替换为空
		if(checkText(value)){
			value = "";
		}
		return value;
	}
	/**
	 *替换段落文本
	 * @param document docx解析对象
	 * @param textMap 需要替换的信息集合
	 * */
	private static void replaceText(XWPFDocument document,Map<String,String> textMap){
		// 获取段落集合
		List<XWPFParagraph> paragraphs = document.getParagraphs();
		// 取每一个段落
		for(XWPFParagraph paragraph :paragraphs){
			// 判断段落是否需要替换
			String text = paragraph.getText();
			if(checkText(text)){
				List<XWPFRun> runs = paragraph.getRuns();
				for(XWPFRun run : runs){
					// 替换模板中的内容
					run.setText(replaceWordContent(run.toString(),textMap),0);
				}
			}
		}
	}
	/**
	 * 判断文本中时候包含$
	 * @param text 文本
	 * @return 包含返回true,不包含返回false
	 */
	public static boolean checkText(String text){
		return text.contains("$");
	}
	/**
	 * 替换表格中的内容
	 *@param document docx解析对象
	 *@param textMap 需要替换的信息集合
	 *@param tableList 需要插入的表格信息集合
	 * */
	private static void replaceTable(XWPFDocument document,Map<String,String> textMap,List<String[]> tableList,List<String[]> defaultTableList){
		// 获取表格对象集合
		List<XWPFTable> tables = document.getTables();
		for(int i = 0;i < tables.size();i++){
			// 只处理行数大于等于2的表格，且不处理表头
			XWPFTable table = tables.get(i);
			if(table.getRows().size() > 1){
				// 当表格中有$替换数据，没有则插入数据
				if(checkText(table.getText())){
					List<XWPFTableRow> rows = table.getRows();
					// 遍历表格，并替换模板
					replaceWordTableContent(rows,textMap);
				}else {
					// 当表格大于模板的行数时，新增行数
					// tables.get(2) == table   <=> i ==2
					if(i == 2){
						// 当时第三张表的数据时，则添加默认数据
						insertTable(tables,table,defaultTableList);
					}else if(i == 1 && tableList.get(0)[0] == "暂无参数"){
						for (int j = 0; j < tableList.size(); j++) {
							mergeColumns(table,j+1,0,5);
						}
						insertTable(tables,table,tableList);
					}else {
						insertTable(tables,table,tableList);
					}
				}
			}
		}
	}
	/**
	 * 为表格插入数据，行数不够添加新行
	 * @param tables 获取模板中的所有表格，取出其中的一张表
	 * @param table 需要插入数据的表格
	 * @param tableList 插入数据集合
	 */
	private static void insertTable(List<XWPFTable> tables,XWPFTable table, List<String[]> tableList){
		//创建行,根据需要插入的数据添加新行，不处理表头
		for(int i = 1; i < tableList.size(); i++){
			XWPFTableRow row =table.createRow();
			//对于多个参数的表格，将interfaceID 跨行合并单元格,只对第一张表进行跨单元格合并
			if(tables.get(1) == table){
				mergeRow(table,0,i,i+1);
			}
		}
		//遍历表格插入数据
		List<XWPFTableRow> rows = table.getRows();
		for(int i = 1; i < rows.size(); i++){
			//为新增的表格设置行高 567 为 1cm
			table.getRows().get(i).setHeight(567);
			// 设置列宽
			// 表格属性
			CTTblPr tblPr = table.getCTTbl().addNewTblPr();
			//表格宽度
			CTTblWidth width = tblPr.addNewTblW();
			// 1710 :大约为3cm
			width.setW(BigInteger.valueOf(1710));
			//设置表格宽度为非自动
			//  width.setType(STTblWidth.DXA);
			XWPFTableRow newRow = table.getRow(i);
			List<XWPFTableCell> cells = newRow.getTableCells();
			for(int j = 0; j < cells.size(); j++){
				XWPFTableCell cell = cells.get(j);
				// 输入的内容垂直居中
				cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
				// 设置水平居中
				CTTc cttc = cell.getCTTc();
				CTTcPr ctPr = cttc.addNewTcPr();
				ctPr.addNewVAlign().setVal(STVerticalJc.CENTER);
				cttc.getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);
				List<XWPFParagraph> graphs = cell.getParagraphs();
				for(XWPFParagraph graph : graphs){
					XWPFRun run = graph.createRun();
					run.setFontSize(12);
					run.setFontFamily("宋体");
					//run.setText(tableList.get(i-1)[j]);
					run.setText("");
				}
			}
		}
	}




	/**
	 * 遍历表格
	 * @param rows 表格行对象
	 * @param textMap 需要替换的信息集合
	 */
	private static void replaceWordTableContent(List<XWPFTableRow> rows ,Map<String, String> textMap){
		for (XWPFTableRow row : rows) {
			List<XWPFTableCell> cells = row.getTableCells();
			for (XWPFTableCell cell : cells) {
				//判断单元格是否需要替换
				// checkText（）判断表格模板中是否被${}包裹
				if(checkText(cell.getText())){
					List<XWPFParagraph> paragraphs = cell.getParagraphs();
					for (XWPFParagraph paragraph : paragraphs) {
						List<XWPFRun> runs = paragraph.getRuns();
						for (XWPFRun run : runs) {
							//replaceWordContent() 遍历Map,依次取出Map 中的key和value
							run.setText(replaceWordContent(run.toString(), textMap),0);
						}
					}
				}
			}
		}
	}


	/**动态生成表格行数
	 * 为表格插入数据，行数不够添加新行
	 * @param table 需要插入数据的表格
	 * @param tableList 插入数据集合
	 */

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



	/**跨列合并
	 * 当接口无参数时，合并行
	 * @param table 当前表
	 * @param col 需要合并的行
	 * @param fromRow 开始行
	 * @param toRow 结束行
	 * */
	private static void  mergeRow(XWPFTable table, int col, int fromRow, int toRow){
		//index 为 行索引
		for (int index = fromRow; index <= toRow ; index++) {
			// 重新创建类加载---类似于new()
			CTVMerge merge = CTVMerge.Factory.newInstance();
			if(index == fromRow){
				merge.setVal(STMerge.RESTART);
			}else{
				merge.setVal(STMerge.CONTINUE);
			}
			XWPFTableCell tableCell = table.getRow(index).getCell(col);
			CTTcPr tcPr = tableCell.getCTTc().getTcPr();
			if(tcPr != null){
				tcPr.setVMerge(merge);
			}else{
				tcPr = CTTcPr.Factory.newInstance();
				tcPr.setVMerge(merge);
				tableCell.getCTTc().setTcPr(tcPr);
			}
		}
	}


	/**跨行合并
	 * 当数据传递的数据为空时，需要显示一个暂无参数，同时合并单元格
	 * 
	 * 合并列
	 * @param table
	 * @param rowNumber 需要合并的列在的行
	 * @param fromCol 开始列
	 * @param toCol 结束列
	 */
	private static void mergeColumns(XWPFTable table, int rowNumber, int fromCol, int toCol) {
		XWPFTableRow row = table.getRow(rowNumber);
		for(int index = fromCol; index < toCol; index++){
			CTHMerge hMerge = CTHMerge.Factory.newInstance();
			if(index == fromCol){
				hMerge.setVal(STMerge.RESTART);
			} else {
				hMerge.setVal(STMerge.CONTINUE);
			}
			XWPFTableCell cell = row.getCell(index);
			CTTcPr tcPr = cell.getCTTc().getTcPr();
			if (tcPr != null) {
				tcPr.setHMerge(hMerge);
			} else {
				tcPr = CTTcPr.Factory.newInstance();
				tcPr.setHMerge(hMerge);
				cell.getCTTc().setTcPr(tcPr);
			}
		}
	}





	// 使用Stream 读取和写入文件内容
	public static void  exportWordTemp(String inputPath, Map<String, String> textMap, 
			List<String[]> tableList,List<String[]> defaultTableList,String fileName
			/*,HttpServletResponse response*/) {
		try {
			InputStream inputStream = new FileInputStream(inputPath);
			//获取文档XX.docx
			XWPFDocument document = new XWPFDocument(inputStream);
			// 替换文本对象
			replaceText(document,textMap);
			// 替换表格内容
			replaceTable(document,textMap,tableList,defaultTableList);
			/*
            OutputStream outputStream = response.getOutputStream();
            // 设置导出的内容是doc
            response.setContentType("application/octet-stream; charset=utf-8");
            response.setHeader("Content-Disposition", "attachment; fileName=" + fileName);
            // 将文件写入关闭流
            document.write(outputStream);
            outputStream.flush();*/

			FileOutputStream out = new FileOutputStream("C:\\bjtu\\temp\\new_doc2.docx");
			document.write(out);

			out.close();

			document.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}




	public static void main_ol(String[] args) {



		//查询业务参数的内容
		//List<InterfaceWordEntity> interfaceWordEntity = getWordInterfaceById(interfaceEntity.getId());
		//  String path = new File("src\\main\\resources\\templates\\temp.docx").getAbsolutePath();
		//导出的名字
		String fileName = "XBM.docx";//interfaceEntity.getName() +".docx";
		// 在文档中的段落写入文字
		Map<String,String> textMap=new HashMap<>();
		textMap.put("name","interfaceEntity.getName()");
		textMap.put("fullPath","interfaceEntity.getFullPath()");
		textMap.put("updateTime","interfaceEntity.getUpdateTime()");

		//if(interfaceEntity.getDescription() != null){
		textMap.put("description","interfaceEntity.getDescription()");
		//}

		List<String[]> tableList = new ArrayList<>();
		// 当数据集参数大于0时们将数据依次，不为空
		/*  if(interfaceWordEntity.size() > 0){
            for(InterfaceWordEntity paramEntity : interfaceWordEntity) {
                tableList.add(new String[]{paramEntity.getInterfaceId(),paramEntity.getRequiredParameter(),paramEntity.getParamType(),paramEntity.getRequired().toString(),paramEntity.getParamTips()});
            }
        }else{
            // 当数据集参数大于等于0，参数为空的时候，将导出的参数列表合并单元格并且显示”暂无参数“
            tableList.add(new String[]{"暂无参数","","","",""});
        }*/
		tableList.add(new String[]{"暂无参数","","","",""});


		// 给模板中的表格生成默认的数据内容
		List<String[]> defaultTableList = new ArrayList<>();
		defaultTableList.add(new String[]{"test_item","String","是","200:查询成功,其他：异常"});
		defaultTableList.add(new String[]{"equip_nam","String","是","返回信息"});
		defaultTableList.add(new String[]{"equip_num","String","是","数据件数"});
		defaultTableList.add(new String[]{"detailList","List<Map<String, String>>","是","返回数据"});

		// 表格中的数据使用params,段落中的内容使用 testMap
		exportWordTemp("C:\\bjtu\\temp\\Test1.docx",textMap,tableList,defaultTableList ,fileName/*,response*/);








		/*Ok
		try {
			// file path
			File is = new File("C:/bjtu/template/t_result.docx");
			FileInputStream fis = new FileInputStream(is);
			// document object
			XWPFDocument doc = new XWPFDocument(fis);

			// calling method
			createFooter(doc);
			// or this method both ok!
			// createFooter(doc);

			// output
			OutputStream os = new FileOutputStream("D:\\Test1.docx");
			doc.write(os);

		} catch (Exception e) {
			e.printStackTrace();
		}*/
	}

	public static void createFooter(XWPFDocument doc) {

		// create footer
		XWPFHeaderFooterPolicy policy = doc.getHeaderFooterPolicy();
		CTP ctpFooter = CTP.Factory.newInstance();

		XWPFParagraph[] parsFooter;

		// add style (s.th.)
		CTPPr ctppr = ctpFooter.addNewPPr();
		CTString pst = ctppr.addNewPStyle();
		pst.setVal("style21");
		CTJc ctjc = ctppr.addNewJc();
		ctjc.setVal(STJc.CENTER);
		ctppr.addNewRPr();

		// add everything from the footerXXX.xml you need
		CTR ctr = ctpFooter.addNewR();
		ctr.addNewRPr();
		CTFldChar fch = ctr.addNewFldChar();
		fch.setFldCharType(STFldCharType.BEGIN);

		ctr = ctpFooter.addNewR();
		ctr.addNewInstrText().setStringValue(" PAGE ");

		ctpFooter.addNewR().addNewFldChar().setFldCharType(STFldCharType.SEPARATE);

		ctpFooter.addNewR().addNewT().setStringValue("1");

		ctpFooter.addNewR().addNewFldChar().setFldCharType(STFldCharType.END);

		XWPFParagraph footerParagraph = new XWPFParagraph(ctpFooter, doc);

		parsFooter = new XWPFParagraph[1];

		parsFooter[0] = footerParagraph;

		policy.createFooter(XWPFHeaderFooterPolicy.DEFAULT, parsFooter);
	}

	public static void createDefaultFooter(final XWPFDocument document) {
		CTP pageNo = CTP.Factory.newInstance();
		XWPFParagraph footer = new XWPFParagraph(pageNo, document);

		CTPPr begin = pageNo.addNewPPr();
		begin.addNewPStyle().setVal("style21");
		begin.addNewJc().setVal(STJc.CENTER);

		pageNo.addNewR().addNewFldChar().setFldCharType(STFldCharType.BEGIN);
		pageNo.addNewR().addNewInstrText().setStringValue("PAGE   \\* MERGEFORMAT");
		pageNo.addNewR().addNewFldChar().setFldCharType(STFldCharType.SEPARATE);

		CTR end = pageNo.addNewR();
		CTRPr endRPr = end.addNewRPr();
		endRPr.addNewNoProof();
		endRPr.addNewLang().setVal("zh-CN");
		end.addNewFldChar().setFldCharType(STFldCharType.END);

		CTSectPr sectPr = document.getDocument().getBody().isSetSectPr() ? document.getDocument().getBody().getSectPr() : document.getDocument().getBody().addNewSectPr();

		XWPFHeaderFooterPolicy policy = new XWPFHeaderFooterPolicy(document, sectPr);
		policy.createFooter(STHdrFtr.DEFAULT, new XWPFParagraph[] { footer });
	}

	//两个对象进行追加
	public  XWPFDocument mergeWord(XWPFDocument document,XWPFDocument doucDocument2) throws Exception {
		XWPFDocument src1Document =document ;
		XWPFParagraph p = src1Document.createParagraph();
		//设置分页符
		p.setPageBreak(true);
		CTBody src1Body = src1Document.getDocument().getBody();
		XWPFDocument src2Document = doucDocument2;
		CTBody src2Body = src2Document.getDocument().getBody();
		XWPFParagraph p2 = src2Document.createParagraph(); 
		XmlOptions optionsOuter = new XmlOptions();
		optionsOuter.setSaveOuter();
		String appendString = src2Body.xmlText(optionsOuter);
		String srcString = src1Body.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("<"));
		CTBody makeBody = CTBody.Factory.parse(prefix+mainPart+addPart+sufix);
		src1Body.set(makeBody);
		return src1Document;
	}

}