package org.phosphoresce.commons.csv;

import java.io.Serializable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;

/**
 * CSVトークンをリストで保持するCSVレコードクラス。<br>
 *
 * @author Kitagawa<br>
 *
 *<!--
 * 更新日		更新者			更新内容
 * 2007/02/16	Kitagawa		新規作成
 * 2008/11/25	Kitagawa		get、remove、listIterator、subListにおいて添え字がサイズを超える場合にリストサイズを自動拡張しないように修正
 * 2008/11/25	Kitagawa		toStringオーバーライド
 *-->
 */
public final class CSVRecord implements Serializable {

	/** CSVトークン保持リストオブジェクト */
	private List list = null;

	/**
	 * コンストラクタ<br>
	 */
	public CSVRecord() {
		super();
		this.list = new LinkedList();
	}

	/**
	 * コンストラクタ<br>
	 * @param record 初期化時のCSVレコードオブジェクト
	 */
	public CSVRecord(CSVRecord record) {
		super();
		this.list = new LinkedList(record.list);
	}

	/**
	 * レコードがCSVトークンを保持せず空であるか判定します。<br>
	 * @return レコードがCSVトークンを保持せず空である場合trueを返却
	 */
	public boolean isEmpty() {
		return list.isEmpty();
	}

	/**
	 * 指定されたCSVトークンが保持されているか判定します。<br>
	 * @param token 判定対象CSVトークン
	 * @return リストにCSVトークンが保持されている場合はtrueを返却
	 */
	public boolean contains(CSVToken token) {
		return list.contains(token);
	}

	/**
	 * 指定されたCSVレコード内容が全て保持されているか判定します。<br>
	 * @param record 判定対象CSVレコード
	 * @return 指定されたCSVレコード内容が全て保持されている場合trueを返却
	 */
	public boolean containsAll(CSVRecord record) {
		return this.list.containsAll(record.list);
	}

	/**
	 * CSVレコードイテレータを取得します。<br>
	 * @return CSVレコードイテレータ
	 */
	public Iterator iterator() {
		return list.iterator();
	}

	/**
	 * 指定されたサイズまでトークンリストサイズを拡張します。<br>
	 * @param size 拡張後のサイズ
	 */
	public void expand(int size) {
		int listSize = list.size();
		for (int i = 0; i <= size - listSize; i++) {
			list.add(new CSVToken());
		}
	}

	/**
	 * 保持しているCSVトークンを配列として取得します。<br>
	 * @return CSVトークン配列
	 */
	public CSVToken[] toArray() {
		return (CSVToken[]) list.toArray(new CSVToken[list.size()]);
	}

	/**
	 * 指定されたCSVレコードを全て追加します。<br>
	 * @param record 追加対象CSVレコード
	 * @return 追加処理の結果、リスト内容が変更された場合はtrueを返却
	 */
	public boolean addAll(CSVRecord record) {
		return this.list.addAll(record.list);
	}

	/**
	 * 指定されたCSVレコードを指定位置に全て追加します。<br>
	 * @param index 追加位置インデックス
	 * @param record 追加対象CSVレコード
	 * @return 処理の結果、リスト内容が変更された場合はtrueを返却
	 */
	public boolean addAll(int index, CSVRecord record) {
		expand(index);
		return this.list.addAll(index, record.list);
	}

	/**
	 * 指定されたCSVトークンリストに格納されている要素のみを残してリストを編集します。<br>
	 * @param record 保持対象のCSVトークンを保持するリストオブジェクト
	 * @return 処理の結果、リスト内容が変更された場合はtrueを返却
	 */
	public boolean retainAll(CSVRecord record) {
		return this.list.retainAll(record.list);
	}

	/**
	 * 保持しているCSVトークンを全て削除します。<br>
	 */
	public void clear() {
		this.list.clear();
	}

	/**
	 * 保持しているCSVトークン数を取得します。<br>
	 * @return 保持しているCSVトークン数
	 */
	public int size() {
		return list.size();
	}

	/**
	 * 指定されたCSVトークンを追加します。<br>
	 * @param token CSVトークン
	 */
	public void add(CSVToken token) {
		list.add(token);
	}

	/**
	 * 指定されたインデックス位置にCSVトークンを追加します。<br>
	 * @param index 追加位置インデックス
	 * @param token 追加対象CSVトークン
	 */
	public void add(int index, CSVToken token) {
		expand(index);
		list.add(index, token);
	}

	/**
	 * 指定されたインデックスのCSVトークンを取得します。<br>
	 * @param index 取得対象インデックス
	 * @return CSVトークン
	 */
	public CSVToken get(int index) {
		//expand(index + 1);
		if (index > list.size() - 1) {
			return null;
		}
		return (CSVToken) list.get(index);
	}

