package org.maachang.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.CharArrayWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;

/**
 * ファイルユーティリティ.
 * 
 * @version 2007/10/18
 * @author masahito suzuki
 * @since MaachangDao 1.00
 */
public class FileUtil {

    /**
     * デフォルト読み込みキャラクタセット.
     */
    private static final String CHARSET = "UTF8";

    /**
     * OSファイルスペース.
     */
    public static final String FILE_SPACE = System
            .getProperty("file.separator");

    /**
     * 指定パスを結合.
     * <BR><BR>
     * 指定パスを結合します.
     * <BR>
     * @param ctx 基本パスを設定します.
     * @param path 結合対象のパスを設定します.
     * @return String 結合されたパスが返されます.
     */
    public static String convertFullPath( String ctx,String path ) {
        if( ctx == null || ( ctx = ctx.trim() ).length() <= 0 ||
            path == null || ( path = path.trim() ).length() <= 0 ) {
            throw new IllegalArgumentException( "引数が不正です" ) ;
        }
        if( path.startsWith( "/" ) || path.startsWith( "\\" ) ) {
            ctx = "/" ;
        }
        ArrayList<String> ctxList = StringUtil.cutString( ctx,"/\\" ) ;
        ArrayList<String> pathList = StringUtil.cutString( path,"/\\" ) ;
        if( pathList != null ) {
            int len = pathList.size() ;
            for( int i = 0 ; i < len ; i ++ ) {
                String c = pathList.get( i ) ;
                if( ".".equals( c ) ) {
                    continue ;
                }
                if( "..".equals( c ) ) {
                    ctxList.remove( ctxList.size()-1 ) ;
                }
                else {
                    ctxList.add( c ) ;
                }
            }
            pathList = null ;
        }
        StringBuilder buf = new StringBuilder() ;
        int len = ctxList.size() ;
        for( int i = 0 ; i < len ; i ++ ) {
            buf.append( "/" ).append( ctxList.get( i ) ) ;
        }
        return buf.toString() ;
    }
    
    /**
     * リアルパスと指定パスをマージ.
     * <BR><BR>
     * リアルパスと指定パスをマージします.
     * <BR>
     * @param real 対象のリアルパスを設定します.
     * @param path 対象のパスを設定します.
     * @return String マージされたフルパスが返されます.
     * @exception Exception 例外.
     */
    public static final String marge( String real,String path )
        throws Exception {
        if( real == null || ( real = real.trim() ).length() <= 0 ||
            path == null || ( path = path.trim() ).length() <= 0 ) {
            throw new IllegalArgumentException( "引数が不正です" ) ;
        }
        if( real.endsWith( "/" ) || real.endsWith( "\\" ) ) {
            real = real.substring( 0,real.length()-1 ) ;
        }
        if( path.startsWith( "/" ) || path.startsWith( "\\" ) ) {
            path = new StringBuilder().append( real ).
                append( path ).toString() ;
        }
        else {
            path = new StringBuilder().append( real ).
                append( FileUtil.FILE_SPACE ).
                append( path ).toString() ;
        }
        return FileUtil.getFullPath( path ) ;
    }
    
    /**
     * 対象のディレクトリを生成. <BR>
     * <BR>
     * 対象のディレクトリ情報を生成します. <BR>
     * 
     * @param dirName
     *            生成対象のディレクトリ名を設定します.
     * @return String 結果のファイル名が返されます.
     * @exception IOException
     *                I/O例外.
     */
    public static final String mkdirs(String dirName) throws IOException {
        File fp = null;
        StringBuffer buf = null;
        String tmp = null;
        String ret = null;

        try {

            if (dirName == null) {
                throw new IllegalArgumentException("引数は不正です");
            }

            if (isDirExists(dirName) == true) {

                fp = new File(dirName);
                tmp = fp.getCanonicalPath();
                buf = new StringBuffer();

                buf.append(tmp);
                buf.append(FILE_SPACE);
                ret = buf.toString();

            } else {

                fp = new File(dirName);
                tmp = fp.getCanonicalPath();
                buf = new StringBuffer();

                buf.append(tmp);
                buf.append(FILE_SPACE);
                ret = buf.toString();

                if (fp.mkdirs() == false) {
                    throw new IOException("ディレクトリ(" + dirName + ")の作成に失敗しました");
                }

            }

        } catch (IOException e) {
            throw e;
        } finally {
            fp = null;
            buf = null;
            tmp = null;
        }

        return ret;

    }

