package com.huaheng.common.jasper;

import com.huaheng.common.exception.service.ServiceException;
import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.export.*;
import net.sf.jasperreports.engine.export.ooxml.JRXlsxExporter;
import net.sf.jasperreports.engine.fill.JRFileVirtualizer;
import net.sf.jasperreports.export.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.sql.Connection;
import java.sql.SQLException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 *  报表工具类
 * @author ricard
 * @date   19/11/21
 *
 */
public class JasperreportUtils {




    private static final Logger LOGGER = LoggerFactory.getLogger(JasperreportUtils.class);
    private HttpServletRequest request;
    private HttpServletResponse response;
    private HttpSession session;

    public JasperreportUtils(HttpServletRequest request, HttpServletResponse response, HttpSession session){
        super();
        this.request = request;
        this.response =response;
        this.session =request.getSession();
    }



    /**
     * datasource与parameters填充报表
     *
     * @param jasperPath
     * @param dataSource
     * @param parameters
     * @return
     * @throws JRException
     */
    public JasperPrint getJasperPrint(String jasperPath, Map<String, Object> parameters, JRDataSource dataSource)
            throws JRException {

        JasperPrint jasperPrint = JasperFillManager.fillReport(jasperPath, parameters, dataSource);
        return jasperPrint;
    }

    /**
     * connection与parameters填充报表
     *
     * @param jasperPath
     * @param conn
     * @param parameters
     * @return
     * @throws JRException
     */
    public JasperPrint getJasperPrint(String jasperPath, Map<String, Object> parameters, Connection conn)
            throws JRException {

        JasperPrint jasperPrint = JasperFillManager.fillReport(jasperPath, parameters, conn);
        return jasperPrint;
    }

    /**
     * 传入list获取jasperPrint
     *
     * @param jasperPath
     * @param parameters
     * @param list
     * @return
     * @throws JRException
     */
//    public JasperPrint getJasperPrintWithBeanList(String jasperPath, Map<String, Object> parameters, List<?> list)
//            throws JRException,SQLException {
//        JRDataSource jrDataSource = null;
//        JasperPrint jasperPrint =new JasperPrint();
//        if(null != list && list.size()> 0) {
//            jrDataSource = new JRBeanCollectionDataSource(list);
//            jasperPrint = JasperFillManager.fillReport(jasperPath, parameters, jrDataSource);
//        }else {
//            jasperPrint = JasperFillManager.fillReport(jasperPath, parameters, connection);
//        }
//        return jasperPrint;
//    }



    /**
     * 获得相应类型的Content type
     *
     * @param docType
     * @return
     */
    public String getContentType(DocType docType) {
        String contentType = "text/html";
        switch (docType) {
            case PDF:
                contentType = "application/pdf";
                break;
            case XLS:
                contentType = "application/vnd.ms-excel";
                break;
            case XLSX:
                contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
                break;
            case XML:
                contentType = "text/xml";
                break;
            case RTF:
                contentType = "application/rtf";
                break;
            case CSV:
                contentType = "text/plain";
                break;
            case DOC:
                contentType = "application/msword";
                break;
            default:
                throw new ServiceException("格式错误!");

        }
        return contentType;
    }

    /**
     * jrxml文件 编译为 jasper文件
     *
     * @param jrxmlPath
     * @param jasperPath
     * @throws JRException
     */
    public void jrxmlToJsper(String jrxmlPath, String jasperPath) throws JRException {

        JasperCompileManager.compileReportToFile(jrxmlPath, jasperPath);

    }


