import java.io.*;
import java.nio.channels.*;

class FileUtils {
    public static final String BACKUP_EXT = ".backup";

    /**
     * 単一のファイルをコピーする
     * @param src	コピー元ファイル
     * @param dst	コピー先ファイル(ディレクトリは指定不可)
     * @param preserve	最終更新日を保持するかのフラグ
     */
    public static void copyFile(File src, File dst, boolean preserve) throws IOException {
	FileChannel srcChan = new FileInputStream(src).getChannel();
	FileChannel destChan = new FileOutputStream(dst).getChannel();
	srcChan.transferTo(0, srcChan.size(), destChan);
	srcChan.close();
	destChan.close();

	// 最終更新日をコピー
	if(preserve)
	    dst.setLastModified(src.lastModified());
    }

    /**
     * ファイルを再帰的にコピーする
     * @param src	コピー元
     * @param dst	コピー先
     * @param preserve	最終更新日を保持するかのフラグ
     */
    public static void copyRecursive(File src, File dst, boolean preserve) throws IOException {
	if(src.isFile()) {
	    copyFile(src, dst, preserve);
	    return;
	}

	if(src.isDirectory()) {
	    String[] entries = src.list();
	    for(int i = 0; i < entries.length; i++) {
		File src2 = new File(src, entries[i]);
		File dst2 = new File(dst, entries[i]);
		if(src2.isFile())
		    copyFile(src2, dst2, preserve);
		else if(src2.isDirectory())
		    copyRecursive(src2, dst2, preserve);
		else
		    throw new RuntimeException(src2.getPath()
					       + " is not file nor directory");
	    }
	}

	throw new RuntimeException(src.getPath()
				   + " is not file nor directory");
    }

    /**
     * 最終更新時刻を保持してバックアップを作成する
     */
    public static void makeBackupFile(File file) throws IOException {
	makeBackupFile(file, true);
    }

    /**
     * ファイルのバックアップを作成する
     */
    public static void makeBackupFile(File file, boolean preserve) throws IOException {
	if(!file.exists())
	    return; // オリジナルが存在しないなら何もしない

	File backup = new File(file.getPath() + BACKUP_EXT);
	if(backup.exists())
	    return; // バックアップが存在するなら何もしない

	copyFile(file, backup, preserve);
    }

    /**
     * ファイルを空に切り詰める。
     * この時にまだバックアップされてなかったら、バックアップも作成する。
     */
    public static void truncate(File file) throws IOException {
	File backup = new File(file.getPath() + BACKUP_EXT);
	if(backup.isFile()) {
	    file.delete();
	    touch(file);
	} else {
	    file.renameTo(backup);
	    touch(file);
	}
    }

    /**
     * ファイルの最終更新時刻を更新する。ファイルが存在しない場合は作成する。
     */
    public static void touch(File file) throws IOException {
	if(!file.exists())
	    (new FileOutputStream(file)).close();
	if(!file.isFile())
	    return; // ノータッチ
	file.setLastModified((new java.util.Date()).getTime());
    }
}
