package charactermanaj.util;

import java.awt.Toolkit;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;


/**
 * デスクトップへのアクセスを提供するユーテリティ.<br>
 * JDK6の機能を使うため、JDK5以前では何もしない.(エラーにはならない)
 * @author seraphy
 */
public class DesktopUtilities {

	/**
	 * ロガー 
	 */
	private static final Logger logger = ApplicationLogger.getLogger();
	
	/**
	 * デスクトップオブジェクト。JDK6以降でなければ、もしくはデスクトップをサポートしていなければnull
	 */
	private static Object desktopObj;

	/**
	 * ブラウズメソッド
	 */
	private static Method methodBrowse;
	
	/**
	 * 編集メソッド
	 */
	private static Method methodEdit;

	/**
	 * 開くメソッド
	 */
	private static Method methodOpen;

	static {
		try {
			Class<?> clz = Class.forName("java.awt.Desktop");
			Method mtdGetDesktop = clz.getMethod("getDesktop");
			methodBrowse = clz.getMethod("browse", URI.class);
			methodEdit = clz.getMethod("edit", File.class);
			methodOpen = clz.getMethod("open", File.class);
			desktopObj = mtdGetDesktop.invoke(null);

		} catch (ClassNotFoundException ex) {
			// JDK6以降でない場合
			logger.log(Level.INFO, "AWT Desktop is not suuported.");
			desktopObj = null;
			
		} catch (Exception ex) {
			// その他の例外は基本的に発生しないが、発生したとしても
			// 単にサポートしていないと見なして継続する.
			logger.log(Level.SEVERE, "AWT Desktop failed.", ex);
			desktopObj = null;
		}
	}
	

	private DesktopUtilities() {
		throw new RuntimeException("utilities class.");
	}
	
	public static boolean isSupported() {
		return desktopObj != null;
	}
	
	protected static boolean callMethod(Method method, Object arg) throws IOException {
		if (desktopObj == null) {
			return false;
		}
		try {
			method.invoke(desktopObj, arg);
			return true;

		} catch (InvocationTargetException ex) {
			Throwable iex = ex.getCause();
			if (iex != null && iex instanceof IOException) {
				throw (IOException) iex;
			}
			throw new RuntimeException(ex.getMessage(), ex);

		} catch (IllegalAccessException ex) {
			throw new RuntimeException(ex.getMessage(), ex);
		}
	}

	/**
	 * ファイルを開く.
	 * @param uri ファイル
	 * @return サポートしていない場合はfalse、実行できればtrue。
	 * @throws IOException 実行できなかった場合
	 */
	public static boolean browse(URI uri) throws IOException {
		return callMethod(methodBrowse, uri);
	}
	
	/**
	 * 指定したdocBaseの親ディレクトリを開く.
	 * @param docBase
	 * @return サポートしていない場合はfalse、実行できればtrue。
	 * @throws IOException 実行できなかった場合
	 */
	public static boolean browseBaseDir(URL docBase) throws IOException {
		File baseDir = null;
		try {
			if (docBase != null) {
				baseDir = new File(docBase.getPath()).getParentFile();
			}
		} catch (Exception ex) {
			baseDir = null;
		}
		if (baseDir == null) {
			Toolkit tk = Toolkit.getDefaultToolkit();
			tk.beep();
			return false;
		}

		return DesktopUtilities.open(baseDir);
	}

	/**
	 * ファイルを編集する.
	 * @param file ファイル
	 * @return サポートしていない場合はfalse、実行できればtrue。
	 * @throws IOException 実行できなかった場合
	 */
	public static boolean edit(File file) throws IOException {
		return callMethod(methodEdit, file);
	}

	/**
	 * ファイルを編集する.
	 * @param file ファイル
	 * @return サポートしていない場合はfalse、実行できればtrue。
	 * @throws IOException 実行できなかった場合
	 */
	public static boolean open(File file) throws IOException {
		return callMethod(methodOpen, file);
	}
}