    /**
     * パス名をフルパス名に設定. <BR>
     * <BR>
     * パス名をフルパス名に設定します. <BR>
     * 
     * @param path
     *            対象のパス名を設定します.
     * @return String フルパス名が返されます.
     * @exception IOException
     *                I/O例外.
     */
    public static final String getFullPath(String path) throws IOException {
        File fp = new File(path);
        return fp.getCanonicalPath();
    }

    /**
     * 指定パスから、ファイル名を取得. <BR>
     * <BR>
     * 指定パスから、ファイル名を取得します. <BR>
     * 
     * @param path
     *            対象のパス名を設定します.
     * @return String 対象のファイル名が返されます.
     */
    public static final String getFileName(String path) {
        int p = path.lastIndexOf("\\");
        int p2 = path.lastIndexOf("/");
        if (p == -1) {
            if (p2 != -1) {
                p = p2;
            }
        } else if (p2 != -1 && p < p2) {
            p = p2;
        }

        if (p == -1) {
            return path;
        }
        return path.substring(p + 1);
    }

    /**
     * 指定位置のファイル区切りを削除. <BR>
     * <BR>
     * 指定位置のファイル区切りを削除します. <BR>
     * 
     * @param mode
     *            対象の指定位置を設定します.<BR>
     *            [true]を設定した場合、先頭のファイル区切りを外します.
     * @param name
     *            対象のファイル名を設定します.
     * @return String 削除された情報が返されます.
     */
    public static final String cutSeparator(boolean mode, String name) {
        if (mode == true) {
            name = name.trim();
            if (name.startsWith("/") == true || name.startsWith("\\") == true) {
                return name.substring(1);
            }
        } else {
            name = name.trim();
            if (name.endsWith("/") == true || name.endsWith("\\") == true) {
                return name.substring(0, name.length() - 1);
            }
        }
        return name;
    }

    /**
     * 指定ファイルを削除. <BR>
     * <BR>
     * 
     * @param name
     *            対象のファイル名を設定します.
     */
    public static final void removeFile(String name) {
        try {
            File file = new File(name);
            file.delete();
        } catch (Exception e) {
        }
    }

    /**
     * 指定ファイルを移動. <BR>
     * <BR>
     * 
     * @param src
     *            移動元のファイル名を設定します.
     * @param dest
     *            移動先のファイル名を設定します.
     */
    public static final void moveFile(String src, String dest) {
        try {
            File fileSrc = new File(src);
            File fileDest = new File(dest);
            fileSrc.renameTo(fileDest);
        } catch (Exception e) {
        }
    }

    /**
     * 指定ファイル長を取得. <BR>
     * <BR>
     * 
     * @param name
     *            対象のファイル名を設定します.
     * @return long 対象のファイル長が返されます.
     */
    public static final long getLength(String name) {
        long ret = -1L;

        try {
            File file = new File(name);
            ret = (file.exists() == true) ? file.length() : -1L;
        } catch (Exception e) {
            ret = -1L;
        }

        return ret;
    }

    /**
     * 指定ファイル日付を取得. <BR>
     * <BR>
     * 
     * @param name
     *            対象のファイル名を設定します.
     * @return long 対象のファイル日付が返されます.
     */
    public static final long getLastTime(String name) {
        long ret = 0L;

        try {
            File file = new File(name);
            ret = (file.exists() == true) ? file.lastModified() : 0L;
        } catch (Exception e) {
            ret = 0L;
        }

        return ret;
    }

    /**
     * 指定ファイル日付を設定. <BR>
     * <BR>
     * 
     * @param name
     *            対象のファイル名を設定します.
     * @param lastTime
     *            対象の更新日付を設定します.
     * @return boolean 設定結果が返されます.
     */
    public static final boolean setLastTime(String name, long lastTime) {
        boolean ret = false;
        try {
            File file = new File(name);
            if (file.exists() == true) {
                ret = file.setLastModified(lastTime);
            }
        } catch (Exception e) {
            ret = false;
        }

        return ret;
    }

    /**
     * 指定ファイル名が存在するかチェック. <BR>
     * <BR>
     * 指定ファイル名が存在するかチェックします.<BR>
     * <BR>
     * 
     * @param name
     *            ファイル名を指定します.
     * @return boolean ファイル存在フラグが返されます.<BR>
     *         [true]が返された場合、指定したファイル名は存在します.<BR>
     *         [false]が返された場合、指定したファイル名は存在しません.
     */
    public static final boolean isFileExists(String name) {
        boolean ret;

        if (name == null || name.length() <= 0) {
            return false;
        }

        try {

            File file = new File(name);
            ret = (file.exists() == true) ? ((file.isDirectory() == false) ? file
                    .canRead()
                    : false)
                    : false;

        } catch (Exception e) {
            ret = false;
        }

        return ret;
    }

