package org.jboss.windup.decompiler.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.apache.commons.io.IOUtils;

/**
 * @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
 * @author <a href="mailto:ozizka@redhat.com">Ondrej Zizka</a>
 */
public class ZipUtil
{
    /**
     * Unzip the given archive into the specified directory.
     */
    public static void unzip(File inputFile, File outputDir) throws IOException
    {
        unzipWithFilter(inputFile, outputDir, null);
    }

    /**
     * Unzip the given archive into the specified directory, using given filter. Directories are created only if needed.
     */
    public static void unzipWithFilter(File inputFile, File outputDir, Filter<ZipEntry> filter) throws IOException
    {
        try (ZipFile zipFile = new ZipFile(inputFile))
        {
            Enumeration<? extends ZipEntry> entryEnum = zipFile.entries();
            while (entryEnum.hasMoreElements())
            {
                ZipEntry entry = entryEnum.nextElement();
                String entryName = entry.getName();
                File destFile = new File(outputDir, entryName);
                if (entry.isDirectory())
                    continue;

                if (filter != null)
                {
                    final Filter.Result res = filter.decide(entry);
                    switch (res)
                    {
                    case STOP:
                        return;
                    case REJECT:
                        continue;
                    }
                }

                File parentDir = destFile.getParentFile();
                if (!parentDir.isDirectory() && !parentDir.mkdirs())
                    throw new RuntimeException("Unable to create directory: " + parentDir.getAbsolutePath());

                try (InputStream zipInputStream = zipFile.getInputStream(entry))
                {
                    try (FileOutputStream outputStream = new FileOutputStream(destFile))
                    {
                        IOUtils.copy(zipInputStream, outputStream);
                    }
                }

                if (filter != null)
                {
                    final Filter.Result res = filter.decide(entry);
                    switch (res)
                    {
                    case ACCEPT_STOP:
                        return;
                    }
                }
            }
        }
    }

}
