/*
 * Copyright (c) 2008-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;

/**
 * <p>トレーディングルールのパターンに関するユーティリティクラスを提供します。</p>
 * 
 * @author 杉澤 浩二
 * @since 2.0.1
 */
public class ChartPatterns {

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

	/**
	 * <p>指定されたローソク足データから Open Close Reversal の売買シグナルを列挙して返します。</p>
	 * 
	 * @param c ローソク足データ
	 * @param trend トレンドを確認するかどうか
	 * @return Open Close Reversal の売買シグナルを列挙
	 */
	public static TrendSignal[] openCloseReversal(final Candlestick[] c, final boolean trend) {
		final int length = c.length;
		final TrendSignal[] results = new TrendSignal[length];
		for (int i = 1; i < length; i++) {
			final int _1 = i - 1, _2 = i;
			if (c[_1] == null || c[_2] == null)
				continue;

			if ((!trend | c[_1].getTrend() == null | c[_1].getTrend() == TrendType.UP) &&
					c[_2].isNearOpen(c[_2].getHigh()) && c[_2].isNearClose(c[_2].getLow()) && c[_1].getClose() < c[_2].getClose())
			{
				results[i] = TrendSignal.BULLISH;
			} else if ((!trend | c[_1].getTrend() == null | c[_1].getTrend() == TrendType.DOWN) &&
						c[_2].isNearOpen(c[_2].getLow()) && c[_2].isNearClose(c[_2].getHigh()) && c[_1].getClose() > c[_2].getClose())
			{
				results[i] = TrendSignal.BEARLISH;
			}
		}
		return results;
	}

	/**
	 * <p>指定されたローソク足データから Closing Price Reversal の売買シグナルを列挙して返します。</p>
	 * 
	 * @param c ローソク足データ
	 * @param trend トレンドを確認するかどうか
	 * @return Closing Price Reversal の売買シグナルを列挙
	 */
	public static TrendSignal[] closingPriceReversal(final Candlestick[] c, final boolean trend) {
		final int length = c.length;
		final TrendSignal[] results = new TrendSignal[length];
		for (int i = 2; i < length; i++) {
			final int _1 = i - 2, _2 = i - 1, _3 = i;
			if (c[_1] == null || c[_2] == null || c[_3] == null)
				continue;

			if (c[_1].getLow() > c[_2].getLow() && c[_1].getClose() < c[_2].getClose() && c[_3].isCloseInTopQuarter()) {
				results[i] = TrendSignal.BULLISH;
			} else if (c[_1].getHigh() <= c[_2].getHigh() && c[_1].getClose() >= c[_2].getClose() && c[_3].isCloseInBottomQuarter()) {
				results[i] = TrendSignal.BEARLISH;
			}
		}
		return results;
	}

	/**
	 * <p>指定されたローソク足データから Hook Reversal の売買シグナルを列挙して返します。</p>
	 * 
	 * @param c ローソク足データ
	 * @param trend トレンドを確認するかどうか
	 * @return Hook Reversal の売買シグナルを列挙
	 */
	public static TrendSignal[] hookReversal(final Candlestick[] c, final boolean trend) {
		final int length = c.length;
		final TrendSignal[] results = new TrendSignal[length];
		for (int i = 1; i < length; i++) {
			final int _1 = i - 1, _2 = i;
			if (c[_1] == null || c[_2] == null)
				continue;
			if (c[_1].getHigh() > c[_2].getHigh() && c[_1].getLow() < c[_2].getLow()) {
				if (
						(!trend | c[_1].getTrend() == null | c[_1].getTrend() == TrendType.UP) &&
						c[_2].isNearHigh(c[_2].getOpen()) && c[_2].isNearLow(c[_2].getClose()))
				{
					results[i] = TrendSignal.BEARLISH;
				} else if (
						(!trend | c[_1].getTrend() == null | c[_1].getTrend() == TrendType.DOWN) &&
						c[_2].isNearHigh(c[_2].getClose()) && c[_2].isNearLow(c[_2].getOpen()))
				{
					results[i] = TrendSignal.BULLISH;
				}
			}
		}
		return results;
	}

	/**
	 * <p>指定されたローソク足データから Key Reversal の売買シグナルを列挙して返します。</p>
	 * 
	 * @param c ローソク足データ
	 * @param trend トレンドを確認するかどうか
	 * @return Key Reversal の売買シグナルを列挙
	 */
	public static TrendSignal[] keyReversal(final Candlestick[] c, final boolean trend) {
		final int length = c.length;
		final TrendSignal[] results = new TrendSignal[length];
		for (int i = 1; i < length; i++) {
			final int _1 = i - 1, _2 = i;
			if (c[_1] == null || c[_2] == null)
				continue;
			// 抱き線(包み線)
			if (c[_1].getHigh() < c[_2].getHigh() && c[_1].getLow() > c[_2].getLow()) {
				if (
						(!trend | c[_1].getTrend() == null | c[_1].getTrend() == TrendType.UP) &&
						c[_1].getClose() < c[_2].getOpen() && c[_1].getLow() >= c[_2].getClose())
				{
					results[i] = TrendSignal.BEARLISH;
				} else if (
						(!trend | c[_1].getTrend() == null | c[_1].getTrend() == TrendType.DOWN) &&
						c[_1].getClose() > c[_2].getOpen() && c[_1].getHigh() <= c[_2].getClose())
				{
					results[i] = TrendSignal.BULLISH;
				}
			}
		}
		return results;
	}

