/*
 * ProGuard -- shrinking, optimization, obfuscation, and preverification
 *             of Java bytecode.
 *
 * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
package proguard.io;

import proguard.util.ExtensionMatcher;

import java.io.*;


/**
 * This DataEntryReader writes the ZIP entries and files that it reads to a
 * given DataEntryWriter.
 *
 * @author Eric Lafortune
 */
public class DataEntryCopier implements DataEntryReader
{
    private static final int BUFFER_SIZE = 1024;

    private final DataEntryWriter dataEntryWriter;
    private final byte[]          buffer = new byte[BUFFER_SIZE];



    public DataEntryCopier(DataEntryWriter dataEntryWriter)
    {
        this.dataEntryWriter = dataEntryWriter;
    }


    // Implementations for DataEntryReader.

    public void read(DataEntry dataEntry) throws IOException
    {
        try
        {
            // Get the output entry corresponding to this input entry.
            OutputStream outputStream = dataEntryWriter.getOutputStream(dataEntry);
            if (outputStream != null)
            {
                InputStream inputStream = dataEntry.getInputStream();

                // Copy the data from the input entry to the output entry.
                copyData(inputStream, outputStream);

                // Close the data entries.
                dataEntry.closeInputStream();
            }
        }
        catch (IOException ex)
        {
            System.err.println("Warning: can't write resource [" + dataEntry.getName() + "] (" + ex.getMessage() + ")");
        }
    }


    // Small utility methods.

    /**
     * Copies all data that it can read from the given input stream to the
     * given output stream.
     */
    private void copyData(InputStream  inputStream,
                          OutputStream outputStream)
    throws IOException
    {
        while (true)
        {
            int count = inputStream.read(buffer);
            if (count < 0)
            {
                break;
            }
            outputStream.write(buffer, 0, count);
        }

        outputStream.flush();
    }


    /**
     * A main method for testing file/jar/war/directory copying.
     */
    public static void main(String[] args)
    {
        try
        {
            String input  = args[0];
            String output = args[1];

            boolean outputIsJar = output.endsWith(".jar");
            boolean outputIsWar = output.endsWith(".war");
            boolean outputIsEar = output.endsWith(".ear");
            boolean outputIsZip = output.endsWith(".zip");

            DataEntryWriter writer = new DirectoryWriter(new File(output),
                                                         outputIsJar ||
                                                         outputIsWar ||
                                                         outputIsEar ||
                                                         outputIsZip);

        if (!outputIsJar)
        {
            // Zip up any zips, if necessary.
            DataEntryWriter zipWriter = new JarWriter(writer);
            if (outputIsZip)
            {
                // Always zip.
                writer = zipWriter;
            }
            else
            {
                // Only zip up zips.
                writer = new FilteredDataEntryWriter(new DataEntryParentFilter(
                                                     new DataEntryNameFilter(
                                                     new ExtensionMatcher(".zip"))),
                                                     zipWriter,
                                                     writer);
            }

            // Zip up any wars, if necessary.
            DataEntryWriter warWriter = new JarWriter(writer);
            if (outputIsWar)
            {
                // Always zip.
                writer = warWriter;
            }
            else
            {
                // Only zip up wars.
                writer = new FilteredDataEntryWriter(new DataEntryParentFilter(
                                                     new DataEntryNameFilter(
                                                     new ExtensionMatcher(".war"))),
                                                     warWriter,
                                                     writer);
            }
        }

        // Zip up any jars, if necessary.
        DataEntryWriter jarWriter = new JarWriter(writer);
        if (outputIsJar)
        {
            // Always zip.
            writer = jarWriter;
        }
        else
        {
            // Only zip up jars.
            writer = new FilteredDataEntryWriter(new DataEntryParentFilter(
                                                 new DataEntryNameFilter(
                                                 new ExtensionMatcher(".jar"))),
                                                 jarWriter,
                                                 writer);
        }


            // Create the copying DataEntryReader.
            DataEntryReader reader = new DataEntryCopier(writer);


            boolean inputIsJar = input.endsWith(".jar");
            boolean inputIsWar = input.endsWith(".war");
            boolean inputIsZip = input.endsWith(".zip");

            // Unzip any jars, if necessary.
            DataEntryReader jarReader = new JarReader(reader);
            if (inputIsJar)
            {
                // Always unzip.
                reader = jarReader;
            }
            else
            {
                // Only unzip jar entries.
                reader = new FilteredDataEntryReader(new DataEntryNameFilter(
                                                     new ExtensionMatcher(".jar")),
                                                     jarReader,
                                                     reader);

                // Unzip any wars, if necessary.
                DataEntryReader warReader = new JarReader(reader);
                if (inputIsWar)
                {
                    // Always unzip.
                    reader = warReader;
                }
                else
                {
                    // Only unzip war entries.
                    reader = new FilteredDataEntryReader(new DataEntryNameFilter(
                                                         new ExtensionMatcher(".war")),
                                                         warReader,
                                                         reader);
                }

                // Unzip any zips, if necessary.
                DataEntryReader zipReader = new JarReader(reader);
                if (inputIsZip)
                {
                    // Always unzip.
                    reader = zipReader;
                }
                else
                {
                    // Only unzip zip entries.
                    reader = new FilteredDataEntryReader(new DataEntryNameFilter(
                                                         new ExtensionMatcher(".zip")),
                                                         zipReader,
                                                         reader);
                }
            }

            DirectoryPump directoryReader = new DirectoryPump(new File(input));

            directoryReader.pumpDataEntries(reader);

            writer.close();
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
    }
}
