package io.renren.common.utils;

import java.awt.Color;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.text.NumberFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.servlet.http.HttpServletResponse;

import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Font;
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.Workbook;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.extensions.XSSFCellBorder.BorderSide;
import org.springframework.web.multipart.MultipartFile;

public class ExcelUtils {
    private final static String EXCEL_2003 = ".xls"; // 2003- 版本的excel
    private final static String EXCEL_2007 = ".xlsx"; // 2007+ 版本的excel

    // 导出 start
    public static void exportExcel(HttpServletResponse response, String fileName, ExcelData data) throws Exception {
        // 告诉浏览器用什么软件可以打开此文件
        response.setHeader("content-Type", "application/vnd.ms-excel");
        // 下载文件的默认名称
        response.setHeader("Content-Disposition", "attachment;filename="+URLEncoder.encode(fileName, "utf-8"));
        exportExcel(data, response.getOutputStream());
    }

    public static void exportExcel(ExcelData data, OutputStream out) throws Exception {

        XSSFWorkbook wb = new XSSFWorkbook();
        try {
            String sheetName = data.getName();
            if (null == sheetName) {
                sheetName = "Sheet1";
            }
            XSSFSheet sheet = wb.createSheet(sheetName);
            writeExcel(wb, sheet, data);

            wb.write(out);
        } catch(Exception e){
            e.printStackTrace();
        }finally{
            //此处需要关闭 wb 变量
            out.close();
        }
    }
    
    private static void writeExcel(XSSFWorkbook wb, Sheet sheet, ExcelData data) {

        int rowIndex = 0;

        rowIndex = writeTitlesToExcel(wb, sheet, data.getTitles());
        writeRowsToExcel(wb, sheet, data.getRows(), rowIndex);
        autoSizeColumns(sheet, data.getTitles().size() + 1);

    }

    private static int writeTitlesToExcel(XSSFWorkbook wb, Sheet sheet, List<String> titles) {
        int rowIndex = 0;
        int colIndex = 0;

        Font titleFont = wb.createFont();
        titleFont.setFontName("simsun");
        //titleFont.setBoldweight(Short.MAX_VALUE);
        // titleFont.setFontHeightInPoints((short) 14);
        titleFont.setColor(IndexedColors.BLACK.index);

        XSSFCellStyle titleStyle = wb.createCellStyle();
        titleStyle.setAlignment(XSSFCellStyle.ALIGN_CENTER);
        titleStyle.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);
        titleStyle.setFillForegroundColor(new XSSFColor(new Color(182, 184, 192)));
        titleStyle.setFillPattern(XSSFCellStyle.SOLID_FOREGROUND);
        titleStyle.setFont(titleFont);
        setBorder(titleStyle, BorderStyle.THIN, new XSSFColor(new Color(0, 0, 0)));

        Row titleRow = sheet.createRow(rowIndex);
        // titleRow.setHeightInPoints(25);
        colIndex = 0;

        for (String field : titles) {
            Cell cell = titleRow.createCell(colIndex);
            cell.setCellValue(field);
            cell.setCellStyle(titleStyle);
            colIndex++;
        }

