package com.bcxin.identify.util.file;

import cn.hutool.core.io.FileUtil;
import com.bcxin.identify.util.common.StringUtil;
import com.google.common.collect.Lists;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.List;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;

public class ZipCompressor {

	private static Logger log = LoggerFactory.getLogger(ZipCompressor.class);

	static final int BUFFER = 8192;
	private File zipFile;

	/**
	 * 压缩文件构造函数
	 * @param pathName 压缩的文件存放目录
	 */
	public ZipCompressor(String pathName) {
		zipFile = new File(pathName);
	}

	/**
	 * 执行压缩操作
	 * @param srcPathName 被压缩的文件/文件夹
	 */
	public void compressSingle(String srcPathName) {
		File file = new File(srcPathName);
		if (!file.exists()){
			throw new RuntimeException(srcPathName + "不存在！");
		}
		try {
			FileOutputStream fileOutputStream = new FileOutputStream(zipFile);
			CheckedOutputStream cos = new CheckedOutputStream(fileOutputStream,new CRC32());
			ZipOutputStream out = new ZipOutputStream(cos);
			String basedir = "";
			compressByType(file, out, basedir);
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
			log.error("执行压缩操作时发生异常:"+e);
			throw new RuntimeException(e);
		}
	}


	/**
	 * 执行压缩操作
	 * @param filePaths 被压缩的文件/文件夹集合
	 */
	public void compressFileList(List<String> filePaths) {
		//过滤有文件的地址
		List<File> files = Lists.newArrayList();
		for (String filePath : filePaths) {
			if (StringUtil.isNotEmpty(filePath)){
				File policyFile = new File(filePath);
				if(policyFile.exists()) {
					files.add(policyFile);
				}
			}
		}

		try {
			FileOutputStream fileOutputStream = new FileOutputStream(zipFile);
			CheckedOutputStream cos = new CheckedOutputStream(fileOutputStream,new CRC32());
			ZipOutputStream out = new ZipOutputStream(cos);

			for (File file : files) {
				String basedir = "";
				compressByType(file, out, basedir);
			}
			out.close();

		} catch (Exception e) {
			e.printStackTrace();
			log.error("执行压缩操作时发生异常:"+e);
			throw new RuntimeException(e);
		}

		//删除Zip之外的已经打包好的源文件
		String fileFolder = "";
		for (File file : files) {
			if (StringUtil.isEmpty(fileFolder)) {
				fileFolder = file.getParent();
			}
			if (file.isFile() && file.exists()) {
				log.debug("删除文件[{}]",file.getPath());
				file.delete();
			}
			if (file.isDirectory()) {
				log.debug("删除文件夹[{}]",file.getPath());
				BcxinFileUtils.deleteFolder(file);
			}
		}
		/* 删除文件夹 */
		if (StringUtil.isNotEmpty(fileFolder)) {
			FileUtil.del(fileFolder);
		}
	}

	/**
	 * 判断是目录还是文件，根据类型（文件/文件夹）执行不同的压缩方法
	 * @param file
	 * @param out
	 * @param basedir
	 */
	private void compressByType(File file, ZipOutputStream out, String basedir) {
        /* 判断是目录还是文件 */
		if (file.isDirectory()) {
			log.info("压缩：" + basedir + file.getName());
			this.compressDirectory(file, out, basedir);
		} else {
			log.info("压缩：" + basedir + file.getName());
			this.compressFile(file, out, basedir);
		}
	}

	/**
	 * 压缩一个目录
	 * @param dir
	 * @param out
	 * @param basedir
	 */
	private void compressDirectory(File dir, ZipOutputStream out, String basedir) {
		if (!dir.exists()){
			return;
		}

		File[] files = dir.listFiles();
		if (files.length == 0) { //空文件夹
			try {
				ZipEntry zipEntry = new ZipEntry(dir.getName() + "/");
				out.putNextEntry(zipEntry);
				out.closeEntry();
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
		for (int i = 0; i < files.length; i++) {
            /* 递归 */
			compressByType(files[i], out, basedir + dir.getName() + "/");
		}
	}

	/**
	 * 压缩一个文件
	 * @param file
	 * @param out
	 * @param basedir
	 */
	private void compressFile(File file, ZipOutputStream out, String basedir) {
		if (!file.exists()) {
			return;
		}
		try {
			BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
			ZipEntry entry = new ZipEntry(basedir + file.getName());
			out.putNextEntry(entry);
			int count;
			byte data[] = new byte[BUFFER];
			while ((count = bis.read(data, 0, BUFFER)) != -1) {
				out.write(data, 0, count);
			}
			bis.close();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}


	public static void main(String[] args) {
		ZipCompressor zc = new ZipCompressor("d:\\szhzip2.zip");
		List<String> filePath = Lists.newArrayList();
		filePath.add("D:\\_act_23494896_t_20170822094542\\2应急预案大多数");
		filePath.add("D:\\_act_23494896_t_20170822094542\\附件");
		filePath.add("D:\\_act_23494896_t_20170822094542\\安全保卫工作方案.docx");
		filePath.add("D:\\_act_23494896_t_20170822094542\\安全工作方案.doc");
		zc.compressFileList(filePath);
	}

}
