package org.phosphoresce.commons.util;

import java.awt.Image;
import java.awt.Toolkit;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;

import javax.swing.ImageIcon;

/**
 * リソースユーティリティクラス<br>
 * <br>
 * 当クラスはクラスローダが提供するリソース、ファイルシステム上のリソースを
 * 意識せずにリソースアクセスを行うために設けたユーティリティクラスです。<br>
 *
 * @author Kitagawa<br>
 *
 *<!--
 * 更新日		更新者			更新内容
 * 2009/04/16	Kitagawa		新規作成
 * 2009/12/20	Kitagawa		{@link #getURL(String)}をpublic化
 * 2010/07/05	Kitagawa		isExistResource追加
 *-->
 */
public final class ResourceUtil {

	/** バイトバッファサイズ */
	private static final int BYTE_BUFFER = 2048;

	/**
	 * コンストラクタ<br>
	 */
	private ResourceUtil() {
		super();
	}

	/**
	 * 指定されたリソースパスからリソースURLを取得します。<br>
	 * URL変換対象リソースパスはクラスローダから提供されるリソース、
	 * ファイルシステムから提供されるリソースの順序で検索が行われます。<br>
	 * @param name リソースパス
	 * @return 指定されたリソースパスのURLオブジェクト
	 * @throws IOException 指定されたリソース名からURLに変換することが出来なかった場合にスローされます
	 */
	public static URL getURL(String name) throws IOException {
		URL url = null;

		url = ResourceUtil.class.getResource(name);
		if (url == null) {
			url = ResourceUtil.class.getResource("/" + name);
		}
		if (url == null) {
			File file = new File(name);
			//if (file.exists()) {
			url = file.toURL();
			//}
		}

		if (url == null) {
			throw new IllegalArgumentException("指定されたリソースパス" + name + "からURLオブジェクトに変換できませんでした");
		}

		return url;
	}

	/**
	 * 指定されたリソースがリソースパス又はファイルシステムに存在するか判定します。<br>
	 * @param name リソースパス
	 * @return 指定したリソースが存在する場合にtrueを返却します
	 * @throws IOException リソースの存在チェックが正しく行えなかった場合にスローされます
	 */
	public static boolean isExistResource(String name) throws IOException {
		try {
			return new File(new URI(getURL(name).toString())).exists();
		} catch (URISyntaxException e) {
			throw new IOException(e.getMessage());
		}
	}

	/**
	 * 指定されたリソースパスから入力ストリームを取得します。<br>
	 * @param name リソースパス
	 * @return 入力ストリームオブジェクト
	 * @throws IOException ストリーム操作時に入出力例外が発生した場合にスローされます
	 */
	public static InputStream getInputStream(String name) throws IOException {
		return getURL(name).openStream();
	}

	/**
	 * 指定されたリソースパスからイメージを取得します。<br>
	 * @param name リソースパス
	 * @return イメージオブジェクト
	 * @throws IOException 不正なリソースパスが指定された場合にスローされます
	 */
	public static Image getImage(String name) throws IOException {
		return Toolkit.getDefaultToolkit().getImage(getURL(name));
	}

	/**
	 * 指定されたリソースパスからイメージアイコンを取得します。<br>
	 * @param name リソースパス
	 * @return イメージアイコンオブジェクト
	 * @throws IOException 不正なリソースパスが指定された場合にスローされます
	 */
	public static ImageIcon getImageIcon(String name) throws IOException {
		return new ImageIcon(getImage(name));
	}

	/**
	 * 指定されたリソースパスからテキストを取得します。<br>
	 * @param name リソースパス
	 * @return リソース内に記述されている文字列
	 * @throws IOException ストリーム操作時に入出力例外が発生した場合にスローされます
	 */
	public static String getText(String name) throws IOException {
		BufferedReader reader = new BufferedReader(new InputStreamReader(getInputStream(name)));
		StringBuffer buffer = new StringBuffer();
		while (reader.ready()) {
			buffer.append(reader.readLine());
			if (reader.ready()) {
				buffer.append("\n");
			}
		}
		reader.close();
		return buffer.toString();
	}

	/**
	 * 指定されたリソースパスからバイトデータを取得します。<br>
	 * @param name リソースパス
	 * @return リソースデータバイト配列
	 * @throws IOException ストリーム操作時に入出力例外が発生した場合にスローされます
	 */
	public static byte[] getBytes(String name) throws IOException {
		InputStream inputStream = getInputStream(name);
		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		int length = -1;
		byte[] buffer = new byte[BYTE_BUFFER];
		while ((length = inputStream.read(buffer)) != -1) {
			outputStream.write(buffer, 0, length);
		}
		byte[] result = outputStream.toByteArray();

		inputStream.close();
		outputStream.close();

		return result;
	}

	/**
	 * 指定されたリソースパスからシリアライズされたオブジェクトを読み込みます。<br>
	 * @param name リソースパス
	 * @return 復元されたオブジェクト
	 * @throws IOException ストリーム操作時に入出力例外が発生した場合にスローされます
	 * @throws ClassNotFoundException シリアライズオブジェクトのクラスが不明な場合にスローされます
	 */
	public static Object getObject(String name) throws IOException, ClassNotFoundException {
		ObjectInputStream inputStream = new ObjectInputStream(getInputStream(name));
		Object object = inputStream.readObject();
		inputStream.close();
		return object;
	}
}
