package daruma.util;

import java.io.*;
import java.util.Properties;
import java.util.ArrayList;

import daruma.util.LogWriter;

/**
 * Propertyファイル取得用クラス<BR>
 * 外部ファイル設定値を読み込むためのクラスです。
 */
public class PropertyReader {
	// 標準のPropertyファイル名
	private final static String DEFAULT_PROPERTY_FILE = "daruma.properties";

	// Propertyファイル名を示すシステムプロパティ名
	private final static String PROPERTY_NAME = "daruma.properties";

	private static String cPropertyFile;

	// プロパティファイルのオブジェクト
	private static Properties prop = null;

	/**
	 * コンストラクタ。<BR>
	 * サーバの起動時に1度だけ呼ばれ、Property値をHashTableに格納します。<BR>
	 * このクラスによるProperty値の読み込みによって、ログ設定ファイルパスを
	 * 確認するため、このクラスからのログ出力はありません。<BR>
	 *
	 * @exception FileNotFoundException プロパティファイルが存在しない場合<BR>
	 * @exception IOException プロパティファイルの入力エラー発生した場合<BR>
	 */
	private static void initialize() throws FileNotFoundException {
	    initialize( System.getProperty( PROPERTY_NAME,
					    DEFAULT_PROPERTY_FILE) );
	}

	public static void initialize( String path )
	    throws FileNotFoundException {
	    cPropertyFile = path;

	    initialize( new FileInputStream(cPropertyFile) );
	}

	public static void initialize( InputStream in ) {
		try {
			// Propertyファイルを読み込む
			prop = new Properties();

			// プロパティリストを読み込む
			prop.load(in);
		} catch (FileNotFoundException e) {
			// ファイルが存在しない場合
			System.err.println("ERROR [PropertyReader] " + e.getMessage());
			e.printStackTrace();
			throw new RuntimeException(e.getMessage());
		} catch(IOException e) {
			// 入出力に失敗した場合
			System.err.println("ERROR [PropertyReader] " + e.getMessage());
			e.printStackTrace();
			throw new RuntimeException(e.getMessage());
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch(IOException e) {
					System.err.println("ERROR [PropertyReader] " + e.getMessage());
					e.printStackTrace();
					throw new RuntimeException(e.getMessage());
				}
			}
		}
	}

	/**
	 * プロパティファイルからProperty値を取得します。<BR>
	 * デフォルト値設定がない場合に呼ばれます。<BR>
	 * Property値が存在しない場合はnullを返します。<BR>
	 * @param propName Property名
	 * @return プロパティファイルから取得した文字列型のプロパティ値
	 */
	public static String getProperty(String propName) {
		return getProperty(propName, null);
	}

	/**
	 * プロパティファイルからProperty値を取得します。<BR>
	 * Property名に対応する値が見つからない場合は、
	 * 設定されたデフォルト値を返却します。<BR>
	 *
	 * @param propName Property名
	 * @param def プロパティ名が見つからない時のデフォルト値
	 * @return プロパティファイルから取得した文字列型のプロパティ値
	 */
	public static String getProperty(String propName, String def) {

		if(prop == null) {
			try {
				initialize();
			} catch( FileNotFoundException e ) {
				e.printStackTrace();
			}
		}

		return prop.getProperty(propName, def);
	}

	/**
	 * プロパティファイルからProperty値を取得します。<BR>
	 * Property名に対応する値が見つからない場合は、
	 * デフォルト値を返却します。<BR>
	 * またデフォルト値がboolean型にキャストできなかった場合は、
	 * falseを返します。
	 *
	 * @param propName Property名
	 * @param def プロパティ名が見つからない時のデフォルト値
	 * @return プロパティファイルから取得したboolean型のプロパティ値
	 */
	public static boolean getProperty(String propName, boolean def) {
		String value = Boolean.toString(def);

		return getPropertyBoolean(propName, value);
	}

	/**
	 * プロパティファイルからProperty値を配列で取得します。<BR>
	 * Property名に対応する値が見つからない場合は、
	 * nullを返却します。<BR>
	 *
	 * @param propName Property名
	 * @return プロパティファイルから取得したArrayList型のプロパティ値
	 */
	public static ArrayList getArrayProperty(String propName) {
		int i = 0;
		ArrayList<String> array_value = new ArrayList<String>();
		while (true) {
			// PropertyKEYの作成
			String array_kind = propName + "." + i;
			// Property値の取得
			String result = getProperty(array_kind);
			if (result != null) {
				// ArrayListへ格納
				array_value.add(result);
			} else {
				break;
			}
			i++;
		}
		return array_value;
	}

	/**
	 * プロパティファイルからProperty値をint型で取得します。<BR>
	 * デフォルト値設定がない場合に呼ばれます。<BR>
	 *
	 * @param propName Property名
	 * @return プロパティファイルから取得したint型のプロパティ値
	 */
	public static int getPropertyInt(String propName) {
		return getProperty(propName, 0);
	}

	/**
	 * プロパティファイルからProperty値をint型で取得します。<BR>
	 * Property名に対応する値が見つからない場合は、
	 * 0を返却します。<BR>
	 *
	 * @param propName Property名
	 * @param def デフォルト値
	 * @return プロパティファイルから取得したint型のプロパティ値
	 */
	public static int getProperty(String propName, int def) {
		String value = getProperty(propName, Integer.toString(def));
		int result = 0;
		try {
			// 値が存在しないときは設定されたデフォルト値
			if (value == null) {
				result = def;
			} else {
				result = Integer.parseInt(value);
			}
		} catch (NumberFormatException e) {
			// エラーログを出力して、throwする
			System.err.println("ERROR [PropertyReader:getProperty]" + e.getMessage());
			throw new NumberFormatException(e.getMessage());
		}
		return result;
	}

	/**
	 * プロパティファイルからProperty値を取得します。<BR>
	 * Property名に対応する値が見つからない場合は、
	 * デフォルト値を返却します。<BR>
	 * また取得した値がboolean型にキャストできなかった場合は、
	 * falseを返します。
	 *
	 * @param String Property名
	 * @param boolean デフォルト値
	 */
	private static boolean getPropertyBoolean(String propName, String def) {
		String value = getProperty(propName, def);
		boolean result = Boolean.valueOf(def).booleanValue();
		// 値が存在しないときは設定されたデフォルト値
		if (value != null) {
			if ( ! value.equals( "true" )
			     && ! value.equals( "false" ) )
			{
				// エラーログを出力する。
				LogWriter.qwrite
				    ( "ERROR",
				      "invalid property value, ",
				      "property name = [", propName, "], ",
				      "value = [", value, "]" );

				System.exit( 1 );
			}

			// 取得した値がboolean型にキャストできないときは、
			// デフォルトでfalseを返す。
			result = Boolean.valueOf(value).booleanValue();
		}

		return result;
	}

	/**
	 * 現在使用中のプロパティファイルの名前を示す
	 */
	public static String getFileName() {
		if (prop == null) {
			try {
				initialize();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
		}

		return cPropertyFile;
	}

	public static String getDefaultPropertyFile() {
		return DEFAULT_PROPERTY_FILE;
	}
}
