package com.pcloud.common.utils.export.word;

import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Random;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.pcloud.common.entity.UploadResultInfo;
import com.pcloud.common.utils.FileUtils;
import com.pcloud.common.utils.aliyun.OssUtils;
import freemarker.template.Configuration;
import freemarker.template.Template;

/**
 * @描述：Word数据导出工具
 * @作者：linweibin
 * @创建时间：2017年4月19日 上午10:55:56 @版本：1.0
 */
public class WordDataExportor {

    private static final Logger logger = LoggerFactory.getLogger(WordDataExportor.class);

    /**
     * 生成word
     * @param response
     * @param fileName
     * @param dataMap
     * @param templateName
     * @author linweibin
     * @date 2017年4月19日 下午4:44:45
     */
    public static void exportWord(Class clazz, HttpServletResponse response, String fileName, Map<String, Object> dataMap,
            String templateName) {
        // 生成word
        String tempFileName = generateWord(clazz, dataMap, templateName);
        // 下载word
        downLoadWord(response, fileName, tempFileName);
    }

    /**
     * 生成word
     * @author gaopeng
     * @date 2018-3-21 16:48:41
     */
    public static void exportWord(Class clazz, HttpServletRequest request, HttpServletResponse response, String fileName, Map<String, Object> dataMap,
            String templateName) {
        // 生成word
        String tempFileName = generateWord(clazz, dataMap, templateName);
        // 下载word
        downLoadWord(request, response, fileName, tempFileName);
    }

    /**
     * 上传word并获取url
     * @param dataMap
     * @param templateName
     * @return
     * @author linweibin
     * @date 2017年5月22日 下午5:34:43
     */
    public static String uploadWord(Class clazz, Map<String, Object> dataMap, String templateName) {
        // 生成word
        String tempFileName = generateWord(clazz, dataMap, templateName);
        // 上传word
        String fileUrl = uploadFile(tempFileName);
        logger.info("文件上传后返回的url=" + fileUrl);
        return fileUrl;
    }

    /**
     * 生成word
     * @param dataMap
     * @param templateName
     * @return
     * @author linweibin
     * @date 2017年5月22日 下午5:22:38
     */
    @SuppressWarnings("deprecation")
    private static String generateWord(Class clazz, Map<String, Object> dataMap, String templateName) {
        logger.info("开始生成word+++");
        // 文件名称
        String tempFileName = getRandomFileName() + ".doc";

        try {
            // 创建配置实例
            Configuration configuration = new Configuration();

            // 设置编码
            configuration.setDefaultEncoding("UTF-8");

            // 获取template文件路径
            configuration.setClassForTemplateLoading(clazz, "/template");

            // 获取模板
            Template template = configuration.getTemplate(templateName);

            // 输出文件
            File outFile = new File(tempFileName);

            // 将模板和数据模型合并生成文件
            Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "UTF-8"));

            // 生成文件
            template.process(dataMap, out);
            logger.info("生成word+++成功");
            // 关闭流
            out.flush();
            out.close();
        } catch (Exception e) {
            logger.error("生成word异常+++" + e.getMessage(), e);
        }
        return tempFileName;
    }

    /**
     * 生成随机文件名
     * @return
     * @author linweibin
     * @date 2017年4月19日 下午4:21:50
     */
    public static String getRandomFileName() {
        logger.info("开始生成随机文件名+++");
        Random r = new Random();
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyMMdd_HHmmss_SSS");
        StringBuffer sb = new StringBuffer();
        sb.append(sdf1.format(new Date()));
        sb.append("_");
        sb.append(r.nextInt(100));
        logger.info("生成随机文件名+++成功" + sb.toString());
        return sb.toString();
    }

    /**
     * 读取并删除文件
     * @param filePath
     * @return
     * @author linweibin
     * @date 2017年4月19日 下午4:33:59
     */
    public static byte[] readFileToByte(String filePath) {
        logger.info("开始读取文件+++");
        byte[] buffer = null;
        try {
            File excelFile = new File(filePath);
            FileInputStream fis = new FileInputStream(excelFile);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            byte[] b = new byte[1024];
            int n;
            while ((n = fis.read(b)) != -1) {
                bos.write(b, 0, n);
            }
            fis.close();
            bos.close();
            buffer = bos.toByteArray();
            logger.info("读取文件+++成功");
            logger.info("开始删除文件+++");
            // 删除文件
            excelFile.delete();
            logger.info("删除文件成功+++");
        } catch (FileNotFoundException e) {
            logger.error("读取并删除文件异常+++" + e.getMessage(), e);
            e.printStackTrace();
        } catch (IOException e) {
            logger.error("读取并删除文件异常+++" + e.getMessage(), e);
            e.printStackTrace();
        }
        return buffer;
    }

    /**
     * 下载word
     * @param response
     * @param fileName
     * @param tempFileName
     * @author linweibin
     * @date 2017年4月19日 下午4:35:58
     */
    public static void downLoadWord(HttpServletResponse response, String fileName, String tempFileName) {
        logger.info("开始下载word+++");
        // 文件名去空格
        fileName = fileName.replace(" ", "");
        byte[] dataByte = readFileToByte(tempFileName);
        response.setContentType("octets/stream");
        try {
            // 转码防止乱码
            response.addHeader("Content-Disposition",
                    "attachment;filename=" + new String(fileName.getBytes("gb2312"), "ISO8859-1") + ".doc");

            OutputStream outputStream = response.getOutputStream();
            outputStream.write(dataByte);
            logger.info("下载word+++成功");
            if (outputStream != null) {
                outputStream.close();
            }
        } catch (IOException e) {
            logger.error("下载word异常+++" + e.getMessage(), e);
            e.printStackTrace();
        }
    }

    /**
     * 下载word
     * @author gaopeng
     * @date 2018-3-21 16:48:41
     */
    public static void downLoadWord(HttpServletRequest request, HttpServletResponse response, String fileName, String tempFileName) {
        logger.info("开始下载word+++");
        // 文件名去空格
        fileName = fileName.replace(" ", "");
        byte[] dataByte = readFileToByte(tempFileName);
        response.setContentType("octets/stream");
        try {
            String userAgent = request.getHeader("User-Agent");
            if (userAgent.contains("MSIE") || userAgent.contains("Trident") || userAgent.contains("Edge")) {
                fileName = URLEncoder.encode(fileName, "UTF-8");
            } else {
                fileName = new String(fileName.getBytes("UTF-8"), "ISO8859-1");
            }
            response.addHeader("Content-Disposition",
                    "attachment;filename=" + fileName + ".doc");

            OutputStream outputStream = response.getOutputStream();
            outputStream.write(dataByte);
            logger.info("下载word+++成功");
            outputStream.close();
        } catch (IOException e) {
            logger.error("下载word异常+++" + e.getMessage(), e);
            e.printStackTrace();
        }
    }

    /**
     * 读取word后，上传文件服务器并删除
     * @param tempFileName
     * @param tempFileName
     * @author linweibin
     * @date 2017年4月19日 下午4:35:58
     */
    public static String uploadFile(String tempFileName) {
        logger.info("开始上传word+++");
        String fileName = FileUtils.getFileName(tempFileName);
        UploadResultInfo uploadResultInfo = OssUtils.uploadLocalFile(tempFileName, fileName);
        if (null != uploadResultInfo) {
            logger.info("上传文件服务器后，返回数据++++++++" + uploadResultInfo.toString());
        }
        File file = new File(tempFileName);
        logger.info("开始删除文件+++");
        // 删除文件
        file.delete();
        return uploadResultInfo.getUrl();
    }

}
