package com.qmth.boot.tools.io;

import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * ZIP格式写入工具
 */
public class ZipWriter {

    private ZipOutputStream ous;

    /**
     * 创建输出到通用输出流的ZIP内容，默认使用UTF8
     *
     * @param outputStream
     * @return
     */
    public static ZipWriter create(OutputStream outputStream) {
        return new ZipWriter(outputStream, StandardCharsets.UTF_8);
    }

    /**
     * 创建输出到通用输出流的ZIP内容，指定字符集
     *
     * @param outputStream
     * @param charset
     * @return
     */
    public static ZipWriter create(OutputStream outputStream, Charset charset) {
        return new ZipWriter(outputStream, charset);
    }

    /**
     * 创建输出到本地文件的ZIP内容，默认使用UTF8
     *
     * @param file
     * @return
     */
    public static ZipWriter create(File file) throws FileNotFoundException {
        return create(new FileOutputStream(file));
    }

    /**
     * 创建输出到本地文件的ZIP内容，指定字符集
     *
     * @param file
     * @return
     */
    public static ZipWriter create(File file, Charset charset) throws FileNotFoundException {
        return create(new FileOutputStream(file), charset);
    }

    private ZipWriter(OutputStream outputStream, Charset charset) {
        if (outputStream == null) {
            throw new IllegalArgumentException("OutputStream should not be null");
        }
        if (charset == null) {
            throw new IllegalArgumentException("Charset should not be null");
        }
        this.ous = new ZipOutputStream(outputStream, charset);
    }

    /**
     * 使用通用数据流增加ZIP内部文件，path包括完整的内部路径，至少包含内部文件名
     *
     * @param inputStream
     * @param path
     * @throws IOException
     */
    public void write(InputStream inputStream, String... path) throws IOException {
        if (inputStream == null) {
            throw new IllegalArgumentException("InputStream should not be null");
        }
        if (path == null || path.length == 0) {
            throw new IllegalArgumentException("path should not be empty");
        }
        ous.putNextEntry(new ZipEntry(StringUtils.join(path, IOUtils.ZIP_SEPERATOR)));
        IOUtils.copy(inputStream, ous);
        IOUtils.closeQuietly(inputStream);
    }

    /**
     * 使用本地文件增加ZIP内部文件，path包括完整的内部路径，至少包含内部文件名
     *
     * @param file
     * @param path
     * @throws IOException
     */
    public void write(File file, String... path) throws IOException {
        write(new FileInputStream(file), path);
    }

    /**
     * 使用byte[]增加ZIP内部文件，path包括完整的内部路径，至少包含内部文件名
     *
     * @param data
     * @param path
     * @throws IOException
     */
    public void write(byte[] data, String... path) throws IOException {
        write(new ByteArrayInputStream(data), path);
    }

    public void close() {
        IOUtils.closeQuietly(ous);
    }

}
