/*
 * 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.candle.generator;

import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.EnumMap;
import java.util.Map;

import jp.sf.orangesignal.ta.FourPrice;
import jp.sf.orangesignal.ta.candle.Candlestick;
import jp.sf.orangesignal.ta.data.DatasetSource;
import jp.sf.orangesignal.ta.data.annotation.AnnotationParser;

/**
 * 注釈を利用してローソク足情報を生成するジェネレータクラスを提供します。
 * 
 * @author 杉澤 浩二
 * @since 2.1
 */
public class AnnotationCandlestickGenerator extends CandlestickGenerator {

	/**
	 * デフォルトの日時データ名です。
	 */
	public static final String DEFAULT_DATE_NAME = "date";

	/**
	 * デフォルトの4本値データ名のマップです。
	 */
	public static final Map<FourPrice, String> DEFAULT_PRICE_NAME_MAP;

	static {
		final Map<FourPrice, String> map = new EnumMap<FourPrice, String>(FourPrice.class);
		map.put(FourPrice.OPEN, "open");
		map.put(FourPrice.HIGH, "high");
		map.put(FourPrice.LOW, "low");
		map.put(FourPrice.CLOSE, "close");
		DEFAULT_PRICE_NAME_MAP = Collections.unmodifiableMap(map);
	}

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

	/**
	 * コンストラクタです。
	 * 
	 * @param settings ローソク足生成設定群情報
	 */
	public AnnotationCandlestickGenerator(final CandlestickGeneratorSettings settings) {
		super(settings);
	}

	public Candlestick[] generate(final Object dataset) throws CandlestickGenerateException {
		return generate(dataset, DEFAULT_DATE_NAME, DEFAULT_PRICE_NAME_MAP, null, this.settings);
	}

	public Candlestick[] generate(final Object dataset, final TrendProcessor processor) throws CandlestickGenerateException {
		return generate(dataset, DEFAULT_DATE_NAME, DEFAULT_PRICE_NAME_MAP, processor, this.settings);
	}

	public static Candlestick[] generate(final Object dataset, final TrendProcessor processor, final CandlestickGeneratorSettings settings) throws CandlestickGenerateException {
		return generate(dataset, DEFAULT_DATE_NAME, DEFAULT_PRICE_NAME_MAP, processor, settings);
	}

	/**
	 * 指定されたデータセットを使用してローソク足情報を生成して返します。<p>
	 * このメソッドは利便性の為に提供しています。<br>
	 * 実装はトレンドプロセッサーに <code>null</code> を指定して、{@link #generate(Object, String, Map, TrendProcessor, CandlestickGeneratorSettings)} を呼出すだけです。
	 * 
	 * @param dataset データセット
	 * @param date 日時データの名前
	 * @param price 4本値の種類とデータの名前のマップ
	 * @return ローソク足情報
	 * @throws CandlestickGenerateException ローソク足情報の生成に失敗した場合
	 * @see #generate(Object, String, Map, TrendProcessor, CandlestickGeneratorSettings)
	 */
	public Candlestick[] generate(final Object dataset, final String date, final Map<FourPrice, String> price) throws CandlestickGenerateException {
		return generate(dataset, date, price, null, this.settings);
	}

	/**
	 * 指定されたデータセット及びトレンドプロセッサーを使用してローソク足情報を生成して返します。<p>
	 * このメソッドは利便性の為に提供しています。<br>
	 * 実装は単に {@link #generate(Object, String, Map, TrendProcessor, CandlestickGeneratorSettings)} を呼出すだけです。
	 * 
	 * @param dataset データセット
	 * @param date 日時データの名前
	 * @param price 4本値の種類とデータの名前のマップ
	 * @param processor トレンドプロセッサー
	 * @return ローソク足情報
	 * @throws CandlestickGenerateException ローソク足情報の生成に失敗した場合
	 * @see #generate(Object, String, Map, TrendProcessor, CandlestickGeneratorSettings)
	 */
	public Candlestick[] generate(final Object dataset, final String date, final Map<FourPrice, String> price, final TrendProcessor processor) throws CandlestickGenerateException {
		return generate(dataset, date, price, processor, this.settings);
	}

