/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2007-2010 Bull S.A.S.
 * Contact: jonas-team@ow2.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
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.launcher.jonas.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Map.Entry;

/**
 * IO utilities.
 * @author Guillaume Sauthier
 */
public final class IOUtils {

    /**
     * Empty private constructor.
     */
    private IOUtils() {
    }

    /**
     * Recursively delete a directory.
     * @param dir directory to be deleted
     * @return true if everything went smoothly.
     */
    public static boolean deleteDir(final File dir) {

        // not a directory, abort quickly
        if (!dir.isDirectory()) {
            return false;
        }

        // to see if this directory is actually a symbolic link to a directory,
        // we want to get its canonical path - that is, we follow the link to
        // the file it's actually linked to
        File candir;
        try {
            candir = dir.getCanonicalFile();
        } catch (IOException e) {
            return false;
        }

        // a symbolic link has a different canonical path than its actual path,
        // unless it's a link to itself
        if (!candir.equals(dir.getAbsoluteFile())) {
            // this file is a symbolic link, and there's no reason for us to
            // follow it, because then we might be deleting something outside of
            // the directory we were told to delete
            return false;
        }

        // now we go through all of the files and sub-directories in the
        // directory and delete them one by one
        File[] files = candir.listFiles();
        if (files != null) {
            for (File file : files) {
                // in case this directory is actually a symbolic link, or it's
                // empty, we want to try to delete the link before we try
                // anything
                boolean deleted = file.delete();
                if (!deleted) {
                    // deleting the file failed, so maybe it's a non-empty
                    // directory
                    if (file.isDirectory()) {
                        deleteDir(file);
                    }

                    // otherwise, there's nothing else we can do
                }
            }
        }

        // now that we tried to clear the directory out, we can try to delete it
        // again
        return dir.delete();
    }

	/**
	 * Return a OS valid path.
	 * @param base basis directory
	 * @param relative relative path name to the basis directory
	 * @return the OS dependent path name
	 */
	public static String getSystemPath(final File base, final String relative) {
	    return getSystemFile(base, relative).getPath();
	}

	/**
	 * Return a OS valid File.
	 * @param base basis directory
	 * @param relative relative path name to the basis directory
	 * @return the OS dependent File
	 */
	public static File getSystemFile(final File base, final String relative) {
	    return new File(base, relative.replace('/', File.separatorChar));
	}

    /**
     * Checks if the file exists.
     * @param filename File name to be tested
     * @return {@code true} if the given file exists.
     */
    public static boolean exists(final String filename) {
        return new File(filename).exists();
    }

    /**
     * @param filename properties file name
     * @return the content of the resource as a {@link java.util.Properties} instance.
     * @throws java.io.IOException if file is not found or if file is not a property file.
     */
    public static Properties getPropertiesFromFile(final File filename) throws IOException {
        return loadPropertiesFromStream(new FileInputStream(filename));
    }

    /**
     * Create a {@code Properties} from the given InputStream. Close the stream
     * at the end of the operation.
     * @param is InputStream
     * @return properties
     * @throws java.io.IOException if the stream cannot be read or if it doesn't
     *         contains a {@code Properties}
     */
    public static Properties loadPropertiesFromStream(final InputStream is) throws IOException {
        Properties config = new Properties();
        try {
            config.load(is);
        } finally {
            is.close();
        }
        return config;
    }

    /**
     * Convert the given properties object into a map<String,String>.
     * @param p the properties object
     * @return a map
     */
    public static Map<String, String> props2Map(final Properties p) {
        Map<String, String> map = new HashMap<String, String>();
        if (p != null) {
            Iterator<Entry<Object,Object>> it = p.entrySet().iterator();
            while (it.hasNext()) {
                Entry<Object,Object> entry = it.next();
                map.put(entry.getKey().toString(), entry.getValue().toString());
            }
        }
        return map;
    }


    /**
     * @param resource properties file name (relative to org/ow2/jonas/launcher/jonas)
     * @return the content of the resource as a {@link java.util.Properties} instance.
     * @throws java.io.IOException if file is not found or if file is not a property file.
     */
    public static Properties getPropertiesFromClass(final String resource, final Class<?> clazz) throws IOException {
        return loadPropertiesFromStream(clazz.getResourceAsStream(resource));
    }
}
