/*
 * Copyright (c) 2009 The openGion Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package org.opengion.plugin.io;

import java.io.BufferedReader;
import java.io.IOException;

import org.opengion.fukurou.util.StringUtil;
import org.opengion.hayabusa.common.HybsSystem;
import org.opengion.hayabusa.common.HybsSystemException;
import org.opengion.hayabusa.db.DBTableModelUtil;
import org.opengion.hayabusa.io.AbstractTableReader;

/**
 * 指定の区切り記号(初期値:タブ区切り)ファイルの読み取りクラスです。
 *
 * 名前，データの入力部のみオーバーライドすれば，各種入力フォーマットに合わせた
 * サブクラスを実現する事が可能です。
 *
 * @og.group ファイル入力
 *
 * @version  4.0
 * @author   Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
public class TableReader_Default extends AbstractTableReader {
	//* このプログラムのVERSION文字列を設定します。	{@value} */
	private static final String VERSION = "5.2.1.0 (2010/10/01)" ;

	/**
	 * DBTableModel から 各形式のデータを作成して,BufferedReader より読み取ります。
	 * コメント/空行を除き、最初の行は、必ず項目名が必要です。
	 * それ以降は、コメント/空行を除き、データとして読み込んでいきます。
	 * このメソッドは、EXCEL 読み込み時に使用します。
	 *
	 * @og.rev 4.0.0 (2006/09/31) 新規追加
	 * @see #isExcel()
	 */
	@Override
	public void readDBTable() {
		String errMsg = "このクラスでは実装されていません。";
		throw new UnsupportedOperationException( errMsg );
	}

	/**
	 * DBTableModel から 各形式のデータを作成して,BufferedReader より読み取ります。
	 * コメント/空行を除き、最初の行は、必ず項目名が必要です。
	 * それ以降は、コメント/空行を除き、データとして読み込んでいきます。
	 *
	 * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
	 * @og.rev 3.5.4.2 (2003/12/15) writer の null チェックを廃止します。
	 * @og.rev 3.5.4.3 (2004/01/05) 引数に、BufferedReader を受け取ル要に変更します。
	 * @og.rev 3.5.4.5 (2004/01/23) カラム名の外部指定を優先して使用する。
	 * @og.rev 5.1.6.0 (2010/05/01) readDBTableのエラーチェック強化
	 * @og.rev 5.1.6.0 (2010/05/01) skipRowCountの追加
	 * @og.rev 5.2.0.0 (2010/09/01) ""で囲われているデータに改行が入っていた場合の対応
	 * @og.rev 5.2.1.0 (2010/10/01) AbstractTableReader.java と重複している箇所の対応
	 *
	 * @param   reader BufferedReaderオブジェクト
	 */
	@Override
	public void readDBTable( final BufferedReader reader ) {
		try {
			String line;
			String[] names = null;
			int numberOfRows = 0;
//			char  sepa = separator.charAt( 0 );
			char  sepa = getSeparator().charAt( 0 );	// 5.2.0.0 (2010/09/01)

			boolean nameNoSet = true;
			table = DBTableModelUtil.newDBTable();

			// 3.5.4.5 (2004/01/23) カラム名の外部指定を優先して使用する。
			if( columns != null && columns.length() > 0 ) {
				names = StringUtil.csv2Array( columns );
				table.init( names.length );
				setTableDBColumn( names ) ;
				nameNoSet = false;
			}

//			int skip = skipRowCount;						// 5.1.6.0 (2010/05/01)
			int skip = getSkipRowCount();					// 5.2.0.0 (2010/09/01)
			while((line = reader.readLine()) != null) {
				// 5.2.0.0 (2010/09/01) ""で囲われているデータに改行が入っていた場合の対応
//				int quotCount = StringUtil.countChar( line, '"' );
//				if( quotCount % 2 == 1 ) {
//					String addLine = null;
//					while(quotCount % 2 == 1 && (addLine = reader.readLine()) != null) {
//						line +=  HybsSystem.CR + addLine;
//						quotCount += StringUtil.countChar( addLine, '"' );
//					}
//				}
				// 5.2.1.0 (2010/10/01) findbugs 対策(文字列の + 連結と、奇数判定ロジック)
				int quotCount = StringUtil.countChar( line, '"' );
				if( quotCount % 2 != 0 ) {
					String addLine = null;
					StringBuilder buf = new StringBuilder( line );
					while(quotCount % 2 != 0 && (addLine = reader.readLine()) != null) {
						buf.append( HybsSystem.CR ).append( addLine );
						quotCount += StringUtil.countChar( addLine, '"' );
					}
					line = buf.toString();
				}

				if( skip > 0 ) { skip--; continue; }		// 5.1.6.0 (2010/05/01)
				if( line.length() == 0 ) { continue; }
				if( line.charAt( 0 ) == '#' ) {
					String key = line.substring( 0,5 );
					if( nameNoSet && ( key.equalsIgnoreCase( "#NAME" ) )) {
						// 超イレギュラー処理 最初の TAB_SEPARATOR 以前の文字は無視する。
						String line2 = line.substring( line.indexOf( sepa )+1 );
						names = StringUtil.csv2Array( line2 ,sepa );
						table.init( names.length );
						setTableDBColumn( names ) ;
						nameNoSet = false;
					}
					else  { continue; }
				}
				else {
					if( nameNoSet ) {
						String errMsg = "#NAME が見つかる前にデータが見つかりました。";
						throw new HybsSystemException( errMsg );
					}
					if( numberOfRows < getMaxRowCount() ) {
						setTableColumnValues( readData( line,names.length ) );		// 5.2.1.0 (2010/10/01)
//						table.addColumnValues( readData( line,names.length ) );
						numberOfRows ++ ;
					}
					else {
						table.setOverflow( true );
					}
				}
			}

			// 5.1.6.0 (2010/05/01) readDBTableのエラーチェック強化
			if( nameNoSet ) {
				String errMsg = "ファイルから有効なデータが見つかりませんでした。";
				throw new HybsSystemException( errMsg );
			}
		}
		catch ( IOException ex ) {
			String errMsg = "ファイル読込みエラー[" + reader + "]"  ;
			throw new HybsSystemException( errMsg,ex );		// 3.5.5.4 (2004/04/15) 引数の並び順変更
		}
	}
}
