package com.ruoyi.common.utils.document;

import com.ruoyi.framework.web.domain.AjaxResult;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 压缩工具Util
 */
public class ZipUtil {

    /**
     * 创建zip文件并用流方式返回浏览器下载
     *
     * @param filePath  需压缩的文件路径
     * @param folder    文件上层目录，用于区分多次下载
     * @param zipName   zip压缩包文件名
     * @param fileNames 目录下文件绝对路径集合
     * @param response
     * @throws Exception
     */
    public static AjaxResult createZip(String filePath, String folder, String zipName, List<String> fileNames, HttpServletResponse response) throws Exception {
        OutputStream out = null;
        ByteArrayOutputStream baos = new ByteArrayOutputStream(1000);
        List<File> fileList = new ArrayList<>();
        for (String fileName : fileNames) {
            File file = new File(filePath + "/" + folder + "/" + fileName);
            fileList.add(file);
        }
        String zip = filePath + folder + "/" + zipName;
        try {
            File file = new File(filePath + "/" + folder);
            if (!file.isDirectory()) {
                file.mkdir();
            }
            File zipFile = new File(zip);
            if (!zipFile.exists()) {
                zipFile.createNewFile();
            }
            // 将package.zip的File对象传到toZip对象中
            toZip(fileList, zipFile);
            //把指定文件提取成流
            FileInputStream fis = new FileInputStream(zip);
            // 设置响应消息头，告诉浏览器当前响应是一个下载文件
            response.setContentType("application/x-msdownload");
            // 告诉浏览器，当前响应数据要求用户干预保存到文件中，以及文件名是什么 如果文件名有中文，必须URL编码
            String fileName = URLEncoder.encode(zipName, "UTF-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            out = response.getOutputStream();
            byte[] b = new byte[1000];
            int n;
            while ((n = fis.read(b)) != -1) {
                baos.write(b, 0, n);
            }
            fis.close();
            baos.writeTo(out);
            baos.close();
            return AjaxResult.success(zipName);
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("导出失败：" + e.getMessage());
        } finally {
            if (baos != null) {
                baos.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }

    /**
     * 把文件集合打成zip压缩包
     *
     * @param srcFiles 压缩文件集合
     * @param zipFile  zip文件名
     * @throws RuntimeException 异常
     */
    public static void toZip(List<File> srcFiles, File zipFile) throws IOException {
        if (zipFile == null) {
            return;
        }
        if (!zipFile.getName().endsWith(".zip")) {
            return;
        }
        ZipOutputStream zos = null;
        FileOutputStream out = new FileOutputStream(zipFile);
        try {
            zos = new ZipOutputStream(out);
            for (File srcFile : srcFiles) {
                byte[] buf = new byte[128];
                zos.putNextEntry(new ZipEntry(srcFile.getName()));
                int len;
                // 读取文件并写入到zip中
                FileInputStream in = new FileInputStream(srcFile);
                while ((len = in.read(buf)) != -1) {
                    zos.write(buf, 0, len);
                    zos.flush();
                }
                in.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (zos != null) {
                zos.close();
            }
        }
    }

    public static void toZipWithDirectory(String sourceFile, String outputFile) throws IOException {
        FileOutputStream fos = new FileOutputStream(outputFile);
        ZipOutputStream zos = new ZipOutputStream(fos);
        FileInputStream in = null;

        try {
            createZipWithDirectory(new File(sourceFile), zos, "");
        } finally {
            if (in != null) {
                in.close();
            }
            zos.close();
            fos.close();
        }
    }

    private static void createZipWithDirectory(File file, ZipOutputStream zos, String dir) throws IOException {
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) {
                createZipWithDirectory(f, zos, dir + file.getName() + "/");
            }
        } else {
            FileInputStream fis = new FileInputStream(file);
            ZipEntry zipEntry = new ZipEntry(dir + file.getName());
            zos.putNextEntry(zipEntry);

            byte[] buffer = new byte[1024];
            int length;
            while ((length = fis.read(buffer)) > 0) {
                zos.write(buffer, 0, length);
            }

            zos.closeEntry();
            fis.close();
        }
    }
}