        rowIndex++;
        return rowIndex;
    }

    private static int writeRowsToExcel(XSSFWorkbook wb, Sheet sheet, List<List<Object>> rows, int rowIndex) {
        int colIndex = 0;

        Font dataFont = wb.createFont();
        dataFont.setFontName("simsun");
        // dataFont.setFontHeightInPoints((short) 14);
        dataFont.setColor(IndexedColors.BLACK.index);

        XSSFCellStyle dataStyle = wb.createCellStyle();
        dataStyle.setAlignment(XSSFCellStyle.ALIGN_CENTER);
        dataStyle.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);
        dataStyle.setFont(dataFont);
        setBorder(dataStyle, BorderStyle.THIN, new XSSFColor(new Color(0, 0, 0)));

        for (List<Object> rowData : rows) {
            Row dataRow = sheet.createRow(rowIndex);
            // dataRow.setHeightInPoints(25);
            colIndex = 0;

            for (Object cellData : rowData) {
                Cell cell = dataRow.createCell(colIndex);
                if (cellData != null) {
                    cell.setCellValue(cellData.toString());
                } else {
                    cell.setCellValue("");
                }

                cell.setCellStyle(dataStyle);
                colIndex++;
            }
            rowIndex++;
        }
        return rowIndex;
    }

    private static void autoSizeColumns(Sheet sheet, int columnNumber) {

        for (int i = 0; i < columnNumber; i++) {
            int orgWidth = sheet.getColumnWidth(i);
            sheet.autoSizeColumn(i, true);
            // int newWidth = (int) (sheet.getColumnWidth(i) + 100);	// 列宽超过255 错误
            // if (newWidth > orgWidth) {
            //     sheet.setColumnWidth(i, newWidth);
            // } else {
            //     sheet.setColumnWidth(i, orgWidth);
            // }
            if(orgWidth<255*256){	// 解决方法一
                sheet.setColumnWidth(i, orgWidth < 3000 ? 3000 : orgWidth);    
            }else{
                sheet.setColumnWidth(i,6000 );
            }
            // if (orgWidth > 255)  // 解决办法二 还是有问题
            // {
            // 	orgWidth = 255;
            // }
            // //设置列宽
            // sheet.setColumnWidth(i, (orgWidth + 1) * 256);
        }
    }

    private static void setBorder(XSSFCellStyle style, BorderStyle border, XSSFColor color) {
        style.setBorderTop(border);
        style.setBorderLeft(border);
        style.setBorderRight(border);
        style.setBorderBottom(border);
        style.setBorderColor(BorderSide.TOP, color);
        style.setBorderColor(BorderSide.LEFT, color);
        style.setBorderColor(BorderSide.RIGHT, color);
        style.setBorderColor(BorderSide.BOTTOM, color);
    }
    // 导出 end

    // 导入 start
    /**
     * 功能描述:创建工作簿
     *
     * @author grm
     * @since 2020年1月28日
     * @param file 文件
     * @return workbook
     */
    public static Workbook createWorkbook(MultipartFile file) {
        InputStream inputStream;
        Workbook workbook = null;
        try {
            if(file.isEmpty()) {
                R.error("file is empty!");
                return null;
            }
            inputStream = file.getInputStream();
            String fileType = getFileType(file);
            if (EXCEL_2003.equals(fileType)) {
                workbook = new HSSFWorkbook(inputStream);
            } else if (EXCEL_2007.equals(fileType)) {
                workbook = new XSSFWorkbook(inputStream);
            } else {
                R.error("file is not excel!");
                return null;
            }
        } catch (IOException e) {
            R.error(e.getMessage());
        }
        return workbook;
    }
    
    /**
     * 功能描述:判断是否是空行
     *
     * @author grm
     * @since 2020年1月28日
     * @param row 行
     * @return boolean
     */
    public static boolean isEmptyRow(Row row) {
        if (row == null || row.toString().isEmpty()) {
            return true;
        } else {
            Iterator<Cell> it = row.iterator();
            boolean isEmpty = true;
            while (it.hasNext()) {
                Cell cell = it.next();
                if (cell.getCellType() != Cell.CELL_TYPE_BLANK) {
                    isEmpty = false;
                    break;
                }
            }
            return isEmpty;
        }
    }

    /**
     * 功能描述:判断是不是excel文件
     *
     * @author grm
     * @since 2020年1月28日
     * @param file 文件
     * @return boolean
     */
    public static boolean isExcel(MultipartFile file) {
        String fileType = getFileType(file);
        if ((!EXCEL_2003.equals(fileType)) && (!EXCEL_2007.equals(fileType))) {
            R.error("file is not excel!");
            return false;
        }
        return true;
    }

    /**
     * 功能描述:获取文件类型/后缀
     *
     * @author grm
     * @since 2020年1月28日
     * @param file 文件
     * @return fileType
     */
    public static String getFileType(MultipartFile file) {
        String originalFilename = file.getOriginalFilename();
        return (originalFilename.substring(originalFilename.lastIndexOf("."), originalFilename.length())).toLowerCase();
    }

    /**
     * 处理类型
     * 
     * @param cell
     * @return
     */
    @SuppressWarnings("deprecation")
    public static String getVal(Cell cell) {
        if (null != cell) {
            switch (cell.getCellType()) {
            case XSSFCell.CELL_TYPE_NUMERIC: // 数字
                double dou = cell.getNumericCellValue();
                NumberFormat nf = NumberFormat.getInstance();
                String str = nf.format(dou);
                if (str.indexOf(",") >= 0) {
                    // 这种方法对于自动加".0"的数字可直接解决
                    // 但如果是科学计数法的数字就转换成了带逗号的，例如：12345678912345的科学计数法是1.23457E+13
                    // 经过这个格式化后就变成了字符串“12,345,678,912,345”，这也并不是想要的结果，所以要将逗号去掉
                    str = str.replace(",", "");
                }
                return str;
            case XSSFCell.CELL_TYPE_STRING: // 字符串
                return cell.getStringCellValue() + "";
            case XSSFCell.CELL_TYPE_BOOLEAN: // Boolean
                return cell.getBooleanCellValue() + "";
            case XSSFCell.CELL_TYPE_FORMULA: // 公式
                try {
                    if (HSSFDateUtil.isCellDateFormatted(cell)) {
                        Date date = cell.getDateCellValue();
                        return (date.getYear() + 1900) + "-" + (date.getMonth() + 1) + "-" + date.getDate();
                    } else {
                        return String.valueOf((int) cell.getNumericCellValue());
                    }
                } catch (IllegalStateException e) {
                    return String.valueOf(cell.getRichStringCellValue());
                }
            case XSSFCell.CELL_TYPE_BLANK: // 空值
                return "";
            case XSSFCell.CELL_TYPE_ERROR: // 故障
                return "";
            default:
                return "未知类型   ";
            }
        } else {
            return "";
        }
    }

    // /**
    //  * 功能描述:导入excel数据到二维数组
    //  *
    //  * @author grm
    //  * @since 2020年1月28日
    //  * @param file 文件
    //  * @return list
    //  */
    // public static List<List<String>> importExcel(MultipartFile file) {
    // 	List<List<String>> list = new ArrayList<>();
    // 	Workbook workbook = ExcelUtils.createWorkbook(file);
    // 	if (workbook != null) {
    // 		// 获取工作表
    // 		Sheet sheet = workbook.getSheetAt(0);
    // 		// 获取sheet中第一行行号
    // 		int firstRowNum = sheet.getFirstRowNum();
    // 		// 获取sheet中最后一行行号
    // 		int lastRowNum = sheet.getLastRowNum();
    // 		// 循环插入数据
    // 		for (int i = firstRowNum + 1; i <= lastRowNum; i++) { // 标题的下一行开始
    // 			Row row = sheet.getRow(i);
    // 			if (ExcelUtils.isEmptyRow(row) == false) {
                  
    // 				List<String> res = HandleRow(row);
    // 				list.add(res);
    // 			}
    // 		}
    // 	}
    // 	return list;
    // }
    
    // public static List<String> HandleRow(Row row) {
    //     List<String> res = new ArrayList<>();

    //     return res;
    // }

    // 导出 end
    
    /**
     *  导入原 rows
     * @param rows
     * @param out
     * @throws Exception
     */
    public static int addRowsExcel(List<List<Object>> rows, int rowIndex, FileInputStream in, OutputStream out) throws Exception {
        XSSFWorkbook workbook = new XSSFWorkbook(in);
        XSSFSheet sheet = workbook.getSheetAt(0);

        try {
            writeRowsToExcel(workbook, sheet, rows, rowIndex);

            workbook.write(out);
        } catch(Exception e){
            e.printStackTrace();
        }finally{
            //此处需要关闭 wb 变量
            out.close();
        }
        return rowIndex;
    }
}