/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-2004 Bull S.A.
 * Contact: jonas-team@objectweb.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * Initial developer(s): Florent BENOIT & Ludovic BERT
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.objectweb.jonas_lib.deployment.work;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * JOnAS Ear File manager. This class provides a way for managing the EAR files.
 * @author Florent Benoit
 * @author Ludovic Bert
 * @author Nicolas Van Caneghem <nicolas.vancaneghem@openpricer.com>Allow the
 *         deployment of an exploded ear
 */

public class EarFileManager extends FileManager {

    /**
     * Constructor. Private as it is an utility class
     */
    private EarFileManager() {
        super();
    }

    /**
     * true If an unpacked directory has the same timestamp than the EAR file,
     * false otherwise.
     * @param urlFileName the url of the name of the EAR file (ends with the
     *        .ear extension).
     * @param urlDirName the url of the directory where the file must be
     *        unpacked.
     * @return true If an unpacked directory has the same timestamp than the EAR
     *         file, false otherwise.
     * @throws FileManagerException if the file doesn't exist
     */
    protected static boolean isUnpackedEar(URL urlFileName, URL urlDirName) throws FileManagerException {

        File urlFile = new File(urlFileName.getFile());

        if (!urlFile.exists()) {
            throw new FileManagerException("File " + urlFileName + "doesn't exist");
        }
        String timeStampDir = fileToTimeStampDir(urlFileName);

        File f = new File(urlDirName.getPath() + File.separator + timeStampDir);

        return f.exists();
    }


    /**
     * Unpack the given EAR file to the specified directory.
     * @param urlFileName the url of the name of the EAR file to unpack.
     * @param urlDirName the url of the destination directory where is unpacked
     *        the EAR file.
     * @return the url of the unpacked directory
     * @throws FileManagerException if we can't unpack the file.
     */
    public static URL unpackEar(URL urlFileName, URL urlDirName) throws FileManagerException {
        return unpackEar(urlFileName, urlDirName, true);
    }

    /**
     * Unpack the given EAR file to the specified directory.
     * @param urlFileName the url of the name of the EAR file to unpack.
     * @param urlDirName the url of the destination directory where is unpacked
     *        the EAR file.
     * @param useTimeStamp use timestamping for unpacking the EAR or not
     * @return the url of the unpacked directory
     * @throws FileManagerException if we can't unpack the file.
     */
    public static URL unpackEar(URL urlFileName, URL urlDirName, boolean useTimeStamp) throws FileManagerException {

        // Check protocol
        if ((!urlFileName.getProtocol().equalsIgnoreCase("file"))
                || (!urlDirName.getProtocol().equalsIgnoreCase("file"))) {
            throw new FileManagerException("Only the file:/ URL can be used");
        }

        // if ear is exploded
        if (new File(urlFileName.getFile()).isDirectory()) {
            return urlFileName;
        }

        // Get the dirName
        String timeStampDir = fileToTimeStampDir(urlFileName);

        boolean unPacked = false;
        if (useTimeStamp) {
            unPacked = isUnpackedEar(urlFileName, urlDirName);
        }

        // EAR file and directory
        JarFile earFile = null;
        File parentDirectoryFile = null;
        URL parentDirectoryUrl = null;
        try {
            earFile = new JarFile(urlFileName.getFile());
            if (useTimeStamp) {
                parentDirectoryFile = new File(urlDirName.getPath() + File.separator + timeStampDir);
            } else {
                String stReturn = new File(urlFileName.getFile()).getName();
                String userName = System.getProperty("user.name", "default");
                //Remove extension .ear
                int lastIndex = stReturn.lastIndexOf(".");
                if (lastIndex == -1) {
                    throw new FileManagerException("The specified file " + urlFileName.getFile()
                            + " is not a file with the format XXX.ear.");
                }
                stReturn = stReturn.substring(0, lastIndex);

                parentDirectoryFile = new File(urlDirName.getPath() + File.separator + userName + "_" + stReturn);
            }
            //Protocol file: no .toURL() method because we have a / at the end
            // of the url otherwise
            parentDirectoryUrl = new URL("file:" + parentDirectoryFile.getPath());
        } catch (IOException e) {
            throw new FileManagerException("Error while creating file for reading the ear file :" + urlFileName
                    + ": " + e.getMessage());
        }

        //Nothing to do if it's unpack
        if (unPacked) {
            return parentDirectoryUrl;
        }

        JarEntry earEntry = null;
        try {
            try {
                //get entries of the EAR file
                for (Enumeration earEntries = earFile.entries(); earEntries.hasMoreElements();) {
                    earEntry = (JarEntry) earEntries.nextElement();

                    //File entry
                    File earEntryFile = new File(parentDirectoryFile, earEntry.getName());

                    //Create directory
                    if (earEntry.isDirectory()) {
                        if (!earEntryFile.exists()) {
                            //create parent directories (with mkdirs)
                            if (!earEntryFile.mkdirs()) {
                                String err = "Can not create directory " + earEntryFile + ", Check the write access.";
                                throw new FileManagerException(err);
                            }
                        }
                        continue;
                    }

                    //If it's a file, we must extract the file
                    //Ensure that the directory exists.
                    earEntryFile.getParentFile().mkdirs();

                    InputStream is = null;
                    try {
                        //get the input stream
                        is = earFile.getInputStream(earEntry);

                        //Dump to the file
                        dump(is, earEntryFile);
                    } finally {
                        is.close();
                    }
                }
            } finally {
                earFile.close();
            }
        } catch (IOException e) {
            throw new FileManagerException("Error while uncompressing entry " + earEntry + ": " + e.getMessage());
        }
        return parentDirectoryUrl;
    }

}