    /**
     * 生成html文件
     * @param response
     * @param connection
     * @param jasperPath
     * @param fileName
     * @param parameters
     * @return
     */
    public String createHtml(HttpServletResponse response, Connection connection, String jasperPath, String fileName,
                             Map<String, Object> parameters, String folder) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
        String dpath = sdf.format(new Date());
        String path = "D:"+"/reportHtml" + folder + "/" + dpath;
        File file = new File(path);
        if (!file.exists()) {
            file.mkdirs();
        }
        String htmlFilePath = path + "/" + fileName;
        try {

            JasperPrint jasperPrint = this.getJasperPrint(jasperPath,parameters,connection);
            JasperExportManager.exportReportToHtmlFile(jasperPrint, htmlFilePath);

        } catch (Exception ex) {
            LOGGER.error("生成html文件错误"+ex.getMessage(),ex);
        }
        return folder + "/" + dpath + "/" + fileName;
    }

    /**
     * 传入类型,获取输出器
     *
     * @param docType
     * @return
     */
    public JRAbstractExporter getJRExporter(DocType docType) {
        JRAbstractExporter exporter = null;
        switch (docType) {
            case PDF:
                exporter = new JRPdfExporter();
                break;
            case HTML:
                exporter = new HtmlExporter();
                break;
            case XLS:
                exporter = new JRXlsExporter();
                break;
            case XLSX:
                exporter = new JRXlsxExporter();
                break;
            case XML:
                exporter = new JRXmlExporter();
                break;
            case RTF:
                exporter = new JRRtfExporter();
                break;
            case CSV:
                exporter = new JRCsvExporter();
                break;
            case DOC:
                exporter = new JRRtfExporter();
                break;
            case TXT:
                exporter = new JRTextExporter();
                break;
            default:
                throw new ServiceException("格式错误!");
        }
        return exporter;
    }


    /**
     * 生成不同格式报表文档(带缓存)
     *
     * @param docType
     *            文档类型
     * @param jasperPath
     */
    @SuppressWarnings("deprecation")
    public void createExportDocument(DocType docType, String jasperPath, Map<String, Object> parameters,
                                     String fileName,Connection connection) throws JRException, IOException, ServletException, SQLException {

        //1、传入类型,获取输出器
        JRAbstractExporter exporter = getJRExporter(docType);

        // 2、获取后缀
        String ext = docType.toString().toLowerCase();

        if (!fileName.toLowerCase().endsWith(ext)) {
            fileName += "." + ext;
        }


        // 3、判断资源类型
        if ("xls".equals(ext)) {
            SimpleXlsReportConfiguration configuration = new SimpleXlsReportConfiguration();
            // 删除记录最下面的空行
            configuration.setRemoveEmptySpaceBetweenRows(Boolean.TRUE);
            // 一页一个sheet
            configuration.setOnePagePerSheet(Boolean.FALSE);
            // 显示边框  背景白色
            configuration.setWhitePageBackground(Boolean.FALSE);
            exporter.setConfiguration(configuration);
        }
        if("xlsx".equals(ext)) {
            SimpleXlsxReportConfiguration configuration = new SimpleXlsxReportConfiguration();
            configuration.setRemoveEmptySpaceBetweenRows(Boolean.TRUE);
            configuration.setRemoveEmptySpaceBetweenColumns(Boolean.TRUE);
            configuration.setWhitePageBackground(Boolean.FALSE);
            //自动选择格式
            configuration.setDetectCellType(Boolean.TRUE);
            exporter.setConfiguration(configuration);
        }
        if ("txt".equals(ext)) {
            SimpleTextReportConfiguration configuration = new SimpleTextReportConfiguration();
            configuration.setCharWidth((float)8);
            configuration.setCharHeight((float)15);
            exporter.setConfiguration(configuration);
        }

        //4、设置格式和头
        response.setContentType(getContentType(docType));
        response.setHeader("Content-Disposition",
                "attachment; filename*=UTF-8''" + URLEncoder.encode(fileName, "UTF-8"));

        //5、加缓存
        JRFileVirtualizer virtualizer = new JRFileVirtualizer(2, "D:/temp");
        parameters.put(JRParameter.REPORT_VIRTUALIZER, virtualizer);
        virtualizer.setReadOnly(true);

        //6、连接数据库获取jasperPrint
        exporter.setExporterInput(new SimpleExporterInput(getJasperPrint(jasperPath, parameters, connection)));
		/*exporter.setParameter(JRExporterParameter.JASPER_PRINT,
				getJasperPrintWithBeanList(jasperPath, parameters, list));*/

        OutputStream outStream = null;
        PrintWriter outWriter = null;

        // 7、解决中文乱码问题
        response.setCharacterEncoding("UTF-8");
        if ("csv".equals(ext) || "doc".equals(ext) || "rtf".equals(ext) || "txt".equals(ext)) {
            outWriter = response.getWriter();
            SimpleWriterExporterOutput outPut = new SimpleWriterExporterOutput(outWriter);
            exporter.setExporterOutput(outPut);
            //exporter.setParameter(JRExporterParameter.OUTPUT_WRITER, outWriter);
        } else {
            if("xml".equals(ext)) {
                outWriter = response.getWriter();
                XmlExporterOutput outPut  = new SimpleXmlExporterOutput(outWriter);
                exporter.setExporterOutput(outPut);
            }else if("html".equals(ext)){
                outWriter = response.getWriter();
                HtmlExporterOutput outPut = new SimpleHtmlExporterOutput(outWriter);
                exporter.setExporterOutput(outPut);
            }else {
                outStream = response.getOutputStream();
                exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(outStream));
            }
        }
        try {
            exporter.exportReport();
            virtualizer.cleanup();
        } catch (JRException e) {
            throw new ServletException(e);
        } finally {
            if (outStream != null) {
                try {
                    outStream.close();
                } catch (IOException ex) {
                }
            }
            if(outWriter != null) {
                outWriter.close();
            }
        }
    }


    /**
     * 输出以分页的形式输出html
     * @param jasperPrint
     * @param pageStr
     * @throws JRException
     * @throws IOException
     */

    public void createHtmlByPage(JasperPrint jasperPrint,String pageStr) throws JRException, IOException {
        int pageIndex = 0;
        int lastPageIndex = 0;

        HtmlExporter exporter = new HtmlExporter();
        if(null != jasperPrint.getPages()) {
            lastPageIndex = jasperPrint.getPages().size() - 1;
        }

        if(null == pageStr) {
            pageStr = "0";
        }
        try {
            pageIndex = Integer.valueOf(pageStr);
            if(pageIndex > 0) {
                pageIndex = pageIndex -1 ;
            }
        } catch (Exception e) {
            // 如果得到的非数字字符串
            if("lastPage".equals(pageStr)) {
                pageIndex = lastPageIndex;
            }
        }

        if (pageIndex < 0) {
            pageIndex = 0;
        }
        if (pageIndex > lastPageIndex) {
            pageIndex = lastPageIndex;
        }
        response.setCharacterEncoding("UTF-8");
        try {
            PrintWriter out = response.getWriter();
            exporter.setExporterInput(new SimpleExporterInput(jasperPrint));

            SimpleHtmlReportConfiguration configuration =  new SimpleHtmlReportConfiguration();
            configuration.setPageIndex(pageIndex);
            exporter.setConfiguration(configuration);
            //exporter.setParameter(JRHtmlExporterParameter.IS_USING_IMAGES_TO_ALIGN, Boolean.FALSE);

            HtmlExporterOutput outPut = new SimpleHtmlExporterOutput(out);
            exporter.setExporterOutput(outPut);

            exporter.exportReport();
        } catch (Exception e) {

            e.printStackTrace();
        }
    }


    /**
     * 批量打印pdf文件
     */
    public void exportBatchPdf(List<JasperPrint> jasperPrintList,String fileName) {

        JRPdfExporter exporter =  new JRPdfExporter();
        try {
            /**
             * 注入打印模板
             */
            exporter.setExporterInput(SimpleExporterInput.getInstance(jasperPrintList));

            OutputStream outStream = null;

            response.setContentType(getContentType(DocType.PDF));
            response.setHeader("Content-Disposition",
                    "attachment; filename*=UTF-8''" + URLEncoder.encode(fileName, "UTF-8"));
            outStream = response.getOutputStream();

            exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(outStream));
            //配置项
            SimplePdfExporterConfiguration configuration = new SimplePdfExporterConfiguration();
            // 是否批量打印
            configuration.setCreatingBatchModeBookmarks(true);
            // 是否加密
            configuration.setEncrypted(false);
            exporter.setConfiguration(configuration);

            exporter.exportReport();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }



    /**
     * 千分位格式化数据 保留两位小数,且 ‘0 ’ 转为 ‘--’
     *
     * @param obj
     * @param fieldNames
     *            需转化的属性
     * @return
     */
    public Object toFormatNumber(Object obj, String[] fieldNames) {
        Class clazz = (Class) obj.getClass();
        Field[] fs = clazz.getDeclaredFields();
        for (int i = 0; i < fs.length; i++) {
            Field f = fs[i];
            // 设置些属性是可以访问的
            f.setAccessible(true);
            String type = f.getType().toString();
            Object val = null;

            try {
                for (String str : fieldNames) {
                    if (f.getName() == str) {
                        val = f.get(obj);
                    }
                }
                if (null != val) {
                    if (type.endsWith("String")) {
                        if ("0".equals(val)) {
                            f.set(obj, "--");
                        } else {
                            /*
                             * ; BigDecimal str=new BigDecimal((String) val); DecimalFormat df=new
                             * DecimalFormat(",###,##0.00");
                             */ // 保留两位小数
                            f.set(obj, this.toNumeber((String) val));
                        }

                    } else if (type.endsWith("int") || type.endsWith("Integer")) {
                        // System.out.println(f.getType()+"\t");
                    } else {
                        // System.out.println(f.getType()+"\t");
                    }
                }

            } catch (Exception ex) {
                LOGGER.error("千分位格式化数据错误"+ex.getMessage(), ex);
            }
        }
        return obj;
    }

    /**
     * 转为万元保留小数点后两位
     *
     * @param value
     * @return
     */
    private String toNumeber(String value) {
        Double number = Double.valueOf(value) / 10000.00;
        BigDecimal str = new BigDecimal(number);
        DecimalFormat df = new DecimalFormat(",###,##0.00");

        return df.format(str);
    }


}