	/**
	 * 指定されたデータセットを使用してローソク足情報を生成して返します。<p>
	 * このメソッドは注釈を利用して指定されたデータセットから日時、始値、高値、安値、終値を取得し {@link #generate(Date[], Number[], Number[], Number[], Number[], TrendProcessor, CandlestickGeneratorSettings)} を呼出します。
	 * 
	 * @param dataset データセット
	 * @param date 日時データの名前
	 * @param price 4本値の種類とデータの名前のマップ
	 * @param processor トレンドプロセッサー
	 * @param settings ローソク足生成設定群情報
	 * @return ローソク足情報
	 * @throws CandlestickGenerateException ローソク足情報の生成に失敗した場合
	 * @see #generate(Date[], Number[], Number[], Number[], Number[], TrendProcessor, CandlestickGeneratorSettings)
	 */
	public static Candlestick[] generate(
		final Object dataset,
		final String date,
		final Map<FourPrice, String> price,
		final TrendProcessor processor,
		final CandlestickGeneratorSettings settings)
	throws CandlestickGenerateException {
		final DatasetSource items = AnnotationParser.parse(dataset);
		return generate(
				items.getDate(date),
				items.getNumber(price.get(FourPrice.OPEN)),
				items.getNumber(price.get(FourPrice.HIGH)),
				items.getNumber(price.get(FourPrice.LOW)),
				items.getNumber(price.get(FourPrice.CLOSE)),
				processor,
				settings
			);
	}

	public Candlestick[] generate(final Collection<?> c) throws CandlestickGenerateException {
		return generate(c, DEFAULT_DATE_NAME, DEFAULT_PRICE_NAME_MAP, null, this.settings);
	}

	public Candlestick[] generate(final Collection<?> c, final TrendProcessor processor) throws CandlestickGenerateException {
		return generate(c, DEFAULT_DATE_NAME, DEFAULT_PRICE_NAME_MAP, processor, this.settings);
	}

	public static Candlestick[] generate(final Collection<?> c, final TrendProcessor processor, final CandlestickGeneratorSettings settings) throws CandlestickGenerateException {
		return generate(c, DEFAULT_DATE_NAME, DEFAULT_PRICE_NAME_MAP, processor, settings);
	}

	/**
	 * 指定されたデータコレクションを使用してローソク足情報を生成して返します。<p>
	 * このメソッドは利便性の為に提供しています。<br>
	 * 実装はトレンドプロセッサーに <code>null</code> を指定して、{@link #generate(Collection, String, Map, TrendProcessor, CandlestickGeneratorSettings)} を呼出すだけです。
	 * 
	 * @param c データコレクション
	 * @param date 日時データの名前
	 * @param price 4本値の種類とデータの名前のマップ
	 * @return ローソク足情報
	 * @throws CandlestickGenerateException ローソク足情報の生成に失敗した場合
	 * @see #generate(Collection, String, Map, TrendProcessor, CandlestickGeneratorSettings)
	 */
	public Candlestick[] generate(final Collection<?> c, final String date, final Map<FourPrice, String> price) throws CandlestickGenerateException {
		return generate(c, date, price, null, this.settings);
	}

	/**
	 * 指定されたデータコレクション及びトレンドプロセッサーを使用してローソク足情報を生成して返します。<p>
	 * このメソッドは利便性の為に提供しています。<br>
	 * 実装は単に {@link #generate(Collection, String, Map, TrendProcessor, CandlestickGeneratorSettings)} を呼出すだけです。
	 * 
	 * @param c データコレクション
	 * @param date 日時データの名前
	 * @param price 4本値の種類とデータの名前のマップ
	 * @param processor トレンドプロセッサー
	 * @return ローソク足情報
	 * @throws CandlestickGenerateException ローソク足情報の生成に失敗した場合
	 * @see #generate(Collection, String, Map, TrendProcessor, CandlestickGeneratorSettings)
	 */
	public Candlestick[] generate(final Collection<?> c, final String date, final Map<FourPrice, String> price, final TrendProcessor processor) throws CandlestickGenerateException {
		return generate(c, date, price, processor, this.settings);
	}

