/*
 * Copyright (c) 2009 OrangeSignal.com All rights reserved.
 * 
 * これは Apache ライセンス Version 2.0 (以下、このライセンスと記述) に
 * 従っています。このライセンスに準拠する場合以外、このファイルを使用
 * してはなりません。このライセンスのコピーは以下から入手できます。
 * 
 * http://www.apache.org/licenses/LICENSE-2.0.txt
 * 
 * 適用可能な法律がある、あるいは文書によって明記されている場合を除き、
 * このライセンスの下で配布されているソフトウェアは、明示的であるか暗黙の
 * うちであるかを問わず、「保証やあらゆる種類の条件を含んでおらず」、
 * 「あるがまま」の状態で提供されるものとします。
 * このライセンスが適用される特定の許諾と制限については、このライセンス
 * を参照してください。
 */

package jp.sf.orangesignal.trading.data;

import static jp.sf.orangesignal.ta.util.ArrayUtils.INDEX_NOT_FOUND;

import java.util.Date;

import jp.sf.orangesignal.ta.FourPrice;
import jp.sf.orangesignal.ta.data.CompressType;
import jp.sf.orangesignal.ta.data.annotation.AnnotationParser;
import jp.sf.orangesignal.ta.data.annotation.NumberCompressorType;
import jp.sf.orangesignal.ta.data.model.Price;
import jp.sf.orangesignal.ta.data.model.PriceDataset;
import jp.sf.orangesignal.ta.data.model.TechnicalPriceDataset;
import jp.sf.orangesignal.ta.util.ArrayUtils;
import jp.sf.orangesignal.ta.util.Assert;
import jp.sf.orangesignal.ta.util.DateArrayUtils;

/**
 * 価格や出来高などの基本的な時系列データセットを提供します。
 * 
 * @author 杉澤 浩二
 * @since 2.2
 */
@NumberCompressorType(CompressType.SUM)
public class Dataset extends TechnicalPriceDataset {

	private static final long serialVersionUID = 1689616808276855902L;

	/**
	 * 足の単位を保持します。
	 */
	private IntervalType interval;

	/**
	 * シンボルを保持します。
	 */
	private String symbol;

	/**
	 * シンボル名を保持します。
	 */
	private String symbolName;

	/**
	 * デフォルトコンストラクタです。
	 */
	public Dataset() {}

	public Dataset(final PriceDataset dataset, final IntervalType interval, final String symbol, final String symbolName) {
		super(dataset);
		this.interval = interval;
		this.symbol = symbol;
		this.symbolName = symbolName;
	}

	public static Dataset newInstance(final Price[] prices, final IntervalType interval, String symbol, String symbolName) {
		Assert.notEmpty(prices, "Prices must not be empty");
		return new Dataset(AnnotationParser.parse(prices).build(PriceDataset.class).execute(), interval, symbol, symbolName);
	}

	// ------------------------------------------------------------------------

	/**
	 * データの長さを返します。
	 * 
	 * @return データの長さ
	 */
	public int getLength() { return date == null ? 0 : date.length; }

	/**
	 * <p>指定された日時以後 (<code>null</code> 可) を含む最初の位置を返します。</p>
	 * 
	 * @param find 検索する日時 (<code>null</code> 可)
	 * @return 指定された日時以後を含む最初の位置。見つからない場合は <code>-1</code>
	 */
	public int indexOf(final Date find) { return DateArrayUtils.indexOf(date, find); }

	/**
	 * <p>指定された日時以前 (<code>null</code> 可) を含む最後の位置を返します。</p>
	 * 
	 * @param find 検索する日時 (<code>null</code> 可)
	 * @return 指定された日時以前を含む最後の位置。見つからない場合は <code>-1</code>
	 */
	public int lastIndexOf(final Date find) { return DateArrayUtils.lastIndexOf(date, find); }

	/**
	 * <p>指定された日時以後又は <code>null</code> でない最初の位置を返します。</p>
	 * 
	 * @param find 検索する日時
	 * @return 指定された日時以後又は <code>null</code> でない最初の位置。見つからない場合は <code>-1</code>
	 */
	public int defaultIndexOf(final Date find) {
		int result = INDEX_NOT_FOUND;
		if (find != null)
			result = DateArrayUtils.indexOf(date, find);
		if (result != INDEX_NOT_FOUND)
			return result;
		return ArrayUtils.notNullIndexOf(date);
	}

	/**
	 * <p>指定された日時以前又は <code>null</code> でない最後の位置を返します。</p>
	 * 
	 * @param find 検索する日時
	 * @return 指定された日時以前又は <code>null</code> でない最後の位置。見つからない場合は <code>-1</code>
	 */
	public int defaultLastIndexOf(final Date find) {
		int result = INDEX_NOT_FOUND;
		if (find != null)
			result = DateArrayUtils.lastIndexOf(date, find);
		if (result != INDEX_NOT_FOUND)
			return result;
		return ArrayUtils.notNullLastIndexOf(date);
	}

	/**
	 * 指定された日時間の期間を返します。
	 * 
	 * @param start 検索する開始日時
	 * @param end 検索する終了日時
	 * @return 期間
	 */
	public int getPeriod(final Date start, final Date end) {
		final int startIndex = indexOf(start);
		final int endIndex = lastIndexOf(end);
		if (startIndex != INDEX_NOT_FOUND && endIndex != INDEX_NOT_FOUND)
			return endIndex - startIndex + 1;
		return 0;
	}

	/**
	 * 指定された4本値の種類に対応する価格データを返します。
	 * 
	 * @param type 4本値の種類
	 * @return 価格データ。又は <code>null</code>
	 */
	public Number[] getPrice(final FourPrice type) {
		switch (type) {
			case OPEN:
				return getOpen();
			case HIGH:
				return getHigh();
			case LOW:
				return getLow();
			case CLOSE:
				return getClose();
			default:
				return null;
		}
	}

	/**
	 * 指定された4本値の種類に対応するテクニカル指標計算用価格データを返します。
	 * 
	 * @param type 4本値の種類
	 * @return テクニカル指標計算用価格データ。又は <code>null</code>
	 */
	public Number[] getTechnicalPrice(final FourPrice type) {
		switch (type) {
			case OPEN:
				return getTechnicalOpen();
			case HIGH:
				return getTechnicalHigh();
			case LOW:
				return getTechnicalLow();
			case CLOSE:
				return getTechnicalClose();
			default:
				return null;
		}
	}

	/**
	 * シンボルを返します。
	 * 
	 * @return シンボル。又は <code>null</code>
	 */
	public String getSymbol() { return symbol; }

	/**
	 * シンボルを設定します。
	 * 
	 * @param symbol シンボル
	 */
	public void setSymbol(final String symbol) { this.symbol = symbol; }

	/**
	 * シンボル名を返します。
	 * 
	 * @return シンボル名。又は <code>null</code>
	 */
	public String getSymbolName() { return symbolName; }

	/**
	 * シンボル名を設定します。
	 * 
	 * @param symbolName シンボル名
	 */
	public void setSymbolName(final String symbolName) { this.symbolName = symbolName; }

	/**
	 * 足の単位を返します。
	 * 
	 * @return 足の単位
	 */
	public IntervalType getInterval() { return interval; }

	/**
	 * 足の単位を設定します。
	 * 
	 * @param interval 足の単位
	 */
	public void setInterval(final IntervalType interval) { this.interval = interval; }

}
