package cn.report.excel.util;

import cn.report.excel.easyexcel.api.EasyExcel;
import cn.report.excel.easyexcel.api.write.builder.ExcelWriterSheetBuilder;
import cn.report.excel.easyexcel.api.write.handler.CellWriteHandler;
import cn.report.excel.easyexcel.api.write.metadata.style.WriteCellStyle;
import cn.report.excel.easyexcel.api.write.metadata.style.WriteFont;
import cn.report.excel.easyexcel.api.write.style.HorizontalCellStyleStrategy;
import cn.report.excel.easyexcel.custom.SamCellWidthWriteHandler;
import cn.report.excel.easyexcel.custom.base.RowRange;
import cn.report.excel.easyexcel.custom.base.RowSum;
import cn.util.core.IsKit;
import cn.util.core.TypeKit;

import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.RegionUtil;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class EasyExcelUtil
{
	/**
	 *  列表导出--添加合并策略（EasyExcel）
	 */
	public static Map<String, List<RowRange>> addMerStrategy(
			List<List<String>> excelDtoList,List<Map<String,Object>> listMap)
	{
		//变量startRow表示拟执行合并操作的的起始行；endRow为结束行
		int startRow = 1; int endRow = excelDtoList.size();  
		return addMerStrategy(excelDtoList,listMap,startRow,endRow);
	}
	/**
	 *  列表导出--添加合并策略（EasyExcel）
	 *  用户直接给出合并范围listMap<起始列，起始行(相对与startRow，即与startRow相加)>
	 *  见：SamCellMergeStrategy
	 */
	public static Map<String, List<RowRange>> addMerStrategy(
			List<List<String>> excelDtoList,
			List<Map<String,Object>> listMap,
			int startRow,int endRow)
	{
		List<String> preExcelDto = null;
		Map<String, List<RowRange>> strategyMap = new HashMap<>();
		for (int i = startRow; i < endRow; i++)
		{
			List<String> currDto = excelDtoList.get(i);
			if (IsKit.isNotNullOrEmpty(preExcelDto)){
				for(int k = 0 ; k < listMap.size() ; k++) {
					EasyExcelUtil.fillStrategyMap(
							strategyMap, 
							TypeKit.objToStr(listMap.get(k).get("startRow")),
							i + TypeKit.objToInt(listMap.get(k).get("startCol"))
							);
				}
			}
			preExcelDto = currDto;
		}
		return strategyMap;
	}
	/**
	 * 新增或修改合并策略map(EasyExcel)
	 */
	private static void fillStrategyMap(
			Map<String, List<RowRange>> strategyMap, 
			String key/**起始列*/, int index) 
	{
		List<RowRange> rowRangeDtoList = strategyMap.get(key) == null ? new ArrayList<>() : strategyMap.get(key);
		boolean flag = false;
		for (RowRange dto : rowRangeDtoList) {
			//分段list中是否有end索引是上一行索引的，如果有，则索引+1
			if (dto.getEnd() == index) {
				dto.setEnd(index + 1);
				flag = true;
			}
		}
		//如果没有，则新增分段
		if (!flag) {
			rowRangeDtoList.add(new RowRange(index, index + 1));
		}
		strategyMap.put(key, rowRangeDtoList);
	}

	/** 构造EasyExcel表的填充数据LinkedHash*/
	public static List<List<String>> content(List<Map<String,Object>> listMap) 
	{
		List<List<String>> dataList = new ArrayList<>();
		if(IsKit.isNotNullOrEmpty(listMap)){
			for (Map<String, Object> m : listMap) 
			{
				List<String> listData = new ArrayList<>();
				String dataV = "";
				for (String k : m.keySet()) {
					dataV = TypeKit.objToStr(m.get(k));
					listData.add(dataV);
				}
				dataList.add(listData);
			}
		}
		return dataList;
	}	

	/**一级标题：统计； 二级标题：数值（3列）和比例（两列）
		List<List<String>> titleList = new ArrayList<>();
	    List<String> titleOne = Lists.newArrayList("统计","","","","");
	    List<String> titleTwo = Lists.newArrayList("数值","","","比例","");
	    titleList.add(makeUpTitle(titleOne));
	    titleList.add(makeUpTitle(titleTwo));
	    .head(roateHeadFields(titleList))
	    import com.alibaba.google.common.collect.Lists;

	 */
	/**补充数据. 示例：统计统计统计统计统计 数值数值数值 比例比例*/
	public static List<String> makeUpTitle(List<String> titleList)
	{
		List<String> makeUpList = new ArrayList<>();
		String temp = "";
		for (String e : ListUtils.emptyIfNull(titleList)) {
			if (StringUtils.isNotEmpty(e)) {
				temp = e;
			}
			makeUpList.add(temp);
		}
		return makeUpList;
	}
	/**旋转数据. 示例：统计数值 统计数值 统计数值  统计比例 统计比例*/
	public static List<List<String>> roateHeadFields(List<List<String>> headFields)
	{
		List<List<String>> result = new ArrayList<>();
		for (List<String> row : headFields) {
			for (int j = 0; j < row.size(); j++) {
				if (result.size() > j) {
					// 往对应第j个List<String> 添加添加值
					result.get(j).add(row.get(j));
				} else {
					// 分割成单个List<String>
					result.add(new ArrayList<>(Collections.singletonList(row.get(j))));
				}
			}
		}
		return result;
	}


	/**动态头传入
	 * bigTitle为一级标题；header为二级标题。
	 * 
	 * 人工加工
	 * List<String> vList = new ArrayList<>();
		vList.add("data0");
		vList.add("data1");
		vList.add("data2");
		vList.add("data3");
		vList.add("data40");
		List<List<String>> head = EasyExcelUtil.head(vList,"一级标题");

		// 第一行大标题样式设置
		.registerWriteHandler(new SamTitleWriteHandler(bigtitle,header ))
		//设置默认样式及写入头信息开始的行数
		.relativeHeadRowIndex(1)               
		// 表头、内容样式设置
		.registerWriteHandler(horizontalCellStyleStrategy)
	 * */
	public static List<List<String>> head(String[] header, String bigTitle) {
		List<String> head0 = null;
		List<List<String>> list = new LinkedList<List<String>>();
		for (String h : header) {
			head0 = new LinkedList<>();
			head0.add(bigTitle);
			head0.add(h);
			list.add(head0);
		}
		return list;
	}
	public static List<List<String>> head(List<String> header, String bigTitle) {
		List<List<String>> list = new ArrayList<>();
		List<String> head0 = new ArrayList<>();
		if(IsKit.isNotNullOrEmpty(header))
			for (String sub : header) {
				head0 = new ArrayList<>();
				head0.add(bigTitle);
				head0.add(sub);
				list.add(head0);
			}
		return list;
	}

	/** 动态头传入 header为二级标题
	 *  一级标题由new SheetWriteHandlerUtil(bigtitle1,header)定义
	 * */
	public static List<List<String>> head(String[] header) {
		List<String> head0 = null;
		List<List<String>> list = new LinkedList<List<String>>();
		for (String h : header) {
			head0 = new LinkedList<>();
			head0.add(h);
			list.add(head0);
		}
		return list;
	}
	/**标题样式
	 * 自定义表头样式
       方式1：通过使用注解来设置颜色（优点：使用非常方便，缺点：对于复杂表头就无能为力了，例如无法单独设置父表头和子表头的颜色）
       方式2：通过使用HorizontalCellStyleStrategy 策略的方式来设置表头颜色（优点：通过此策略可以对表头设置更多的样式，缺点：但此策略的应用对象是所有表头，这意味着无法单独对单个的表头进行个性化设置）。
	 * WriteCellStyle headWriteCellStyle = EasyExcelUtil.getHeadStyle();
	   HorizontalCellStyleStrategy horizontalCellStyleStrategy =
           new HorizontalCellStyleStrategy(headWriteCellStyle, new WriteCellStyle());
        //表头样式设置
        EasyExcel.writerSheet("模板")
        .registerWriteHandler(horizontalCellStyleStrategy)
	 * */
	public static WriteCellStyle getHeadStyle(){
		// 头的策略
		WriteCellStyle headWriteCellStyle = new WriteCellStyle();
		// 背景颜色
		headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
		headWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
		// 字体
		WriteFont headWriteFont = new WriteFont();
		headWriteFont.setFontName("黑体");//设置字体名字
		headWriteFont.setFontHeightInPoints((short)15);//设置字体大小
		headWriteFont.setBold(true);//字体加粗
		headWriteCellStyle.setWriteFont(headWriteFont); //在样式用应用设置的字体;
		// 样式
		headWriteCellStyle.setBorderBottom(BorderStyle.THIN);//设置底边框;
		headWriteCellStyle.setBottomBorderColor((short) 0);//设置底边框颜色;
		headWriteCellStyle.setBorderLeft(BorderStyle.THIN);  //设置左边框;
		headWriteCellStyle.setLeftBorderColor((short) 0);//设置左边框颜色;
		headWriteCellStyle.setBorderRight(BorderStyle.THIN);//设置右边框;
		headWriteCellStyle.setRightBorderColor((short) 0);//设置右边框颜色;
		headWriteCellStyle.setBorderTop(BorderStyle.THIN);//设置顶边框;
		headWriteCellStyle.setTopBorderColor((short) 0); //设置顶边框颜色;
		headWriteCellStyle.setWrapped(true);  //设置自动换行;
		//设置水平对齐的样式为居中对齐;
		headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
		//设置垂直对齐的样式为居中对齐;
		headWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); 

		//设置文本收缩至合适
		//headWriteCellStyle.setShrinkToFit(true);

		return headWriteCellStyle;
	}
	/**内容样式
	 *  WriteCellStyle contentWriteCellStyle = EasyExcelUtil.getContentStyle();
		HorizontalCellStyleStrategy horizontalCellStyleStrategy =
				new HorizontalCellStyleStrategy(EasyExcelUtil.getHeadStyle(), contentWriteCellStyle);
		 //内容样式设置
        EasyExcel.writerSheet("模板")
        .registerWriteHandler(horizontalCellStyleStrategy)
	 * */
	public static WriteCellStyle getContentStyle()
	{
		// 内容的策略
		WriteCellStyle contentWriteCellStyle = new WriteCellStyle();

		// 背景绿色
		// 需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定
		contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
		contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);

		// 字体策略
		WriteFont contentWriteFont = new WriteFont();
		contentWriteFont.setFontHeightInPoints((short) 9);//设置字体大小
		contentWriteFont.setFontName("宋体"); //设置字体名字
		contentWriteCellStyle.setWriteFont(contentWriteFont);//在样式用应用设置的字体;

		//设置样式;
		contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);//设置底边框;
		contentWriteCellStyle.setBottomBorderColor((short) 0);//设置底边框颜色;
		contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);  //设置左边框;
		contentWriteCellStyle.setLeftBorderColor((short) 0);//设置左边框颜色;
		contentWriteCellStyle.setBorderRight(BorderStyle.THIN);//设置右边框;
		contentWriteCellStyle.setRightBorderColor((short) 0);//设置右边框颜色;
		contentWriteCellStyle.setBorderTop(BorderStyle.THIN);//设置顶边框;
		contentWriteCellStyle.setTopBorderColor((short) 0); ///设置顶边框颜色;

		//垂直居中,水平居中
		contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);// 水平居中
		contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);// 垂直居中

		//设置自动换行;
		contentWriteCellStyle.setWrapped(true); 

		//contentWriteCellStyle.setDataFormatData(DataFormatData.data(49));//设置单元格格式是：文本格式，方式长数字文本科学计数法
		// contentWriteCellStyle.setShrinkToFit(true);//设置文本收缩至合适

		return contentWriteCellStyle;
	}
	public static HorizontalCellStyleStrategy getStyleStrategy2()
	{
		WriteCellStyle contentWriteCellStyle = EasyExcelUtil.getContentStyle();
		return new HorizontalCellStyleStrategy(EasyExcelUtil.getHeadStyle(), contentWriteCellStyle);
	}

	/**去除默认表头样式及设置内容居中*/
	public static HorizontalCellStyleStrategy getStyleStrategy()
	{
		//内容样式策略
		WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
		// 背景色（浅灰色）
		contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
		//垂直居中,水平居中
		contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
		contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
		//设置边框样式
		contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
		contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
		contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
		contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
		contentWriteCellStyle.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
		contentWriteCellStyle.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
		contentWriteCellStyle.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
		contentWriteCellStyle.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());

		//设置 自动换行
		contentWriteCellStyle.setWrapped(true);
		// 字体策略
		WriteFont contentWriteFont = new WriteFont();
		// 字体大小
		contentWriteFont.setFontHeightInPoints((short) 12);
		contentWriteCellStyle.setWriteFont(contentWriteFont);

		//头策略使用默认
		WriteCellStyle headWriteCellStyle = new WriteCellStyle();
		headWriteCellStyle.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());

		// 头样式与内容样式合并
		return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
	}

	private static XSSFCellStyle getCellStyle(Workbook workbook)
	{
		XSSFCellStyle cellStyle = (XSSFCellStyle) workbook.createCellStyle();// 单元格样式.getCellStyleAt(0);

		cellStyle.setWrapText(true);// 自动换行
		cellStyle.setAlignment(HorizontalAlignment.RIGHT);
		cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
		//对合并单元不起作用
		cellStyle.setBorderBottom(BorderStyle.THIN);//设置底边框;
		cellStyle.setBorderLeft(BorderStyle.THIN);  //设置左边框;
		cellStyle.setBorderRight(BorderStyle.THIN);//设置右边框;
		cellStyle.setBorderTop(BorderStyle.THIN);//设置顶边框;

		//标黄,要一起设置
		cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); //设置前景填充样式
		cellStyle.setFillForegroundColor(IndexedColors.YELLOW.getIndex());//前景填充色

		Font font = workbook.createFont();
		font.setFontName("仿宋_GB2312");
		font.setBold(true);
		font.setFontHeightInPoints((short) 12);
		cellStyle.setFont(font);

		return cellStyle;
	}

	/**增加下拉选择框
	 * 导出excel
	 * @param outputStream 输出流
	 * @param dataList     导出的数据
	 * @param classT        模板类
	 * @param sheetName     sheetName
	 * @param cellWriteHandlers    样式处理类
	 * 
	 *  // 指定标红色的列
        List<Integer> columns = Arrays.asList(0, 1);
        // 指定批注
        HashMap<Integer, String> annotationsMap = new HashMap<>();
        annotationsMap.put(0,"第一列标题批注");
        annotationsMap.put(1,"第二列标题批注");
        HashMap<Integer, String[]> dropDownMap = new HashMap<>();
        // 指定下拉框
        String[] ags = {"13","34","64"};
        String[] school = {"一中","二中","三中"};
        dropDownMap.put(1,ags);
        dropDownMap.put(2,school);

        TitleHandler titleHandler = new TitleHandler(columns, IndexedColors.RED.index,annotationsMap,dropDownMap);
        // 导出的数据
        List<TestVO> dataList = new ArrayList<>();
        // 输出流
        OutputStream outputStream = new FileOutputStream(new File(fileName));

        EasyExcelUtil.writeExcelWithModel(
        		outputStream,
        		data(), 
        		DemoData.class,
        		"模板", titleHandler); 
	 */
	public static void writeExcelWithModel(
			OutputStream outputStream, 
			List<? extends Object> dataList, 
			Class<? extends Object> classT, 
			String sheetName, 
			CellWriteHandler... cellWriteHandlers) {

		// 头的策略
		WriteCellStyle headWriteCellStyle = new WriteCellStyle();
		// 单元格策略
		WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
		// 初始化表格样式
		HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);

		ExcelWriterSheetBuilder excelWriterSheetBuilder = 
				EasyExcel.write(outputStream, classT)
				.sheet(sheetName)
				.registerWriteHandler(new SamCellWidthWriteHandler())
				.registerWriteHandler(horizontalCellStyleStrategy)
				;
		if (null != cellWriteHandlers && cellWriteHandlers.length > 0) {
			for (int i = 0; i < cellWriteHandlers.length; i++) {
				excelWriterSheetBuilder.registerWriteHandler(cellWriteHandlers[i]);
			}
		}
		// 开始导出
		excelWriterSheetBuilder.doWrite(dataList);
	}

	/**最后一行 增加汇总行
	 * 
	 * 	Workbook workbook = excelWriter.writeContext().writeWorkbookHolder().getWorkbook();  
		// 执行公式
		workbook.setForceFormulaRecalculation(true);
		excelWriter.write(data, writeSheet);

		int headRowNum = 2;//头行数
		int dataRowNum = 10;//数据行数
		String colString = "A";//长度转成ABC后的列
		String formulaStr = "SUM(" + colString 
				+(headRowNum+1) 
				+":" + colString 
				+ (headRowNum+dataRowNum) 
				+ ")";
		List<RowSum> sumList = new ArrayList<>();
		RowSum sumData = new RowSum((headRowNum+dataRowNum),0,2,formulaStr);
		sumData.setTitle("总和");
		sumData.setCellStyle(cellStyle);
		sumList.add(sumData);
		EasyExcelUtil.sumRow(workbook,sumList);
	 */
	public static void sumRow(Workbook workbook, List<RowSum> sumList) 
	{
		if(IsKit.isNullOrEmpty(sumList) || IsKit.isNullOrEmpty(workbook)) {
			return;
		}
		Boolean rowFlag = true;
		Row row = null;
		Sheet sheet = null;
		for(RowSum rowSum : sumList)
		{
			if(rowFlag) {
				sheet = workbook.getSheetAt(rowSum.getSheetNum());
				row = sheet.createRow(rowSum.getRowNum());
				rowFlag = false;
			}

			int startCol = rowSum.getStartCol();
			int endCol = rowSum.getEndCol();

			//指定行中指定列合并
			if(IsKit.isNotNullOrEmpty(startCol)
					&& IsKit.isNotNullOrEmpty(endCol)
					&& startCol != endCol && startCol < endCol
					){
				CellRangeAddress cellRangeAddress = new CellRangeAddress(
						rowSum.getRowNum(),rowSum.getRowNum(),
						startCol,endCol);
				sheet.addMergedRegionUnsafe(cellRangeAddress);
				//使用RegionUtil类为合并后的单元格添加边框
				RegionUtil.setBorderBottom(BorderStyle.THIN, cellRangeAddress, sheet); // 下边框
				RegionUtil.setBorderLeft(BorderStyle.THIN,cellRangeAddress, sheet); // 左边框
				RegionUtil.setBorderRight(BorderStyle.THIN, cellRangeAddress, sheet); // 有边框
				RegionUtil.setBorderTop(BorderStyle.THIN, cellRangeAddress, sheet); // 上边框
			}

			//创建单元格
			Cell cell = row.createCell(startCol);
			//设置单元格样式
			if(IsKit.isNotNullOrEmpty(rowSum.getCellStyle())) {
				cell.setCellStyle(rowSum.getCellStyle());
			}
			else {
				cell.setCellStyle(getCellStyle(workbook));
			}
			//汇总的名称
			cell.setCellValue(rowSum.getTitle());

			//汇总的结果
			cell = row.createCell(endCol + 1);
			cell.setCellStyle(rowSum.getCellStyle());
			//把公式塞入合计列
			cell.setCellFormula(rowSum.getFormula());
		}    
	}


}