package jp.agentec.adf.util;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 外部プロパティファイルを扱うクラス<br>
 * 複数のプロパティファイルやINIファイル等を扱うことが可能。<br>
 * <br>
 * <strong>※本クラスは、jp.agentec.sinaburocast.common.utilから移管したものであります。</strong>
 *
 * @author tsukada, Taejin Hong
 * @version 2.0.0
 */
public class PropertyUtil {
	private static Map<String, Properties> propMap = new ConcurrentHashMap<String, Properties>();

    /**
     * プロパティファイルを読み込み、Propertiesオブジェクトとして返却
     *
     * @param file プロパティファイル(.propertiesは付けない)
     * @param reload true ファイルを再読み込みする。 false キャッシュしてある内容を返す
     * @return Propertiesオブジェクト
     * @throws IOException 
     */
	public static Properties getProperties(String file, boolean reload) throws IOException {
		Properties properties = propMap.get(file);
		if (properties == null || reload) {
			properties = loadProperies(file, ".properties");
		}
		return properties;
	}

	/**
	 * sinaburocast.propertiesの値を返す
	 *
	 * @param key キー値
	 * @return 値 (キーが存在しない場合空文字を返却)
	 */
	public static String getProperty(String key) throws IOException {
		return getProperty("sinaburocast", key, false);
	}

	/**
	 * プロパティを設定する(ただしファイルへは反映しない)
	 *
	 * @param file プロパティファイル名(.propertiesを除く)
	 * @param key キー名
	 * @param val 値
	 * @throws IOException 
	 */
	public static void setProperty(String file, String key, String val) throws IOException {
		Properties properties = propMap.get(file);
		if (properties == null) {
			properties = loadProperies(file, ".properties");
		}
		assert properties != null;
		properties.setProperty(key, val);
	}

	/**
	 * プロパティを再読み込みする。
	 *
	 * @param file プロパティファイル名(.propertiesを除く)
	 * @throws IOException 
	 */
	public static void reloadProperty(String file) throws IOException {
		loadProperies(file, ".properties");
	}

	/**
	 * プロパティを取得する
	 *
	 * @param file プロパティファイル名(.propertiesを除く)
	 * @param key キー値
	 * @param reload  true ファイルを再読み込みする。 false キャッシュしてある内容を返す
	 * @return
	 * @throws IOException 
	 */
	public static String getProperty(String file, String key, boolean reload) throws IOException {
		Properties properties = propMap.get(file);
		if (properties == null || reload) {
			properties = loadProperies(file, ".properties");
		}
		assert properties != null;
		return StringUtil.toString(properties.getProperty(key));
	}

	private static Properties loadProperies(String file, String ext) throws IOException {
		InputStream is = null;
		try {
			ClassLoader loader = Thread.currentThread().getContextClassLoader();
			URL url = loader.getResource(file + ext);
		    if (url != null) {
	            URLConnection connection = url.openConnection();
	            if (connection != null) {
	                connection.setUseCaches(false);
	                is = connection.getInputStream();
	            }
	        }
		    else {
		    	//LOGGER.warn("Resource was not found. [" + file + ext + "]");
		    	is = PropertyUtil.class.getResourceAsStream("/" + file + ext);
		    }
		} catch (IOException e) {
			//LOGGER.fatal("load " + file + ext + " failed.", e);
			throw e;
		}
		if (is == null) {
			return null;
		}
		return loadProperties(file, is);
	}

	private static Properties loadProperties(String file, InputStream is) throws IOException {
		Properties properties = new Properties();
		try {
			if (is == null) {
				//LOGGER.fatal("load properties failed: " + file + ".properties may not exist.");
			}
			else {
				properties.load(is);
				is.close();
			}
			propMap.put(file, properties);
		} catch (IOException e) {
			//LOGGER.fatal("load properties failed: " + file, e);
			try {
				is.close();
			} catch (IOException e1) {
				//LOGGER.error("", e1);
				throw e1;
			}
		}
		return properties;
	}

	/**
	 * sinaburocast.propertiesから値を取得して返す。<br>
	 *
	 * @param key キー名
	 * @return 値 (キーが存在しない場合空文字を返却)
	 */
	public static String getString(String key) throws IOException {
		return getProperty("sinaburocast", key, false);
	}

	/**
	 * sinaburocast.propertiesから値を取得し、boolean値を返す。<br>
	 *
	 * @param key キー名
	 * @return true:値が"true"の場合 false:それ以外の場合
	 */
	public static boolean getBoolean(String key) throws IOException {
		String str = getProperty("sinaburocast", key, false);
		return (str != null) && str.equals("true");
	}

	/**
	 * sinaburocast.propertiesから値を取得し、short値を返す。<br>
	 *
	 * @param key キー名
	 * @return short値(shortではない場合0を返却)
	 */
	public static short getShort(String key) throws IOException {
		String str = getProperty(key);
		return NumericUtil.parseShort(str);
	}

	/**
	 * sinaburocast.propertiesから値を取得し、int値を返す。<br>
	 *
	 * @param key キー名
	 * @return int値(intではない場合0を返却)
	 */
	public static int getInt(String key) throws IOException {
		String str = getProperty("sinaburocast", key, false);
		return NumericUtil.parseInt(str);
	}

	/**
	 * sinaburocast.propertiesから値を取得し、long値を返す。<br>
	 *
	 * @param key キー名
	 * @return long値(longではない場合0Lを返却)
	 * @throws IOException 
	 */
	public static long getLong(String key) throws IOException {
		String str = getProperty(key);
		return NumericUtil.parseLong(str);
	}

	/**
	 * sinaburocast.propertiesから値を取得し、カンマ区切りで分解し、リストとして返却する。<br>
	 *
	 * @param key キー名
	 * @return String List(キーが存在しない場合、空リストを返却)
	 */
	public static List<String> getList(String key) throws IOException {
		return getList(key, false);
	}

	public static List<String> getList(String key, boolean reload) throws IOException {
		return getList("sinaburocast", key, reload);
	}
	
	/**
	 * sinaburocast.propertiesから値を取得し、カンマ区切りで分解し、リストとして返却する。<br>
	 *
	 * @param key キー名
	 * @param reload リロードするか否か
	 * @return String List(キーが存在しない場合、空リストを返却)
	 * @throws IOException 
	 */
	public static List<String> getList(String file, String key, boolean reload) throws IOException {
		String str = getProperty(file, key, reload);
		String[] vals = StringUtil.split(str, ",");
		
		ArrayList<String> list = new ArrayList<String>();
		for (String val : vals) {
			list.add(val.trim());
		}
		return list;
	}

    public static Map<String, Object> getPropertiesStartWith(final String key) throws IOException {
        Properties properties = propMap.get("sinaburocast");
        if (properties == null) {
            properties = loadProperies("sinaburocast", ".properties");
        }

        Map<String, Object> pMap = new HashMap<String, Object>();
        if (properties != null) {
            for (Object pKey : properties.keySet()) {
                String pKeyStr = (String) pKey;
                if (pKeyStr.startsWith(key)) {
                    pMap.put(pKeyStr, properties.getProperty(pKeyStr));
                }
            }
        }
        return pMap;
    }
}