    /**
     * 指定ディレクトリ名が存在するかチェック. <BR>
     * <BR>
     * 指定ディレクトリ名が存在するかチェックします. <BR>
     * 
     * @param dirName
     *            ディレクトリ名を指定します.
     * @return boolean ディレクトリ存在フラグが返されます.<BR>
     *         [true]が返された場合、指定したディレクトリ名は存在します.<BR>
     *         [false]が返された場合、指定したディレクトリ名は存在しません.
     */
    public static final boolean isDirExists(String dirName) {
        boolean ret;
        File check = null;

        if (dirName == null) {
            return false;
        }

        check = new File(dirName);
        ret = check.isDirectory();
        check = null;

        return ret;
    }

    /**
     * 指定ファイル名が読み取り可能かチェック. <BR>
     * <BR>
     * 指定ファイル名が読み取り可能かチェックします.<BR>
     * <BR>
     * 
     * @param name
     *            読み取り可能チェック対象のディレクトリ／ファイル名を 指定します.
     * @return boolean 読み取り可能か否かが返されます.<BR>
     *         [true]が返された場合、読み取り可能です.<BR>
     *         [false]が返された場合、読み取り不可能か存在しません.
     */
    public static final boolean isRead(String name) {
        boolean ret;

        File file = null;

        if (name == null || name.length() <= 0) {
            return false;
        }

        try {

            file = new File(name);
            ret = file.canRead();

        } catch (Exception e) {
            ret = false;
        } finally {
            file = null;
        }

        return ret;
    }

    /**
     * 指定ファイル名が書き込み可能かチェック. <BR>
     * <BR>
     * 指定ファイル名が書き込み可能かチェックします. <BR>
     * 
     * @param name
     *            書き込み可能チェック対象のディレクトリ／ファイル名を 指定します.
     * @return boolean 書き込み可能か否かが返されます.<BR>
     *         [true]が返された場合、書き込み可能です.<BR>
     *         [false]が返された場合、書き込み不可能か存在しません.
     */
    public static final boolean isWrite(String name) {
        boolean ret;
        File check = null;

        if (name == null) {
            return false;
        }

        check = new File(name);
        ret = check.canWrite();
        check = null;

        return ret;
    }

    /**
     * 指定ディレクトリ以下のファイル/ディレクトリ名一覧を取得. <BR>
     * <BR>
     * 指定ディレクトリ以下のファイル/ディレクトリ名一覧を取得します. <BR>
     * 
     * @param dir
     *            対象ディレクトリ名を設定します.
     * @return String[] ファイル/ディレクトリ名一覧が返されます.
     */
    public static final String[] getList(String dir) {
        if (dir == null || dir.length() <= 0) {
            return null;
        }
        if (dir.endsWith("/") == true || dir.endsWith("\\") == true) {
            dir.substring(0, dir.length() - 1);
        }
        dir += FILE_SPACE;
        try {
            File fp = new File(dir);
            return fp.list();
        } catch (Exception e) {
        }
        return null;
    }

    /**
     * 指定ディレクトリ以下のファイル/ディレクトリ名一覧を取得. <BR>
     * <BR>
     * 指定ディレクトリ以下のファイル/ディレクトリ名一覧を取得します. <BR>
     * 
     * @param dir
     *            対象ディレクトリ名を設定します.
     * @return ArrayList<String> ファイル/ディレクトリ名一覧が返されます.
     */
    public static final ArrayList<String> getListByArray(String dir) {
        String[] lst = getList( dir ) ;
        if( lst != null && lst.length > 0 ) {
            int len = lst.length ;
            ArrayList<String> ret = new ArrayList<String>() ;
            for( int i = 0 ; i < len ; i ++ ) {
                ret.add( lst[ i ] ) ;
            }
            return ret ;
        }
        return null ;
    }

