/*
 * $Id: IndexerThread.java,v 1.7 2006/02/21 13:16:52 akabane Exp $
 * Copyright (c) 2004 LOGICAL-PARADOX.ORG
 */
package org.logical_paradox.koike.core.indexer;

import java.util.Iterator;

import org.logical_paradox.common.charset.CharsetUtils;
import org.logical_paradox.koike.core.KoikeConfig;
import org.logical_paradox.koike.core.document.DocumentAccessor;
import org.logical_paradox.koike.core.logging.LogFactory;
import org.logical_paradox.koike.core.logging.Logger;
import org.logical_paradox.koike.core.parser.Parser;
import org.logical_paradox.koike.core.parser.Term;

/**
 * インデクサスレッド
 * 
 * @author satoshi akabane@logical-paradox.org
 * @version $Revision: 1.7 $
 */
public class IndexerThread extends Thread {
	/** インデックスシステムに接続しているインターフェース */
	private IndexAccessor idxAccessor;
	/** コンテンツ管理システムに接続しているインターフェース */
	private DocumentAccessor docAccessor;
	/** リモートキューシステムに接続しているインターフェース */
	private Iterator ri;
	/** コンフィグレーション */
	private final KoikeConfig config;

	// ロガー
	private Logger log = LogFactory.getLogger();

	// パーザー
	private final Parser parser;

	/**
	 * コンストラクタ
	 * @param cfg コンフィグ
	 */
	public IndexerThread(KoikeConfig cfg) throws Exception {
		config = cfg;

		// インデックスサーバー用の接続インターフェース
		idxAccessor = config.getInterfaceFactory().getIndexAccessor();
		// コンテンツ管理システムの接続インターフェース
		docAccessor = config.getInterfaceFactory().getDocumentAccessor();
		// リモートキューシステムに接続しているイテレータ
		ri = config.getInterfaceFactory().getRemoteQueueIterator();

		// n-gramパーザー
		parser = new Parser(config.getNgramTermLength());
	}

	/**
	 * スレッドメイン
	 */
	@Override
	public void run() {
		log.write("**** スレッド[" + this.toString() + "]がインデクシングを開始しました");

		// キューに処理するべきコンテンツが残っている間継続する
		// キューに何か残っている間は処理がblockされる
		boolean loopc = true;
		try {
			while(loopc) {
				String digest = null;
				while((digest = getDigest()) != null) {
					String contents = null;
					try {
						log.write("ダイジェスト[" + digest + "]を解析しています");
						// 取得できたダイジェストでコンテンツファインダーを稼動させる
						contents = docAccessor.getDocument(digest).getDocument();
						// エンコーディング変換が必要である場合，最初にまとめて変換しておく
						if(config.isNeedToEncode()) {
							log.write("索引語のエンコーディングを変換しています[" + System.getProperty("file.encoding") + " → " + config.getTermEncoding());
							contents = CharsetUtils.encode(config.getTermEncoding(), contents);
						}
						// パース
						Term[] terms = parser.parse(contents);
						// インデックスサーバーへの登録(あとのことはまかせた)
						transfer(digest, terms);
					} catch (Exception e) {
						e.printStackTrace();
						log.write("ダイジェスト[" + digest + "]がコンテンツ管理システムにありません");
					}
				}

				if(config.isWaitOnEmpty() == false) {
					log.write("waitonemptyフラグがfalseのため、インデクシングを終了します");
					loopc = false;
					continue;
				}
				// スリープ
				Thread.sleep(2000);
			}
		} catch(InterruptedException ie) {
			tearDown();
		}
		log.write("**** スレッド[" + this.toString() + "]がインデクシングを終了しました");
	}
	/**
	 * キューシステムからダイジェストを取り出して返す
	 * Iterator.hasNext()とnext()に対してsynchronizedを適用するために作ったメソッド
	 * @return
	 */
	protected String getDigest() {
		synchronized(ri) {
			if(ri.hasNext() == false) {
				return null;
			} else {
				return (String)ri.next();
			}
		}
	}
	/**
	 * インデックスサーバーに対して，索引語と位置情報をある程度まとめて送信する．
	 * 何個単位で転送するかは，このメソッドにゆだねられる
	 * @param digest ドキュメントのダイジェスト
	 * @param terms 転送しなければならない索引語
	 * @throws Exception 転送中に発生した例外
	 */
	protected void transfer(String digest, Term[] terms) throws Exception {
		// とりあえず全部まとめておくっとけ
		idxAccessor.addTerm(digest, terms);
	}
	/**
	 * スレッドの停止処理
	 */
	protected void tearDown() {
		log.write("**** スレッドが停止します ****");
		// インデックスシステムとの接続インターフェースをクローズする
		try {
			synchronized(idxAccessor) {
				if(idxAccessor != null && idxAccessor.isClosed() == false) {
					idxAccessor.close();
					idxAccessor = null;
				}
			}
		} catch(IndexAccessException e) {
			log.write("**** インデックスシステムとの接続インターフェースのクローズに失敗しました");
		}
		// ドキュメントリソースの接続インターフェースをクローズする
		try {
			synchronized(docAccessor) {
				if(docAccessor != null && docAccessor.isClosed() == false) {
					docAccessor.close();
					docAccessor = null;
				}
			}
		} catch(Exception e) {
			log.write("**** ドキュメントリソースの接続インターフェースのクローズに失敗しました");
		}
		log.write("**** スレッドが停止しました ****");
	}
}
