package com.uas.report.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 压缩工具类
 * 
 * @author sunyj
 * @since 2016年11月1日 下午4:51:38
 */
public class ZipUtils {

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

	/**
	 * 压缩文件夹
	 * 
	 * @param sourceFolderPath
	 *            将压缩的文件夹
	 * @param fileFilter
	 *            文件过滤器，不压缩某些文件
	 * @return 压缩后的数据
	 * @throws IOException
	 */
	public static byte[] zipFolder(String sourceFolderPath, FileFilter fileFilter) throws IOException {
		if (StringUtils.isEmpty(sourceFolderPath)) {
			return null;
		}
		File folder = new File(sourceFolderPath);
		if (!folder.exists() || !folder.isDirectory()) {
			throw new IOException("路径不存在或并非文件夹：" + sourceFolderPath);
		}
		File[] files = folder.listFiles();
		if (files.length < 0) {
			throw new IOException("空文件夹：" + sourceFolderPath);
		}

		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		byte[] zipData = null;
		ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);
		putNextEntryFromFolder(zipOutputStream, folder, "", fileFilter);
		zipOutputStream.close();
		logger.info("Zip done");
		zipData = outputStream.toByteArray();
		outputStream.close();
		return zipData;
	}

	/**
	 * 压缩文件夹
	 * 
	 * @param sourceFolderPath
	 *            将压缩的文件夹
	 * @param zipFilePath
	 *            压缩后的压缩包路径
	 * @param fileFilter
	 *            文件过滤器，不压缩某些文件
	 * @throws IOException
	 */
	public static void zipFolder(String sourceFolderPath, String zipFilePath, FileFilter fileFilter)
			throws IOException {
		if (StringUtils.isEmpty(sourceFolderPath) || StringUtils.isEmpty(zipFilePath)) {
			return;
		}
		File folder = new File(sourceFolderPath);
		if (!folder.exists() || !folder.isDirectory()) {
			throw new IOException("路径不存在或并非文件夹：" + sourceFolderPath);
		}
		File[] files = folder.listFiles();
		if (files.length < 0) {
			throw new IOException("空文件夹：" + sourceFolderPath);
		}

		ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFilePath));
		putNextEntryFromFolder(zipOutputStream, folder, "", fileFilter);
		zipOutputStream.close();
		logger.info("Zip finished to... " + zipFilePath);
	}

	/**
	 * 递归将文件夹下的文件进行压缩
	 * 
	 * @param zipOutputStream
	 *            压缩包的输出流
	 * @param folder
	 *            需要压缩的文件夹
	 * @param prefix
	 *            为保持压缩后的路径层次不变，所记录的当前文件夹的相对层级
	 * @param fileFilter
	 *            文件过滤器，不压缩某些文件
	 * @throws IOException
	 */
	private static void putNextEntryFromFolder(ZipOutputStream zipOutputStream, File folder, String prefix,
			FileFilter fileFilter) throws IOException {
		File[] files = folder.listFiles();
		for (File file : files) {
			if (file.isDirectory()) {
				putNextEntryFromFolder(zipOutputStream, file, prefix + file.getName() + File.separator, fileFilter);
			} else {
				// 过滤某些文件
				if (fileFilter != null && !fileFilter.accept(file)) {
					continue;
				}
				zipOutputStream.putNextEntry(new ZipEntry(prefix + file.getName()));
				InputStream inputStream = new FileInputStream(file);
				int b;
				while ((b = inputStream.read()) != -1) {
					zipOutputStream.write(b);
				}
				inputStream.close();
			}
			logger.info("Ziped from... " + file.getPath());
		}
	}

	/**
	 * 解压缩
	 * 
	 * @param zipData
	 *            压缩包数据
	 * @param folderPath
	 *            解压缩后的文件路径
	 * @throws IOException
	 */
	public static void unzip(byte[] zipData, String folderPath) throws IOException {
		if (StringUtils.isEmpty(folderPath)) {
			return;
		}

		ZipInputStream zipInputStream = new ZipInputStream(new ByteArrayInputStream(zipData));
		ZipEntry zipEntry;
		while ((zipEntry = zipInputStream.getNextEntry()) != null) {
			File outFile = new File(folderPath + File.separator + zipEntry.getName());
			logger.info("Unzipping to... " + outFile.getPath());
			if (zipEntry.isDirectory()) {
				if (!outFile.exists()) {
					outFile.mkdirs();
				}
				continue;
			}
			if (!outFile.getParentFile().exists()) {
				outFile.getParentFile().mkdirs();
			}

			OutputStream outputStream = new FileOutputStream(outFile);
			int b;
			while ((b = zipInputStream.read()) != -1) {
				outputStream.write(b);
			}
			outputStream.close();
		}
		zipInputStream.close();
		logger.info("Unzip done");
	}

	/**
	 * 解压缩
	 * 
	 * @param zipFilePath
	 *            将解压缩的压缩包路径
	 * @param zipFilePath
	 *            解压缩后的文件路径
	 * @throws IOException
	 */
	public static void unzip(String zipFilePath, String folderPath) throws IOException {
		if (StringUtils.isEmpty(zipFilePath) || StringUtils.isEmpty(folderPath)) {
			return;
		}
		File file = new File(zipFilePath);
		if (!file.exists()) {
			throw new FileNotFoundException("压缩包不存在：" + zipFilePath);
		}

		File folder = new File(folderPath);
		if (!folder.exists()) {
			folder.mkdirs();
		}
		if (!folder.isDirectory()) {
			throw new IOException("并非文件夹：" + folderPath);
		}

		ZipFile zipFile = new ZipFile(file);
		Enumeration<? extends ZipEntry> zipEntries = zipFile.entries();
		while (zipEntries.hasMoreElements()) {
			ZipEntry zipEntry = zipEntries.nextElement();
			if (zipEntry.isDirectory()) {
				continue;
			}
			InputStream inputStream = zipFile.getInputStream(zipEntry);
			File outFile = new File(folder.getPath() + File.separator + zipEntry.getName());
			if (!outFile.getParentFile().exists()) {
				outFile.getParentFile().mkdirs();
			}

			String fileName = folder.getPath() + File.separator + zipEntry.getName();
			OutputStream outputStream = new FileOutputStream(fileName);
			int b;
			while ((b = inputStream.read()) != -1) {
				outputStream.write(b);
			}
			inputStream.close();
			outputStream.close();
		}
		zipFile.close();
		logger.info("Unzip finished from... " + zipFilePath);
	}
}
