/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/util/org/apache/slide/util/Files.java,v 1.1 2004/03/25 16:18:11 juergen Exp $
 * $Revision: 1.1 $
 * $Date: 2004/03/25 16:18:11 $
 *
 * ====================================================================
 *
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.slide.util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class Files {
    public static File file(String path) {
        return new File(path.replace('/', File.separatorChar));
    }
    
    /**
     ** Returns a File from a given location. This method can be replaced by an java.net.Uri
     ** if we dump jdk 1.3 support
     **
     ** @param url the given location of the file
     **
     ** @return the file
     **/
    public static File getFile(URL url) {
        String str;
        
        // TODO: this method is deprecated in jdk 1.4, but I can't use
        //    try {
        //        str = URLDecoder.decode(url.getFile(), JDom.UTF_8); // ' ' might be encoded by %20 on windows
        //    } catch (UnsupportedEncodingException e) {
        //        throw new XAssertionFailed("expected on every platform");
        //    }
        // because we want to support 1.3
        str = URLDecoder.decode(url.getFile()); // ' ' might be encoded by %20 on windows
        return file(str);
    }
    
    public static void clean(File file) throws IOException {
        if (file.exists()) {
            delete(file);
        }
    }
    
    public static File up(File file, String[] dirs) {
        String name;
        List lst;
        
        file = file.getAbsoluteFile();
        lst = Arrays.asList(dirs);
        while (true) {
            name = file.getName();
            if (lst.indexOf(name) != -1) {
                file = file.getParentFile();
                if (file == null) {
                    throw new XAssertionFailed();
                }
            } else {
                return file;
            }
        }
    }
    
    /**
     ** Deletes a file or directory. Directories are deleted recursively.
     **
     ** @param target file or directory to be deleted recursively
     **
     ** @throws IOException if a file cannot be deleted
     **/
    public static void delete(File target) throws IOException {
        File[] files;
        int i;
        
        files = target.listFiles();
        if (files != null) {
            // delete all files and dirs inside the directory
            for (i = 0; i < files.length; i++) {
                delete(files[i]);
            }
        }
        if (!target.delete()) {
            throw new IOException("cannot delete file " + target);
        }
    }
    
    public static List readLines(File src) throws IOException {
        List lines;
        BufferedReader reader;
        String line;
        
        lines = new ArrayList();
        reader = new BufferedReader( new FileReader(src) );
        while (true) {
            line = reader.readLine();
            if (line == null) {
                break;
            }
            lines.add(line);
        }
        reader.close();
        return lines;
    }
    
    public static void writeLines(File dest, List lines) throws IOException {
        Iterator iter;
        String line;
        BufferedWriter writer;
        
        iter = lines.iterator();
        writer = new BufferedWriter(new FileWriter(dest));
        while (iter.hasNext()) {
            line = (String) iter.next();
            writer.write(line);
            writer.newLine();
        }
        writer.close();
    }
    
    //--
    
    public static File join(File base, String a, String b, String c, String d, String e, String f) {
        return join(base, new String[] { a, b, c, d, e, f });
    }
    public static File join(File base, String a, String b, String c, String d, String e) {
        return join(base, new String[] { a, b, c, d, e });
    }
    public static File join(File base, String a, String b, String c, String d) {
        return join(base, new String[] { a, b, c, d });
    }
    public static File join(File base, String a, String b, String c) {
        return join(base, new String[] { a, b, c });
    }
    public static File join(File base, String a, String b) {
        return join(base, new String[] { a, b });
    }
    public static File join(File base, String a) {
        return join(base, new String[] { a });
    }
    public static File join(File base, String[] names) {
        return new File(base, join(names));
    }
    
    public static String join(String a, String b, String c, String d, String e, String f) {
        return join(new String[] { a, b, c, d, e, f });
    }
    public static String join(String a, String b, String c, String d, String e) {
        return join(new String[] { a, b, c, d, e });
    }
    public static String join(String a, String b, String c, String d) {
        return join(new String[] { a, b, c, d });
    }
    public static String join(String a, String b, String c) {
        return join(new String[] { a, b, c });
    }
    public static String join(String a, String b) {
        return join(new String[] { a, b });
    }
    
    public static String join(String[] names) {
        return Strings.join(names, File.separator);
    }
    
    /**
     * Null if child equals anchestor.
     *
     * @return none-null if child is contained directly or indirectly in a sub-directory of parent
     */
    public static String getRelative(File anchestor, File child) {
        String p;
        String c;
        
        // TODO: canonical path? use getParent instead?
        p = withSlash(anchestor.getAbsolutePath());
        c = withoutSlash(child.getAbsolutePath());
        if (c.startsWith(p)) {
            return c.substring(p.length());
        } else {
            return null;
        }
    }
    
    private static String withSlash(String path) {
        if (path.endsWith(File.separator)) {
            return path;
        } else {
            return path + File.separator;
        }
    }
    private static String withoutSlash(String path) {
        if (path.endsWith(File.separator)) {
            return path.substring(0, path.length() - 1);
        } else {
            return path;
        }
    }
    
    public static void checkDirectory(File dir) throws IOException {
        if (dir.isDirectory()) {
            return;
        }
        if (dir.exists()) {
            throw new IOException("directory expected: " + dir);
        } else {
            throw new IOException("no such directory: " + dir);
        }
    }
    public static void checkFile(File file) throws IOException {
        if (file.isFile()) {
            return;
        }
        if (file.exists()) {
            throw new IOException("file expected: " + file);
        } else {
            throw new IOException("no such file: " + file);
        }
    }
    
    
    public static void mkdir(File file) throws IOException {
        if (!file.mkdir()) {
            throw new IOException("cannot create directory: " + file);
        }
    }
    
    public static File mkTmpDir(File base, String name) throws IOException {
        int i;
        File file;
        
        for (i = 0; true; i++) {
            file = new File(base, name + i);
            if (!file.exists()) {
                // TODO: how to do this atomically?
                if (file.mkdir()) {
                    return file;
                } else {
                    throw new IOException("mkdir failed: " + file);
                }
            }
        }
    }
    
    public static String getRelative(File startdir, File destfile, char separator) throws IOException {
        String startfilepath;
        String destpath;
        String common;
        StringBuffer result;
        int len;
        int ups;
        int i;
        
        startfilepath = new File(startdir, "foo").getAbsolutePath();
        destpath = destfile.getAbsolutePath();
        common = Strings.getCommon(startfilepath, destpath);
        common = common.substring(0, common.lastIndexOf(File.separator) + 1);  // ok for idx == -1
        len = common.length();
        if (len == 0) {
            throw new IOException("no common prefix: " + startfilepath + " " + destpath);
        }
        startfilepath = startfilepath.substring(len);
        destpath = destpath.substring(len);
        result = new StringBuffer();
        ups = Strings.count(startfilepath, File.separator);
        for (i = 0; i < ups; i++) {
            result.append(".." + separator);
        }
        result.append(Strings.replace(destpath, File.separator, "" + separator));
        return result.toString();
    }
}

