package net.argius.filetool;

import java.io.*;
import java.util.zip.*;

import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;

/**
 * Zipアーカイバ。
 * AntAPIを使用してZIP形式のアーカイブを作成する。
 */
public final class ZipArchiver implements Archiver {

    private ZipOutputStream zos;
    private boolean includesDirectory;

    /**
     * ZipArchiverの生成。
     * @param os 出力先ストリーム
     */
    public ZipArchiver(OutputStream os) {
        this.zos = new ZipOutputStream(os);
    }

    /**
     * includesDirectoryの設定。
     * @param includesDirectory includesDirectory
     */
    public void setIncludesDirectory(boolean includesDirectory) {
        this.includesDirectory = includesDirectory;
    }

    /* (overridden)
     * @see net.argius.filetool.compress.Archiver#addEntry(net.argius.filetool.compress.ArchiverEntry, java.io.InputStream, int, long)
     */
    public void addEntry(ArchiveEntry ae, InputStream is, long length) throws IOException {
        if (ae.isDirectory()) {
            // ディレクトリ
            if (includesDirectory) {
                ZipEntry entry = new ZipEntry(ae.getName());
                zos.putNextEntry(entry);
                entry.setMethod(java.util.zip.ZipEntry.STORED);
                entry.setCrc(0);
                entry.setSize(0);
                entry.setCompressedSize(0);
                entry.setTime(ae.getLastModified());
                zos.closeEntry();
            }
        } else {
            // ファイル
            ZipEntry entry = new ZipEntry(ae.getName());
            zos.putNextEntry(entry);
            CheckedInputStream cis = new CheckedInputStream(is, new CRC32());
            long totalSize = IOUtilities.transferAll(is, zos);
            entry.setCrc(cis.getChecksum().getValue());
            entry.setSize(totalSize);
            entry.setCompressedSize(totalSize);
            entry.setTime(ae.getLastModified());
            zos.closeEntry();
        }
    }

    /* (overridden)
     * @see java.io.Closeable#close()
     */
    public void close() throws IOException {
        zos.close();
    }

}
