package jp.co.areaweb.tools.csv;
import java.io.*;
import java.util.LinkedList;

import jp.co.areaweb.tools.csv.CsvRecord;

/**
 * <p>CSVファイルの読み取りを行う。<br/>
 * このクラスではCSVに対するファイル操作と、各行を束ねた単位で操作します。各行は、CsvRecordオブジェクトで管理します。<br/>
 * このクラスは通常,CsvRecordクラスとセットで利用します。</p>
 * 
 * （読み出し可能ファイルサイズ＝最大８MBまで）
 * 
 * @author y_hayashi
 * @version v2.23	2010/07/27
 * @see jp.co.areaweb.tools.csv.CsvRecord
 * @since 2010/07/27
 */
public class CsvReader
{
	/**
	 * CSVファイルの読み取りを行う。
	 * （読み出し可能ファイルサイズ＝最大８MBまで）
	 * 
	 * @param args
	 */
	public static void main(String[] args) throws Exception {
		File file = new File("test.csv");
		CsvReader obj = new CsvReader(file, true, ",");
		int size = obj.load();
		System.out.println("line count = "+ obj.size());
		
		for (int i=0; i < size; i++) {
			System.out.print(String.format("%05d : ", i));
			CsvRecord rec = obj.get(i);
			if (rec != null) {
				System.out.println(rec.toString());
			}
			else {
				System.out.println("< null >");
			}
		}
	}

	
	int size = 0;
	int columnSize = 0;
	boolean titleLine = false;
	File file = null;
	String split = ",";
	protected String charsetName = "Windows-31J";
	LineNumberReader reader;
	
	/**
	 * ＜コンストラクタ＞
	 * fileで指定されたファイルを対象のCSVファイルとします．
	 * 
	 * @param file 対象のCSVファイル
	 * @throws IOException 
	 * @throws UnsupportedEncodingException 
	 */
	public CsvReader(File file) throws UnsupportedEncodingException, IOException {
		this(file, false, ",");
	}
	
	/**
	 * ＜コンストラクタ＞
	 * fileで指定されたファイルを対象のCSVファイルとします．
	 * 
	 * @param file 対象のCSVファイル
	 * @throws IOException 
	 * @throws UnsupportedEncodingException 
	 */
	public CsvReader(File file, boolean titleLine, String split) throws UnsupportedEncodingException, IOException {
		this.file = file;
		this.titleLine = titleLine;
		this.reader = null;
		this.split = split;
	}
	
	/**
	 * CVSファイルからデータを読みだします。
	 * （読み出し可能ファイルサイズ＝最大８MBまで）
	 * 
	 * @param limit	全レコードを読み出したふりをする。
	 */
	public int load() throws Exception {
		this.reader = new LineNumberReader(new InputStreamReader(new FileInputStream(this.file), this.charsetName));
		this.reader.mark(1024 * 1024 * 8);
		this.size = 0;
		this.columnSize = 0;
		while (reader.readLine() != null) {
			this.size++;
		}
		return size;
	}
	
	
	public CsvRecord get(int index) {
		if ((index < 0) || (index > this.size)) {
			return null;
		}
		try {
			this.reader.reset();
			
			for (int i=0; i < index; i++) {
				reader.readLine();
			}

			String line = reader.readLine();
			if (line != null) {
				CsvRecord record = new CsvRecord();
				record.analizeRecord(line, this.split);
				return record;
			}
		}
		catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * index番目の項目がdataStrになっているレコードを読み出す。
	 * @param index 検索対象とする列番号（０～）
	 * @param dataStr 検索値
	 * @return 条件に合致したレコード（複数）
	 * @throws IOException 
	 */
	public LinkedList<CsvRecord> find(int index, String dataStr) throws IOException {
		if ((index < 0) || (index > this.size)) {
			return null;
		}
		LinkedList<CsvRecord> result = new LinkedList<CsvRecord>();
		this.reader.reset();
		
		for (int i=0; i < this.size; i++) {
			String line = reader.readLine();
			if (line != null) {
				CsvRecord record = new CsvRecord();
				record.analizeRecord(line, this.split);
				String item = record.get(index);
				if ((item != null) && item.trim().equals(dataStr)) {
					result.add(record);
				}
			}
		}
		return result;
	}

	public int size() {
		return this.size;
	}

	/**
	 * インポート元のキャラクタセットを設定する。
	 * デフォルトは、「Windows31J」
	 * @param charsetName 対象のCSVファイル内の文字コード
	 */
	public void setCharsetName(String charsetName) {
		this.charsetName = charsetName;
	}
	
	/**
	 * 現在設定されているCSVファイルの文字コードを取得する
	 * @return 現在設定されている文字コードを取得する
	 */
	public String getCharsetName() {
		return this.charsetName;
	}
}
