/*
 * 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.ta.data.model;

import static jp.sf.orangesignal.ta.data.DataConvertUtils.previousIfNull;
import static jp.sf.orangesignal.ta.data.DataConvertUtils.zeroIfNull;
import jp.sf.orangesignal.ta.candle.Candlestick;
import jp.sf.orangesignal.ta.candle.generator.CandlestickGenerator;
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.annotation.NumberItem;
import jp.sf.orangesignal.ta.util.Assert;

/**
 * テクニカル指標計算用価格データセットを提供します。
 * 
 * @author 杉澤 浩二
 * @since 2.2
 */
@NumberCompressorType(CompressType.SUM)
public class TechnicalPriceDataset extends PriceDataset {

	private static final long serialVersionUID = -3475688299719279063L;

	/**
	 * ローソク足データを保持します。
	 */
	protected Candlestick[] candlestick;

	/**
	 * テクニカル指標計算用始値データを保持します。
	 */
	@NumberItem
	@NumberCompressorType(CompressType.FIRST)
	protected Number[] technicalOpen;

	/**
	 * テクニカル指標計算用高値データを保持します。
	 */
	@NumberItem
	@NumberCompressorType(CompressType.HIGHEST)
	protected Number[] technicalHigh;

	/**
	 * テクニカル指標計算用安値データを保持します。
	 */
	@NumberItem
	@NumberCompressorType(CompressType.LOWEST)
	protected Number[] technicalLow;

	/**
	 * テクニカル指標計算用終値データを保持します。
	 */
	@NumberItem
	@NumberCompressorType(CompressType.LAST)
	protected Number[] technicalClose;

	/**
	 * テクニカル指標計算用出来高データを保持します。
	 */
	@NumberItem
	@NumberCompressorType(CompressType.SUM)
	protected Number[] technicalVolume;

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

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

	/**
	 * 指定された価格データセットからこのクラスのインスタンスを構築するコンストラクタです。
	 * 
	 * @param dataset 価格データセット
	 * @throws IllegalArgumentException <code>dataset</code> が <code>null</code> の場合
	 */
	public TechnicalPriceDataset(final PriceDataset dataset) {
		Assert.notNull(dataset, "Dataset must not be null");

		date = dataset.date;
		open = dataset.open;
		high = dataset.high;
		low = dataset.low;
		close = dataset.close;
		volume = dataset.volume;

		candlestick = new CandlestickGenerator().generate(date, open, high, low, close);
		if (open != null) {
			technicalOpen = previousIfNull(open);
		}
		if (high != null) {
			technicalHigh = previousIfNull(high);
		}
		if (low != null) {
			technicalLow = previousIfNull(low);
		}
		if (close != null) {
			technicalClose = previousIfNull(close);
		}
		if (volume != null) {
			technicalVolume = zeroIfNull(volume);
		}
	}

	/**
	 * 指定された価格データからテクニカル指標計算用価格データセットの新しいインスタンスを構築して返します。
	 * 
	 * @param prices 価格データ
	 * @return テクニカル指標計算用価格データセット
	 * @throws IllegalArgumentException <code>prices</code> が <code>null</code> または要素が存在しない場合
	 */
	public static TechnicalPriceDataset newInstance(final Price[] prices) {
		Assert.notEmpty(prices, "Prices must not be empty");
		return new TechnicalPriceDataset(AnnotationParser.parse(prices).build(PriceDataset.class).execute());
	}

	/**
	 * ローソク足データを返します。
	 * 
	 * @return ローソク足データ。ローソク足データが存在しない場合は <code>null</code>
	 */
	public Candlestick[] getCandlestick() { return candlestick; }

	/**
	 * テクニカル指標計算用始値データを返します。
	 * 
	 * @return テクニカル指標計算用始値データ
	 */
	public Number[] getTechnicalOpen() { return technicalOpen; }

	/**
	 * テクニカル指標計算用高値データを返します。
	 * 
	 * @return テクニカル指標計算用高値データ
	 */
	public Number[] getTechnicalHigh() { return technicalHigh; }

	/**
	 * テクニカル指標計算用安値データを返します。
	 * 
	 * @return テクニカル指標計算用安値データ
	 */
	public Number[] getTechnicalLow() { return technicalLow; }

	/**
	 * テクニカル指標計算用終値データを返します。
	 * 
	 * @return テクニカル指標計算用終値データ
	 */
	public Number[] getTechnicalClose() { return technicalClose; }

	/**
	 * テクニカル指標計算用出来高データを返します。
	 * 
	 * @return テクニカル指標計算用出来高データ。テクニカル指標計算用出来高データが存在しない場合は <code>null</code>
	 */
	public Number[] getTechnicalVolume() { return technicalVolume; }

}