	/**
	 * 指定されたデータコレクションを使用してローソク足情報を生成して返します。<p>
	 * このメソッドは利便性の為に提供しています。<br>
	 * 実装は単に {@link #generate(Object[], String, Map, TrendProcessor, CandlestickGeneratorSettings)} を呼出すだけです。
	 * 
	 * @param c データコレクション
	 * @param date 日時データの名前
	 * @param price 4本値の種類とデータの名前のマップ
	 * @param processor トレンドプロセッサー
	 * @param settings ローソク足生成設定群情報
	 * @return ローソク足情報
	 * @throws CandlestickGenerateException ローソク足情報の生成に失敗した場合
	 * @see #generate(Object[], String, Map, TrendProcessor, CandlestickGeneratorSettings)
	 */
	public static Candlestick[] generate(final Collection<?> c, final String date, final Map<FourPrice, String> price, final TrendProcessor processor, final CandlestickGeneratorSettings settings) throws CandlestickGenerateException {
		return generate(c.toArray(), date, price, processor, settings);
	}

	/**
	 * 指定されたデータ配列を使用してローソク足情報を生成して返します。<p>
	 * このメソッドは注釈を利用して指定されたデータ配列から日時、始値、高値、安値、終値を取得し {@link #generate(Object[], String, Map, TrendProcessor, CandlestickGeneratorSettings)} を呼出します。
	 * 
	 * @param array データ配列
	 * @return ローソク足情報
	 * @throws CandlestickGenerateException ローソク足情報の生成に失敗した場合
	 * @see #generate(Object[], String, Map, TrendProcessor, CandlestickGeneratorSettings)
	 */
	public Candlestick[] generate(final Object[] array) throws CandlestickGenerateException {
		return generate(array, DEFAULT_DATE_NAME, DEFAULT_PRICE_NAME_MAP, null, this.settings);
	}

	/**
	 * 指定されたデータ配列を使用してローソク足情報を生成して返します。<p>
	 * このメソッドは注釈を利用して指定されたデータ配列から日時、始値、高値、安値、終値を取得し {@link #generate(Object[], String, Map, TrendProcessor, CandlestickGeneratorSettings)} を呼出します。
	 * 
	 * @param array データ配列
	 * @param processor トレンドプロセッサー
	 * @return ローソク足情報
	 * @throws CandlestickGenerateException ローソク足情報の生成に失敗した場合
	 * @see #generate(Object[], String, Map, TrendProcessor, CandlestickGeneratorSettings)
	 */
	public Candlestick[] generate(final Object[] array, final TrendProcessor processor) throws CandlestickGenerateException {
		return generate(array, DEFAULT_DATE_NAME, DEFAULT_PRICE_NAME_MAP, processor, this.settings);
	}

	/**
	 * 指定されたデータ配列を使用してローソク足情報を生成して返します。<p>
	 * このメソッドは注釈を利用して指定されたデータ配列から日時、始値、高値、安値、終値を取得し {@link #generate(Object[], String, Map, TrendProcessor, CandlestickGeneratorSettings)} を呼出します。
	 * 
	 * @param array データ配列
	 * @param processor トレンドプロセッサー
	 * @param settings ローソク足生成設定群情報
	 * @return ローソク足情報
	 * @throws CandlestickGenerateException ローソク足情報の生成に失敗した場合
	 * @see #generate(Object[], String, Map, TrendProcessor, CandlestickGeneratorSettings)
	 */
	public static Candlestick[] generate(final Object[] array, final TrendProcessor processor, final CandlestickGeneratorSettings settings) throws CandlestickGenerateException {
		return generate(array, DEFAULT_DATE_NAME, DEFAULT_PRICE_NAME_MAP, processor, settings);
	}