    /**
     * 指定ディレクトリ以下のファイル名一覧を取得. <BR>
     * <BR>
     * 指定ディレクトリ以下のファイル名一覧を取得します. <BR>
     * 
     * @param dir
     *            対象ディレクトリ名を設定します.
     * @return String[] ファイル名一覧が返されます.
     */
    public static final String[] getFileList(String dir) {
        if (dir == null || dir.length() <= 0) {
            return null;
        }
        if (dir.endsWith("/") == true || dir.endsWith("\\") == true) {
            dir.substring(0, dir.length() - 1);
        }
        dir += FILE_SPACE;
        try {
            File fp = new File(dir);
            String[] names = fp.list();
            int len;
            if (names != null && (len = names.length) > 0) {
                for (int i = 0; i < len; i++) {
                    File f = new File(dir + names[i]);
                    if (f.exists() == false || f.isDirectory() == true) {
                        names[i] = null;
                    }
                }
            }
            return names;
        } catch (Exception e) {
        }
        return null;
    }

    /**
     * 指定ディレクトリ以下のファイル名一覧を取得. <BR>
     * <BR>
     * 指定ディレクトリ以下のファイル名一覧を取得します. <BR>
     * 
     * @param dir
     *            対象ディレクトリ名を設定します.
     * @return String[] ファイル名一覧が返されます.
     */
    public static final String[] getFileDirList(String dir) {
        if (dir == null || dir.length() <= 0) {
            return null;
        }
        if (dir.endsWith("/") == true || dir.endsWith("\\") == true) {
            dir.substring(0, dir.length() - 1);
        }
        dir += FILE_SPACE;
        try {
            File fp = new File(dir);
            String[] names = fp.list();
            int len;
            if (names != null && (len = names.length) > 0) {
                for (int i = 0; i < len; i++) {
                    File f = new File(dir + names[i]);
                    if (f.canRead() == false) {
                        names[i] = null;
                    }
                }
            }
            return names;
        } catch (Exception e) {
        }
        return null;
    }

    /**
     * 指定ディレクトリ以下のファイル名一覧を取得. <BR>
     * <BR>
     * 指定ディレクトリ以下のファイル名一覧を取得します. <BR>
     * 
     * @param dir
     *            対象ディレクトリ名を設定します.
     * @return ArrayList<String> ファイル名一覧が返されます.
     */
    public static final ArrayList<String> getFileListByArray(String dir) {
        String[] lst = getFileList( dir ) ;
        if( lst != null && lst.length > 0 ) {
            int len = lst.length ;
            ArrayList<String> ret = new ArrayList<String>() ;
            for( int i = 0 ; i < len ; i ++ ) {
                ret.add( lst[ i ] ) ;
            }
            return ret ;
        }
        return null ;
    }

    /**
     * 指定ディレクトリ内の最終更新日付を取得. <BR>
     * <BR>
     * 指定ディレクトリ内の最終更新日付を取得します. <BR>
     * 
     * @param name
     *            対象のディレクトリ名を設定します.
     * @return long ディレクトリ内の情報に対する最終更新日が返されます.
     */
    public static final long getDirectoryToLastTime(String name) {
        if (isDirExists(name) == false) {
            return -1L;
        }
        return lastUpdateByDirectory(name, -1L);
    }

    /**
     * 指定ディレクトリ内の指定時間より後の更新日付のファイル名を取得. <BR>
     * <BR>
     * 指定ディレクトリ内の指定時間より後の更新日付のファイル名を取得します. <BR>
     * 
     * @param out
     *            ファイル名を格納するオブジェクトを設定します.
     * @param name
     *            対象のディレクトリ名を設定します.
     * @param targetTime
     *            ターゲットの日付を設定します.
     */
    public static final void getDirectoryToTargetNextTime(
            ArrayList<String> out, String name, long targetTime) {
        if (isDirExists(name) == false) {
            return;
        }
        targetNextUpdateByDirectory(out, name, targetTime);
    }

    /**
     * 指定ファイル内容をバイナリ情報として取得. <BR>
     * <BR>
     * 指定されたファイルの内容をバイナリ情報として取得します.<BR>
     * <BR>
     * 
     * @param name
     *            取得対象のファイル名を設定します.
     * @return byte[] 指定ファイル内容が返されます.
     * @exception Exception
     *                例外.
     */
    public static final byte[] getFile(String name) throws Exception {
        long len;

        BufferedInputStream buf = null;
        byte[] ret = null;

        try {

            buf = new BufferedInputStream(new FileInputStream(name));

            len = FileUtil.getLength(name);

            if (len > 0x000000007fffffffL) {
                throw new Exception("指定されたファイル名(" + name
                        + ")はファイルサイズが大きいため取得できません");
            }

            ret = new byte[(int) (len & 0x000000007fffffffL)];
            buf.read(ret);

        } finally {

            try {
                buf.close();
            } catch (Exception t) {
            }

            buf = null;

        }

        return ret;

    }

