package charactermanaj.util;

import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import charactermanaj.model.AppConfig;

public final class FileUtilities {

	private static final Method methodMoveToTrash = getMethodMoveToTrash();

	private FileUtilities() {
		super();
	}

	private static Method getMethodMoveToTrash() {
		try {
			// MOVE_TO_TRASHアクションを取得する(定義されていないバージョンの場合は実行時例外)
			Desktop.Action moveToTrashType = Enum.valueOf(Desktop.Action.class, "MOVE_TO_TRASH");

			// MOVE_TO_TRASHアクションがサポートされているか？
			Desktop desktop = Desktop.getDesktop();
			if (!desktop.isSupported(moveToTrashType)) {
				return null;
			}

			// moveToTrashメソッドを取得する。(定義されていなければ実行時例外)
			return Desktop.class.getMethod("moveToTrash", File.class);

		} catch (Exception ex) {
			return null;
		}
	}

	/**
	 * ゴミ箱が有効であるか？
	 * @return 有効であればtrue
	 */
	public static boolean isSupportMoveToTrash() {
		return methodMoveToTrash != null;
	}

	/**
	 * ゴミ箱にファイルまたはディレクトリを捨てる。
	 *
	 * @param file
	 * @throws IOException 削除に失敗した場合
	 */
	public static void moveToTrash(File file) throws IOException {
		if (file == null) {
			throw new NullPointerException();
		}

		if (!isSupportMoveToTrash()) {
			throw new UnsupportedOperationException("moveToTrash is not supported.");
		}

		if (!file.exists()) {
			return;
		}

		try {
			Desktop desktop = Desktop.getDesktop();
			Boolean ret = (Boolean) methodMoveToTrash.invoke(desktop, file);
			if (ret == null || !ret) {
				throw new IOException("failed to move to recyclebin. " + file);
			}

		} catch (IllegalAccessException ex) {
			throw new RuntimeException(ex);

		} catch (InvocationTargetException ex) {
			Throwable cause = ex.getCause();
			throw new IOException("failed to move to recyclebin. " + file, cause);
		}
	}

	/**
	 * 指定したファイルまたはディレクトリを削除します.<br>
	 * 指定した引数がディレクトリを示す場合、このディレクトリを含む配下のすべてのファイルとディレクトリを削除します.<br>
	 *
	 * @param file
	 *            ファイル、またはディレクトリ
	 * @throws IOException
	 *             削除できない場合
	 */
	public static void deleteRecursive(File file) throws IOException {
		if (file == null) {
			throw new IllegalArgumentException();
		}
		if (!file.exists()) {
			return;
		}
		if (file.isDirectory()) {
			File[] children = file.listFiles();
			if (children != null) {
				for (File child : children) {
					deleteRecursive(child);
				}
			}
		}
		if (!file.delete()) {
			throw new IOException("can't delete file. " + file);
		}
	}

	/**
	 * ファイルまたはフォルダを削除します。
	 * @param file
	 * @throws IOException
	 */
	public static void delete(File file) throws IOException {
		AppConfig appConfig = AppConfig.getInstance();
		if (isSupportMoveToTrash() && appConfig.isUseRecycleBinIfSupported()) {
			moveToTrash(file);
		} else {
			deleteRecursive(file);
		}
	}
}