	/**
	 * 指定されたデータ配列を使用してローソク足情報を生成して返します。<p>
	 * このメソッドは利便性の為に提供しています。<br>
	 * 実装はトレンドプロセッサーに <code>null</code> を指定して、{@link #generate(Object[], String, Map, TrendProcessor, CandlestickGeneratorSettings)} を呼出すだけです。
	 * 
	 * @param array データ配列
	 * @param date 日時データの名前
	 * @param price 4本値の種類とデータの名前のマップ
	 * @return ローソク足情報
	 * @throws CandlestickGenerateException ローソク足情報の生成に失敗した場合
	 * @see #generate(Object[], String, Map, TrendProcessor, CandlestickGeneratorSettings)
	 */
	public Candlestick[] generate(final Object[] array, final String date, final Map<FourPrice, String> price) throws CandlestickGenerateException {
		return generate(array, date, price, null, this.settings);
	}

	/**
	 * 指定されたデータ配列及びトレンドプロセッサーを使用してローソク足情報を生成して返します。<p>
	 * このメソッドは利便性の為に提供しています。<br>
	 * 実装は単に {@link #generate(Object[], String, Map, TrendProcessor, CandlestickGeneratorSettings)} を呼出すだけです。
	 * 
	 * @param array データ配列
	 * @param date 日時データの名前
	 * @param price 4本値の種類とデータの名前のマップ
	 * @param processor トレンドプロセッサー
	 * @return ローソク足情報
	 * @throws CandlestickGenerateException ローソク足情報の生成に失敗した場合
	 * @see #generate(Object[], String, Map, TrendProcessor, CandlestickGeneratorSettings)
	 */
	public Candlestick[] generate(final Object[] array, final String date, final Map<FourPrice, String> price, final TrendProcessor processor) throws CandlestickGenerateException {
		return generate(array, date, price, processor, this.settings);
	}

	/**
	 * 指定されたデータ配列を使用してローソク足情報を生成して返します。<p>
	 * このメソッドは注釈を利用して指定されたデータ配列から日時、始値、高値、安値、終値を取得し {@link #generate(Object[], String, String, String, String, String, TrendProcessor, CandlestickGeneratorSettings)} を呼出します。
	 * 
	 * @param array データ配列
	 * @param date 日時データの名前
	 * @param price 4本値の種類とデータの名前のマップ
	 * @param processor トレンドプロセッサー
	 * @param settings ローソク足生成設定群情報
	 * @return ローソク足情報
	 * @throws CandlestickGenerateException ローソク足情報の生成に失敗した場合
	 * @see #generate(Object[], String, String, String, String, String, TrendProcessor, CandlestickGeneratorSettings)
	 */
	public static Candlestick[] generate(
		final Object[] array,
		final String date,
		final Map<FourPrice, String> price,
		final TrendProcessor processor,
		final CandlestickGeneratorSettings settings)
	throws CandlestickGenerateException {
		return generate(
				array,
				date,
				price.get(FourPrice.OPEN),
				price.get(FourPrice.HIGH),
				price.get(FourPrice.LOW),
				price.get(FourPrice.CLOSE),
				processor,
				settings
			);
	}

	public static Candlestick[] generate(
		final Object[] array,
		final String date,
		final String open,
		final String high,
		final String low,
		final String close,
		final TrendProcessor processor,
		final CandlestickGeneratorSettings settings)
	throws CandlestickGenerateException {
		return generate(AnnotationParser.parse(array), date, open, high, low, close, processor, settings);
	}

	private static Candlestick[] generate(
		final DatasetSource items,
		final String date,
		final String open,
		final String high,
		final String low,
		final String close,
		final TrendProcessor processor,
		final CandlestickGeneratorSettings settings)
	throws CandlestickGenerateException {
		return generate(
				date == null ? null : items.getDate(date),
				items.getNumber(open),
				items.getNumber(high),
				items.getNumber(low),
				items.getNumber(close),
				processor,
				settings
			);
	}

}