    /**
     * 指定ファイル内容を文字列情報として取得. <BR>
     * <BR>
     * 指定されたファイルの内容を文字列情報として取得します.<BR>
     * <BR>
     * 
     * @param name
     *            取得対象のファイル名を設定します.
     * @return String 取得された情報が返されます.
     * @exception Exception
     *                例外.
     */
    public static final String getFileByString(String name) throws Exception {
        return FileUtil.getFileByString(name, CHARSET);
    }

    /**
     * 指定ファイル内容を文字列情報として取得. <BR>
     * <BR>
     * 指定されたファイルの内容を文字列情報として取得します. <BR>
     * 
     * @param name
     *            取得対象のファイル名を設定します.
     * @param charset
     *            取得対象のキャラクターセットを設定します.
     * @return String 取得された情報が返されます.
     * @exception Exception
     *                例外.
     */
    public static final String getFileByString(String name, String charset)
            throws Exception {
        int len;
        char[] tmp = null;

        CharArrayWriter ca = null;
        BufferedReader buf = null;
        String ret = null;

        try {

            tmp = new char[8192];
            ca = new CharArrayWriter();
            buf = new BufferedReader(new InputStreamReader(new FileInputStream(
                    name), charset));

            while ((len = buf.read(tmp, 0, 8192)) > 0) {
                ca.write(tmp, 0, len);
            }

            ret = ca.toString();
            ca.close();
            ca = null;

        } finally {

            try {
                buf.close();
            } catch (Exception t) {
            }

            try {
                ca.close();
            } catch (Exception t) {
            }

            buf = null;
            ca = null;
            tmp = null;

        }

        return ret;
    }

    /**
     * 指定ファイル名に対象のバイナリ情報を出力. <BR>
     * <BR>
     * 指定されたファイル名に対してバイナリ情報を出力します. <BR>
     * 
     * @param name
     *            出力対象のファイル名を設定します.
     * @param binary
     *            出力対象のバイナリ情報を設定します.
     * @exception Exception
     *                例外.
     */
    public static final void setFile(String name, byte[] binary)
            throws Exception {
        FileUtil.setFile(name, true, binary);
    }

    /**
     * 指定ファイル名に対象のバイナリ情報を出力. <BR>
     * <BR>
     * 指定されたファイル名に対してバイナリ情報を出力します. <BR>
     * 
     * @param name
     *            出力対象のファイル名を設定します.
     * @param mode
     *            書き込みモードを設定します.<BR>
     *            [true]を設定した場合、既に同一のファイルが存在しても上書きします.<BR>
     *            [false]を設定した場合、既に同一のファイルが存在した場合後に書き込みます.
     * @param binary
     *            出力対象のバイナリ情報を設定します.
     * @exception Exception
     *                例外.
     */
    public static final void setFile(String name, boolean mode, byte[] binary)
            throws Exception {
        BufferedOutputStream buf = null;

        if (name == null || binary == null) {
            throw new IllegalArgumentException("引数は不正です");
        }

        try {

            if (mode == true) {
                buf = new BufferedOutputStream(new FileOutputStream(name));
            } else {
                buf = new BufferedOutputStream(new FileOutputStream(name, true));
            }

            buf.write(binary);

        } catch (Exception e) {
            throw e;
        } finally {

            try {
                buf.close();
            } catch (Exception t) {
            }

            buf = null;

        }

    }

    /**
     * 指定ファイル名に対象の文字列情報を出力. <BR>
     * <BR>
     * 指定されたファイル名に対して文字列情報を出力します. <BR>
     * 
     * @param name
     *            出力対象のファイル名を設定します.
     * @param value
     *            出力対象の文字列情報を設定します.
     * @exception Exception
     *                例外.
     */
    public static final void setFileByString(String name, String value)
            throws Exception {
        FileUtil.setFileByString(name, true, value, CHARSET);
    }

