/**
 * 
 */
package com.yonge.toolset.utils.compress;

import java.io.BufferedOutputStream;
import java.io.File;
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.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import com.yonge.toolset.base.exception.UtilException;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;



/**
 * 工具类，Zip解压缩类 <br>
 * Copyright <a href="http://www.erayt.com/" target="_blank">erayt.com</a>(c)<br>
 * 
 * @author GuoZheyong
 * @version 2011-7-15
 */
public final class ZipUtil {

	private final static Logger LOGGER = LoggerFactory.getLogger(ZipUtil.class);

	private static final int BUFFER = 2048;

	private static ZipUtil util = new ZipUtil();

	/**
	 * 获取ZipUtil单例
	 * 
	 * @return 实例
	 */
	public static ZipUtil getInstance() {
		return util;
	}

	private ZipOutputStream out;

	private ZipUtil() {
	}

	/**
	 * 压缩单个文件或文件夹
	 * 
	 * @param fromFile
	 *            待压缩文件，fromFile是绝对路径
	 * @param toFile
	 *            压缩文件，toFile是绝对路径
	 * @throws IOException
	 *             如果发生 I/O 错误
	 */
	public void zipDirectoryOrFile(String fromFile, String toFile) throws IOException {
		try {
			init(toFile);
			File file = new File(fromFile);
			writeEntry(out, file, "");
		} finally {
			destroy();
		}
	}

	/**
	 * 压缩多个文件或文件夹
	 * 
	 * @param fromFile
	 *            待压缩文件数组
	 * @param toFile
	 *            压缩文件
	 * @throws IOException
	 *             如果发生 I/O 错误
	 */
	public void zipMultiFile(String fromFile[], String toFile) throws IOException {
		try {
			init(toFile);
			File file = null;
			for (int i = 0; i < fromFile.length; i++) {
				file = new File(fromFile[i]);
				writeEntry(out, file, "");
			}
		} finally {
			destroy();
		}
	}

	private void init(String toFile) {
		try {
			LOGGER.info("compress " + toFile);
			FileOutputStream fos = new FileOutputStream(toFile);
			out = new ZipOutputStream(new BufferedOutputStream(fos));
		} catch (FileNotFoundException e) {
			LOGGER.warn("初始化得到zip文件异常", e);
			throw new UtilException(e.getMessage(), e);
		}
	}

	private void destroy() throws IOException {
		if (out != null) {
			out.close();
		}
	}

	private void writeEntry(ZipOutputStream zos, File srcFile, String baseURL) throws IOException {

		baseURL = baseURL == null || baseURL.length() == 0 ? srcFile.getName() : baseURL + "/" + srcFile.getName();
		if (srcFile.isDirectory()) {
			File[] files = srcFile.listFiles();
			if (files != null && files.length > 0) {
				for (File f : files) {
					writeEntry(zos, f, baseURL);
				}
			} else {
				zos.putNextEntry(new ZipEntry(baseURL + "/"));
			}
		} else {
			zos.putNextEntry(new ZipEntry(baseURL));

			FileInputStream fileInputStream = null;
			try {
				// 读数据
				fileInputStream = new FileInputStream(srcFile);
				byte[] bytes = new byte[BUFFER];
				int length = -1;
				while ((length = fileInputStream.read(bytes)) != -1) {
					zos.write(bytes, 0, length);
				}
			} finally {
				if (fileInputStream != null) {
					fileInputStream.close();
				}
			}
		}
	}

	/**
	 * 解压zip包
	 * @param inputStream
	 * @param outputFolder
	 * @return
	 * @throws IOException
	 */
	public static List<File> unCompressZipFile(InputStream inputStream, String outputFolder) {
		List<File> files = new ArrayList<File>();
		ZipInputStream zis = null;
		try {
			Charset utf = Charset.forName("utf-8");
			zis = new ZipInputStream(inputStream, utf);
			ZipEntry entry;
			while ((entry = zis.getNextEntry()) != null) {
				String encoding = System.getProperty("file.encoding");
				String fileName = new String(entry.getName().getBytes("GBK"), encoding);
				File entryFile = new File(outputFolder, fileName);
				if (entry.isDirectory()) {
					if (entryFile.exists()) {
						throw new UtilException("目录已存在", entryFile);
					} else {
						entryFile.mkdirs();
					}
				} else {
					if (entryFile.getParentFile() != null && !entryFile.getParentFile().exists()) {
						entryFile.getParentFile().mkdirs();
					}
					if (!entryFile.exists()) {
						entryFile.createNewFile();
					}
					OutputStream os = null;
					try {
						os = new FileOutputStream(entryFile);
						IOUtils.copy(zis, os);
					} finally {
						IOUtils.closeQuietly(os);
						zis.closeEntry();
					}
				}
				files.add(entryFile);
			}
		} catch (Exception e) {
			throw new UtilException("解压失败", e);
		} finally {
			IOUtils.closeQuietly(zis);
		}
		return files;
	}

	 public static void main(String [] args) throws IOException
	 {
	 final String INPUT_ZIP_FILE = "d:/anypipe/测试.zip";
	 String OUTPUT_FOLDER = "d:/test-gzip/anypipe";
	
	 File file = new File(INPUT_ZIP_FILE);
	 InputStream inputStream = new FileInputStream(file);
	
	 OUTPUT_FOLDER += File.separator + file.getName();
	
	 unCompressZipFile(inputStream, OUTPUT_FOLDER);
	
	 /*File file = new File(OUTPUT_FOLDER);
	 FileUtil.deleteFolder(file);*/
	 }

}
