/*
 * Copyright 2000-2020 YGSoft.Inc All Rights Reserved.
 */
package com.ygsoft.ecp.app.mappcore.impl.util;

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.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import com.ygsoft.ecp.service.log.EcpLogFactory;
import com.ygsoft.ecp.service.log.IEcpLog;

/**
 * 文件压缩,解压处理.<br>
 *
 * @author mapengfei <br>
 * @version 1.0.0 2016年4月14日<br>
 * @see
 * @since JDK 1.5.0
 */
public class ZipMultiFile {

    /**
     * 日志文件
     */
    private static final IEcpLog LOG = EcpLogFactory.getLog(ZipMultiFile.class);
    /**
     * 取得当前文件编码格式
     */
    private static String encoding = System.getProperty("file.encoding");
    /**
     * 文件压缩格式
     */
    public  static final String ZIP_MULTI_FILE_TIPE = ".zip";

    /**
     * 压缩
     *
     * @param zipFileName
     *            压缩产生的zip包文件名--带路径,如果为null或空则默认按文件名生产压缩文件名
     * @param relativePath
     *            相对路径,默认为空
     * @param directory
     *            文件或目录的绝对路径
     * @throws FileNotFoundException
     * @throws IOException
     * @author mapengfei
     * @date 2016-04-14
     */
    public static void zip(final String zipFileName, final String relativePath, final String directory)
            throws FileNotFoundException, IOException {
        String fileName = zipFileName;
        if (fileName == null || fileName.trim().equals("")) {
            File temp = new File(directory);
            if (temp.isDirectory()) {
                fileName = directory + ".zip";
            } else {
                if (directory.indexOf(".") > 0) {
                    fileName = directory.substring(0, directory.lastIndexOf(".")) + "zip";
                } else {
                    fileName = directory + ".zip";
                }
            }
        }
        ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new String(fileName.getBytes(encoding),"iso-8859-1")));
        try {
            zip(zos, relativePath, directory);
        } catch (IOException ex) {
            if (LOG.isDebugEnabled()) {
                LOG.info("压缩文件出现异常");
            }
            LOG.error(ex);
        } finally {
            if (null != zos) {
                zos.close();
            }
        }
    }

    /**
     * 压缩
     *
     * @param zos
     *            压缩输出流
     * @param relativePath
     *            相对路径
     * @param absolutPath
     *            文件或文件夹绝对路径
     * @throws IOException
     * @author mapengfei
     * @date 2016-04-14
     */
    private static void zip(final ZipOutputStream zos, final String relativePath, final String absolutPath)
            throws IOException {
        File file = new File(absolutPath);
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (int i = 0; i < files.length; i++) {
                File tempFile = files[i];
                if (tempFile.isDirectory()) {
                    String newRelativePath = relativePath + tempFile.getName() + File.separator;
                    createZipNode(zos, newRelativePath);
                    zip(zos, newRelativePath, tempFile.getPath());
                } else {
                    zipFile(zos, tempFile, relativePath);
                }
            }
        } else {
            zipFile(zos, file, relativePath);
        }
    }

    /**
     * 压缩文件
     *
     * @param zos
     *            压缩输出流
     * @param file
     *            文件对象
     * @param relativePath
     *            相对路径
     * @throws IOException
     * @author mapengfei
     * @date 2016-04-14
     */
    private static void zipFile(final ZipOutputStream zos, final File file, final String relativePath)
            throws IOException {
        if (file.isFile()) {
            ZipEntry entry = new ZipEntry(relativePath + new String(file.getName().getBytes(encoding), "iso-8859-1"));
            zos.putNextEntry(entry);
            InputStream input = null;
            try {
                input = new FileInputStream(file);
                int temp = 0;
                while ((temp = input.read()) != -1) {
                    zos.write(temp);
                }
                zos.flush();
                zos.closeEntry();
            } catch (IOException ex) {
                if (LOG.isDebugEnabled()) {
                    LOG.info("文件爱你压缩失败,文件名:" + file.getName());
                }
                LOG.error(ex);
            } finally {
                input.close();
            }
        }
    }

    /**
     * 生产文件 如果文件所在路径不存在则生成路径
     *
     * @param fileName
     *            文件名 带路径
     * @param isDirectory
     *            是否为路径
     * @return
     * @author mapengfei
     * @date 2016-4-14
     */
    @SuppressWarnings("rawtypes")
    public static void unzip(final String zipFilePath, final String targetPath) throws IOException {
        OutputStream os = null;
        InputStream is = null;
        ZipFile zipFile = null;
        try {
            zipFile = new ZipFile(zipFilePath);
            String directoryPath = "";
            if (null == targetPath || "".equals(targetPath)) {
                directoryPath = zipFilePath.substring(0, zipFilePath.lastIndexOf("."));
            } else {
                directoryPath = targetPath;
            }
            Enumeration entryEnum = zipFile.entries();
            if (null != entryEnum) {
                ZipEntry zipEntry = null;
                while (entryEnum.hasMoreElements()) {
                    zipEntry = (ZipEntry) entryEnum.nextElement();
                    if (zipEntry.isDirectory()) {
                        directoryPath = directoryPath + File.separator + zipEntry.getName();
                        if(LOG.isDebugEnabled()){
                            LOG.info(directoryPath);
                        }
                        continue;
                    }
                    if (zipEntry.getSize() > 0) {
                        // 文件
                        File targetFile = ZipMultiFile.buildFile(directoryPath + File.separator + new String(zipEntry.getName().getBytes(encoding),"iso-8859-1"),
                                false);
                        os = new BufferedOutputStream(new FileOutputStream(targetFile));
                        is = zipFile.getInputStream(zipEntry);
                        byte[] buffer = new byte[4096];
                        int readLen = 0;
                        while ((readLen = is.read(buffer, 0, 4096)) >= 0) {
                            os.write(buffer, 0, readLen);
                        }

                        os.flush();
                        os.close();
                    } else {
                        // 空目录
                        ZipMultiFile.buildFile(directoryPath + File.separator + zipEntry.getName(), true);
                    }
                }
            }
        } catch (IOException ex) {
            throw ex;
        } finally {
            if (null != zipFile) {
                zipFile = null;
            }
            if (null != is) {
                is.close();
            }
            if (null != os) {
                os.close();
            }
        }
    }

    /**
     * 生产文件 如果文件所在路径不存在则生成路径
     *
     * @param fileName
     *            文件名 带路径
     * @param isDirectory
     *            是否为路径
     * @return
     * @author mapengfei
     * @date 2016-4-14
     */
    public static File buildFile(final String fileName, final boolean isDirectory) {
        File target = new File(fileName);
        if (isDirectory) {
            target.mkdirs();
        } else {
            if (!target.getParentFile().exists()) {
                target.getParentFile().mkdirs();
                target = new File(target.getAbsolutePath());
            }
        }
        return target;
    }

    /**
     * 创建目录
     *
     * @param zos
     *            zip输出流
     * @param relativePath
     *            相对路径
     * @throws IOException
     * @author mapengfei
     * @date 2016-04-14
     */
    private static void createZipNode(final ZipOutputStream zos, final String relativePath) throws IOException {
        ZipEntry zipEntry = new ZipEntry(relativePath);
        zos.putNextEntry(zipEntry);
        zos.closeEntry();
    }

    public static void main(final String[] args) throws Exception {
        // ZipMultiFile.zip("E:/zippath.zip", "","E:/mapptemplate"); //压缩
        ZipMultiFile.unzip("F:/ziptest.zip", "F:/z");

    }
}