    /**
     * 指定ファイル名に対象の文字列情報を出力. <BR>
     * <BR>
     * 指定されたファイル名に対して文字列情報を出力します. <BR>
     * 
     * @param name
     *            出力対象のファイル名を設定します.
     * @param mode
     *            書き込みモードを設定します.<BR>
     *            [true]を設定した場合、既に同一のファイルが存在しても上書きします.<BR>
     *            [false]を設定した場合、既に同一のファイルが存在した場合後に書き込みます.
     * @param value
     *            出力対象の文字列情報を設定します.
     * @exception Exception
     *                例外.
     */
    public static final void setFileByString(String name, boolean mode,
            String value) throws Exception {
        FileUtil.setFileByString(name, mode, value, CHARSET);
    }

    /**
     * 指定ファイル名に対象の文字列情報を出力. <BR>
     * <BR>
     * 指定されたファイル名に対して文字列情報を出力します. <BR>
     * 
     * @param name
     *            出力対象のファイル名を設定します.
     * @param mode
     *            書き込みモードを設定します.<BR>
     *            [true]を設定した場合、既に同一のファイルが存在しても上書きします.<BR>
     *            [false]を設定した場合、既に同一のファイルが存在した場合後に書き込みます.
     * @param value
     *            出力対象の文字列情報を設定します.
     * @param charset
     *            出力対象のキャラクターセットを設定します.
     * @exception Exception
     *                例外.
     */
    public static final void setFileByString(String name, boolean mode,
            String value, String charset) throws Exception {
        BufferedWriter buf = null;

        if (name == null || value == null) {
            throw new IllegalArgumentException("引数は不正です");
        }

        try {

            if (mode == true) {
                buf = new BufferedWriter(new OutputStreamWriter(
                        new FileOutputStream(name), charset));
            } else {
                buf = new BufferedWriter(new OutputStreamWriter(
                        new FileOutputStream(name, true), charset));
            }

            buf.write(value);

        } catch (Exception e) {
            throw e;
        } finally {

            try {
                buf.close();
            } catch (Exception t) {
            }

            buf = null;

        }

    }

    /**
     * 指定パスのスクリプトを取得. <BR>
     * <BR>
     * 指定パスのスクリプトを取得します. <BR>
     * 
     * @param path
     *            対象のスクリプトパスを設定します.
     * @return String スクリプト内容が返されます.
     * @exception Exception
     *                例外.
     */
    public static String getScriptByResource(String path, String charset)
            throws Exception {
        if (charset == null || charset.length() <= 0) {
            charset = "UTF8";
        }
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        BufferedReader br = null;
        try {
            StringBuilder buf = new StringBuilder();
            br = new BufferedReader(new InputStreamReader(cl
                    .getResourceAsStream(path), charset));
            for (;;) {
                String s = br.readLine();
                if (s == null) {
                    break;
                }
                buf.append(s).append("\r\n");
            }
            br.close();
            br = null;
            return buf.toString();
        } catch (Exception e) {
            throw e;
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (Exception e) {
                }
            }
        }
    }

    /**
     * ディレクトリ内の最終時間を取得.
     */
    private static final long lastUpdateByDirectory(String name, long ret) {

        if (name.endsWith("\\") == false && name.endsWith("/") == false) {
            name = name + FILE_SPACE;
        }

        File file = new File(name);
        String[] names = file.list();
        file = null;
        int len;
        if (names != null && (len = names.length) > 0) {
            for (int i = 0; i < len; i++) {
                String target = name + names[i];
                names[i] = null;
                File fp = new File(target);

                if (fp.isDirectory() == true) {
                    fp = null;
                    ret = lastUpdateByDirectory(target, ret);
                } else {
                    long now = fp.lastModified();
                    fp = null;
                    if (now > ret) {
                        ret = now;
                    }
                }
            }
        }

        return ret;
    }

    /**
     * 指定ディレクトリ以下にある、ターゲット時間より後のファイル日付の名前を取得.
     */
    private static final void targetNextUpdateByDirectory(
            ArrayList<String> lst, String name, long targetTime) {

        if (name.endsWith("\\") == false && name.endsWith("/") == false) {
            name = name + FILE_SPACE;
        }

        File file = new File(name);
        String[] names = file.list();
        file = null;
        int len;
        if (names != null && (len = names.length) > 0) {
            for (int i = 0; i < len; i++) {
                String target = name + names[i];
                names[i] = null;
                File fp = new File(target);

                if (fp.isDirectory() == true) {
                    fp = null;
                    targetNextUpdateByDirectory(lst, target, targetTime);
                } else {
                    long now = fp.lastModified();
                    fp = null;
                    if (now > targetTime) {
                        lst.add(new String(target));
                    }
                }
            }
        }

    }

}
