/*
 * Indexer
 * 転置インデックスを作成するクラス
 */
package org.logical_paradox.fts;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;

public final class Indexer {
	private final String contentsDirectory;
	protected final IndexAccessor accessor;			// 転置インデックスデータファイルにアクセスするためのインターフェース
//	protected final Parser parser;

	/*
	 * コンストラクタ
	 */
	public Indexer(String dirname) throws Exception {
		contentsDirectory = dirname;
		accessor = IndexAccessorFactory.getIndexAccessor(FullTextSearchProperty.FTS_INDEX_PROPERTY_NAME);
//		parser = new Parser( accessor, FullTextSearchProperty.GRAM_LENGTH );
	}

	/*
	 * 参照しているコンテンツディレクトリを返す
	 */
	public String getContentsDirectory() {
		return contentsDirectory;

	}

	/*
	 * 指定されたディレクトリに格納されている文書のファイル名を配列にして返す
	 */
	public File[] documents() throws IOException {
		return new File( contentsDirectory ).listFiles();
	}

	/*
	 * 全てのファイルを解析する
	 */
	public void parseAllFiles() throws Exception {
		File[] files = documents();
		int parserno = 0;
		ConcurrentParser[] parsers = new ConcurrentParser[files.length];
		HashMap map =  new HashMap();

		for( int i = 0; i < files.length; i++ ) {
			if(files[i].isFile() == false) {
				// ディレクトリは無視する
				continue;
			}
			System.err.println( "processing: " + files[i] );

			BufferedReader br = new BufferedReader( new InputStreamReader( new FileInputStream( files[i] ), "UnicodeBig" ) );
			StringBuffer sb = new StringBuffer();
			String line = null;

			while( (line = br.readLine()) != null ) {
				sb.append( line );
			}
			br.close();

			parsers[parserno] = new ConcurrentParser(accessor, map, sb.toString(), i);
			parsers[parserno].start();
			parserno++;
		}
		// 解析処理の待ち合わせ
		for(int i = 0; i < parserno; i++) {
			parsers[i].join();
		}

		// 解析結果をストレージへ書き込む
		for(Iterator it = map.keySet().iterator(); it.hasNext();) {
			Key k = (Key)it.next();
			if(k == null) {
				continue;
			}
			KeywordLocationArray kla = (KeywordLocationArray)map.get(k);
			if(kla != null) {
				accessor.addKey(k, kla);
			}
		}
		// ファイルを閉じる
		accessor.close();
	}

	/*
	 * 閉じる
	 */
	public void close() throws Exception {
		if( accessor.isClosed() == false ) {
			accessor.close();
		}
	}

	/*
	 * 起動メソッド
	 */
	public static void main( String[] args ) throws Exception {
		String dirname = null;
		if( args.length == 0 ) {
			dirname = "db";
		} else {
			dirname = args[0];
		}

		System.out.println("開始: " + Calendar.getInstance().getTime());

		Indexer idxr = new Indexer( dirname );
		idxr.parseAllFiles();
		idxr.close();

		System.out.println("終了: " + Calendar.getInstance().getTime());
		System.err.println( "done." );
	}

	class ConcurrentParser extends Thread {
		private IndexAccessor axsr;
		private String doc;
		private int dicno;
		private HashMap map;

		ConcurrentParser(IndexAccessor a, HashMap m, String d, int n) {
			axsr = a;
			doc = d;
			dicno = n;
			map = m;
		}
		public void run() {
			Parser p = new Parser(axsr, map, FullTextSearchProperty.GRAM_LENGTH);
			try {
				p.parse(doc, dicno);
			} catch(IndexAccessException iae) {
				iae.printStackTrace();
			}
		}
	}
}

// end of Indexer.java