	/**
	 * 指定されたインデックスに対してCSVトークンを設定します。<br>
	 * @param index インデックス
	 * @param token CSVトークン
	 * @return 設定処理前に保持されていたCSVトークン
	 */
	public CSVToken set(int index, CSVToken token) {
		expand(index + 1);
		return (CSVToken) list.set(index, token);
	}

	/**
	 * 指定されたCSVトークンを削除します。<br>
	 * @param token 削除対象CSVトークン
	 * @return 指定されたCSVトークンが保持されている場合はtrueを返却
	 */
	public boolean remove(CSVToken token) {
		return list.remove(token);
	}

	/**
	 * 指定されたインデックスのCSVトークンを削除します。<br>
	 * @param index トークンインデックス
	 * @return 指定されたインデックスに存在するCSVトークン
	 */
	public CSVToken remove(int index) {
		//expand(index + 1);
		if (index > list.size() - 1) {
			return null;
		}
		return (CSVToken) list.remove(index);
	}

	/**
	 * 指定されたCSVレコードに格納されているすべての要素をリストから削除します。<br>
	 * @param record 削除対象のCSVトークンを保持するリストオブジェクト
	 * @return 処理の結果、リスト内容が変更された場合はtrueを返却
	 */
	public boolean removeAll(CSVRecord record) {
		return this.list.removeAll(record.list);
	}

	/**
	 * 指定されたCSVトークン位置を取得します。<br>
	 * @param token 位置取得対象CSVトークン
	 * @return 指定された要素がリスト内で最初に検出された位置のインデックス。リストにこの要素がない場合は-1を返却。
	 */
	public int indexOf(CSVToken token) {
		return list.indexOf(token);
	}

	/**
	 * 指定されたCSVトークンの最終出現位置を取得します。<br>
	 * @param token 位置取得対象CSVトークン
	 * @return 指定された要素がリスト内で最後に検出された位置のインデックス。リストにこの要素がない場合は-1を返却。
	 */
	public int lastIndexOf(CSVToken token) {
		return list.lastIndexOf(token);
	}

	/**
	 * CSVトークンリスト内の要素を適切な順序で繰り返し処理する反復子を取得します。<br>
	 * @return  CSVトークンリスト内の要素を適切な順序で繰り返し処理する反復子
	 */
	public ListIterator listIterator() {
		return list.listIterator();
	}

	/**
	 * リスト内の要素を適切な順序で繰り返し処理する、リスト内の指定された位置から開始する反復子を取得します。<br>
	 * @param index nextメソッドの呼び出しによってリスト反復子から返される最初の要素のインデックス
	 * @return  CSVトークンリスト内の要素を適切な順序で繰り返し処理する反復子
	 */
	public ListIterator listIterator(int index) {
		//expand(index);
		index = index > list.size() - 1 ? list.size() - 1 : index;
		return list.listIterator(index);
	}

	/**
	 * 指定されたインデックス範囲のCSVレコードを取得します。<br>
	 * @param fromIndex 開始インデックス
	 * @param toIndex 終了インデックス
	 * @return 指定範囲のCSVレコード
	 */
	public CSVRecord subList(int fromIndex, int toIndex) {
		//expand(fromIndex);
		//expand(toIndex);
		fromIndex = fromIndex > list.size() - 1 ? list.size() - 1 : fromIndex;
		toIndex = toIndex > list.size() - 1 ? list.size() - 1 : toIndex;
		List record = this.list.subList(fromIndex, toIndex);
		CSVRecord result = new CSVRecord();
		for (Iterator iterator = record.iterator(); iterator.hasNext();) {
			result.add((CSVToken) iterator.next());
		}
		return result;
	}

	/**
	 * CSVレコードが提供するCSV文字列を取得します。<br>
	 * @return CSVレコード文字列
	 */
	public String getRecordValue() {
		StringBuffer buffer = new StringBuffer();
		for (Iterator iterator = list.iterator(); iterator.hasNext();) {
			CSVToken token = (CSVToken) iterator.next();
			buffer.append(token.getEncodedValue());
			if (iterator.hasNext()) {
				buffer.append(CSVToken.SEPARATOR);
			}
		}
		return buffer.toString();
	}

	/**
	 * オブジェクトの文字列表現を返します。<br>
	 * @return オブジェクトの文字列表現
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		//		StringBuffer buffer = new StringBuffer();
		//		buffer.append("{");
		//		buffer.append("}");
		//		return buffer.toString();
		return list.toString();
	}
}

