/*
 * LOGICAL-PARADOX.ORG
 * Copyright (C)2005 satoshi akabane(akabane@logical-paradox.org)
 * $Id: KoikeConfig.java,v 1.6 2006/02/21 13:16:52 akabane Exp $
 */
package org.logical_paradox.koike.core;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Properties;

import org.logical_paradox.common.charset.CharsetUtils;
import org.logical_paradox.common.util.StringUtils;
import org.logical_paradox.koike.core.search.SearchEngine;

/**
 * コンフィグレーション
 * @author satoshi akabane@logical-paradox.org
 * @version $Revision: 1.6 $
 */
public class KoikeConfig implements KoikeConstant {
	/** デフォルトのインデクサスレッド数 */
	public static final int DEFAULT_INDEXER_THREADS = 3;
	/** デフォルトのn-gram数 */
	public static final int DEFAULT_N_GRAM_TERM_LENGTH = 2;
	/** デフォルトの索引語エンコーディング */
	public static final String DEFAULT_TERM_ENCODING = System.getProperty("file.encoding");

	/** マスターのプロパティ */
	private Properties masterProperty;
	/** サーチエンジン */
	private SearchEngine searchEngine;
	/** 具象インターフェースファクトリ */
	private ConcreteInterfaceFactory interfaceFactory;
	/** 具象インターフェースファクトリの初期化パラメータ */
	private String initialParameter;
	/** 解析待ちキューが空になった際にインデクサを停止するかどうか */
	private boolean waitOnEmpty = false;
	/** インデクサのスレッド数 */
	private int indexerThreads = DEFAULT_INDEXER_THREADS;
	/** N-gram数 */
	private int ngramTermLength = DEFAULT_N_GRAM_TERM_LENGTH;
	/** 索引語のエンコーディング */
	private String termEncoding = DEFAULT_TERM_ENCODING;
	/** 索引語のエンコーディング変換の必要があるかどうか(true:ある / false:ない) */
	private boolean needToEncode = true;

	/**
	 * コンストラクタ
	 * @param prop プロパティ
	 */
	public KoikeConfig(Properties prop) throws KoikeConfigException {
		marshall(prop);
	}
	/**
	 * 指定されたプロパティファイルを元にして，このインスタンスのプロパティを設定する
	 * @param prop プロパティファイル
	 */
	protected void marshall(Properties prop) throws KoikeConfigException {
		masterProperty = prop;
		try {
			// INTERFACE_FACTORY
			String factoryName = prop.getProperty(KEY_INTERFACE_FACTORY);
			if(factoryName == null || factoryName.trim().length() == 0) {
				throw new IllegalArgumentException("必須項目[INTERFACE_FACTORY]がありません");
			}
			Constructor constructor = Class.forName(factoryName).getConstructor(new Class[] {String.class});
			// INTERFACE_FACTORY_INITPARAM
			initialParameter = prop.getProperty(KEY_INTERFACE_FACTORY_INITPARAM);
			interfaceFactory = (ConcreteInterfaceFactory)constructor.newInstance(initialParameter);

			// N_GRAM_TERM_LENGTH
			String ngramTermLengthStr = prop.getProperty(KEY_N_GRAM_TERM_LENGTH);
			if(ngramTermLengthStr == null || ngramTermLengthStr.trim().length() == 0) {
				ngramTermLength = DEFAULT_N_GRAM_TERM_LENGTH;
			} else {
				ngramTermLength = Integer.parseInt(ngramTermLengthStr);
			}
			// INDEXER_THREADS
			String threadCountStr = prop.getProperty(KEY_INDEXER_THREADS);
			if(threadCountStr != null && threadCountStr.trim().length() > 0) {
				indexerThreads = Integer.parseInt(threadCountStr);
			} else {
				indexerThreads = DEFAULT_INDEXER_THREADS;
			}
			// KEY_WAIT_ON_EMPTY
			String waitOnEmptyStr = prop.getProperty(KEY_WAIT_ON_EMPTY);
			if(waitOnEmptyStr != null && waitOnEmptyStr.trim().length() > 0) {
				waitOnEmpty = Boolean.valueOf(waitOnEmptyStr).booleanValue();
			} else {
				waitOnEmpty = false;
			}
			// INDEX_TERM_ENCODING
			String indexTermEncoding = prop.getProperty(INDEX_TERM_ENCODING);
			if(StringUtils.isEmpty(indexTermEncoding) == false) {
				termEncoding = indexTermEncoding;
			}
			// エンコーディング変換の必要があるかどうかテストする．
			needToEncode = CharsetUtils.testNeedToEncode(termEncoding);
		} catch(Exception e) {
			throw new KoikeConfigException(e);
		}
	}
	/**
	 * インデクサスレッド数を返す
	 * @return インデクサスレッド数
	 */
	public int getIndexerThreads() {
		return indexerThreads;
	}

	/**
	 * 具象インターフェースファクトリ用の初期化パラメータを返す
	 * @return 初期化パラメータ
	 */
	public String getInitialParameter() {
		return initialParameter;
	}

	/**
	 * 具象インターフェースファクトリを返す
	 * @return 具象インターフェースファクトリ
	 */
	public ConcreteInterfaceFactory getInterfaceFactory() {
		return interfaceFactory;
	}

	/**
	 * N-gram数を返す
	 * @return N-gram数
	 */
	public int getNgramTermLength() {
		return ngramTermLength;
	}

	/**
	 * サーチエンジンを返す
	 * @return サーチエンジン
	 */
	public SearchEngine getSearchEngine() throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
		if(searchEngine == null) {
			// サーチエンジンがまだロードされていない場合，ロードする
			String searchEngineClass = masterProperty.getProperty(KoikeConstant.KEY_SEARCH_ENGINE_CLASS);
			if(searchEngineClass != null && searchEngineClass.trim().length() > 0) {
				Class clazz = Class.forName(searchEngineClass);
				Constructor cstr = clazz.getConstructor(new Class[]{KoikeConfig.class});
				searchEngine = (SearchEngine)cstr.newInstance(new Object[]{this});
			}
		}
		return searchEngine;
	}

	/**
	 * キューに何もなくなった際に、終了するかどうかを返す
	 * @return true:新しいドキュメントを待つ / false:終了する
	 */
	public boolean isWaitOnEmpty() {
		return waitOnEmpty;
	}
	/**
	 * 索引語のエンコーディング．
	 * @return エンコーディング
	 */
	public String getTermEncoding() {
		return termEncoding;
	}
	/**
	 * 索引語のエンコーディング変換をする必要があるかどうか．
	 * @return true:ある / false:ない
	 */
	public boolean isNeedToEncode() {
		return needToEncode;
	}
}