	/**
	 * <p>指定されたローソク足データから Island Reversal の売買シグナルを列挙して返します。</p>
	 * 
	 * @param c ローソク足データ
	 * @param trend トレンドを確認するかどうか
	 * @return Island Reversal の売買シグナルを列挙
	 */
	public static TrendSignal[] islandReversal(final Candlestick[] c, final boolean trend) {
		final int length = c.length;
		final TrendSignal[] results = new TrendSignal[length];
		for (int i = 2; i < length; i++) {
			final int _1 = i - 2, _2 = i - 1, _3 = i;
			if (c[_1] == null || c[_2] == null || c[_3] == null)
				continue;

			if ((!trend | c[_1].getTrend() == null | c[_1].getTrend() == TrendType.UP) && c[_1].gapUp(c[_2]) && c[_2].gapDown(c[_3])) {
				results[i] = TrendSignal.BULLISH;
			} else if ((!trend | c[_1].getTrend() == null | c[_1].getTrend() == TrendType.DOWN) && c[_1].gapDown(c[_2]) && c[_2].gapUp(c[_3])) {
				results[i] = TrendSignal.BEARLISH;
			}
		}
		return results;
	}

	/**
	 * <p>指定されたローソク足データから Three Bar Rule の売買シグナルを列挙して返します。</p>
	 * 
	 * @param c ローソク足データ
	 * @return Three Bar Rule の売買シグナルを列挙
	 */
	public static TrendSignal[] threeBarRule(final Candlestick[] c) {
		final int length = c.length;
		final TrendSignal[] results = new TrendSignal[length];
		for (int i = 2; i < length; i++) {
			final int _1 = i - 2, _2 = i - 1, _3 = i;
			if (c[_1] == null || c[_2] == null || c[_3] == null)
				continue;

			if (c[_1].getClose() >= c[_1].median() && c[_2].getClose() >= c[_2].median() && c[_3].isCloseInTopQuarter()) {
				results[i] = TrendSignal.BULLISH;
			} else if (c[_1].getClose() <= c[_1].median() && c[_2].getClose() <= c[_2].median() && c[_3].isCloseInBottomQuarter()) {
				results[i] = TrendSignal.BEARLISH;
			}
		}
		return results;
	}

	/**
	 * <p>指定されたローソク足データから Gap Rule の売買シグナルを列挙して返します。</p>
	 * 
	 * @param c ローソク足データ
	 * @return Gap Rule の売買シグナルを列挙
	 */
	public static TrendSignal[] gapRule(final Candlestick[] c) {
		final int length = c.length;
		final TrendSignal[] results = new TrendSignal[length];
		for (int i = 2; i < length; i++) {
			final int _1 = i - 2, _2 = i - 1, _3 = i;
			if (c[_1] == null || c[_2] == null || c[_3] == null)
				continue;

			if (c[_1].getHigh() < c[_2].getLow() && c[_2].isCloseInTopQuarter() && c[_3].isCloseInTopQuarter()) {
				results[i] = TrendSignal.BULLISH;
			} else if (c[_1].getLow() > c[_2].getHigh() && c[_2].isCloseInBottomQuarter() && c[_3].isCloseInBottomQuarter()) {
				results[i] = TrendSignal.BEARLISH;
			}
		}
		return results;
	}

/*
	public static Signal[] lindahlBuyRule(final Candlestick[] c) {
		final int length = c.length;
		final Signal[] results = new Signal[length];
		for (int i = 0; i < length; i++) {
		}
		return results;
	}

	public static Signal[] lindahlSellRule(final Candlestick[] c) {
		final int length = c.length;
		final Signal[] results = new Signal[length];
		for (int i = 0; i < length; i++) {
		}
		return results;
	}

	public static Signal[] trendContinuationRule(final Candlestick[] c) {
		final int length = c.length;
		final Signal[] results = new Signal[length];
		for (int i = 0; i < length; i++) {
		}
		return results;
	}

	public static Signal[] trendReversalRule(final Candlestick[] c) {
		final int length = c.length;
		final Signal[] results = new Signal[length];
		for (int i = 0; i < length; i++) {
		}
		return results;
	}

	public static Signal[] doubleReversalRule(final Candlestick[] c) {
		final int length = c.length;
		final Signal[] results = new Signal[length];
		for (int i = 0; i < length; i++) {
		}
		return results;
	}
*/

	/**
	 * <p>指定されたローソク足データから High Low Reversal の売買シグナルを列挙して返します。</p>
	 * 
	 * @param c ローソク足データ
	 * @return High Low Reversal の売買シグナルを列挙
	 */
	public static TrendSignal[] highLowReversal(final Candlestick[] c) {
		final double diff = 0.05;
		final int length = c.length;
		final TrendSignal[] results = new TrendSignal[length];
		for (int i = 1; i < length; i++) {
			final int _1 = i - 1, _2 = i;
			if (c[_1] == null || c[_2] == null)
				continue;
			if (c[_1].getClose() >= (c[_1].getHigh() - diff) && c[_2].getClose() <= (c[_2].getLow() + diff))
				results[i] = TrendSignal.BEARLISH;
			else if (c[_2].getClose() >= (c[_2].getHigh() - diff) && c[_1].getClose() <= (c[_1].getLow() + diff))
				results[i] = TrendSignal.BULLISH;
		}
		return results;
	}

}
