#ifndef __SFJP_MYU__AGH_EffectControl_H__
#define __SFJP_MYU__AGH_EffectControl_H__

#include <math.h>

namespace math{

	#define _AGH_MATH_SIN	sin
	#define _AGH_MATH_COS	cos

	//	線・波の基底クラス
	template <typename Ty>
	class TLineBase
	{
	protected:
		Ty m_rangeMin, m_rangeMax;

		inline Ty _Sub(){
			return m_rangeMax - m_rangeMin; }
	public:
		//	コンストラクタ・デストラクタ
		TLineBase(){
			m_rangeMin = m_rangeMax = 0;
		}
		virtual ~TLineBase(){}

		//	最小値と最大値を設定する。
		void SetRange(Ty rangeMin, Ty rangeMax){
			m_rangeMin = rangeMin;
			m_rangeMax = rangeMax;
		}

		//	0.0f〜1.0fの間で指定する事により中間値を取得する。・・・まぁマイナスとか1.0f以上の指定も可能だけれど・・・
		virtual Ty Get(float fIntermediate)=0;
	};

	typedef TLineBase<int> CIntLineBase;
	typedef TLineBase<float> CFloatLineBase;

	//typedef CLineBase CWaveBase;

	//////////////////////////////////////////////////////////////

	//	直線クラス
	template <typename Ty>
	class TStraightLine : public TLineBase<Ty>
	{
	public:
		TStraightLine(){}
		virtual ~TStraightLine(){}

		Ty Get(float fIntermediate){
			return (Ty)(m_rangeMin + _Sub() * fIntermediate);
		}
	};
	typedef TStraightLine<int> CStraightLine, CStraight, CLinear, CLine;
	typedef TStraightLine<int> CIntStraightLine, CIntStraight, CIntLinear, CIntLine;
	typedef TStraightLine<float> CFloatStraightLine, CFloatStraight, CFloatLinear, CFloatLine;

	//typedef CStraightLine CStraight, CLinear, CLine;

	//////////////////////////////////////////////////////////////

	//	正弦波（サイン）
	template <typename Ty>
	class TSineWave : public TLineBase<Ty>
	{
	public:
		TSineWave(){}
		virtual ~TSineWave(){}

		Ty Get(float fIntermediate){
			return (Ty)(m_rangeMin + (_Sub()/2.0f) + (_Sub()/2.0f) * sin((double)fIntermediate));
		}
	};
	typedef TSineWave<double> CSineWave, CDoubleSineWave;
	typedef TSineWave<float> CFloatSineWave;
	typedef TSineWave<int> CIntSineWave;
	
	//	こっちはSineでなくSinね。
	typedef TSineWave<double> CSinWave, CDoubleSinWave;
	typedef TSineWave<float> CFloatSinWave;
	typedef TSineWave<int> CIntSinWave;

	//////////////////////////////////////////////////////////////

	//	余弦（コサイン）
	template <typename Ty>
	class TCosWave : public TLineBase<Ty>
	{
	public:
		TCosWave(){}
		virtual ~TCosWave(){}

		Ty Get(float fIntermediate){
			return (Ty)(m_rangeMin + (_Sub()/2.0f) + (_Sub()/2.0f) * _AGH_MATH_COS((double)fIntermediate));
		}
	};
	typedef TCosWave<double> CCosWave, CCosineWave;
	typedef TCosWave<float> CFloatCosWave, CFloatCosineWave;
	typedef TCosWave<int> CIntCosWave, CIntCosineWave;

	//////////////////////////////////////////////////////////////

	//	三角波（ ／＼／＼／＼ な波形）
	template <typename Ty>
	class TTriWave : public TLineBase<Ty>
	{
	public:
		TTriWave(){}
		virtual ~TTriWave(){}

		Ty Get(float fIntermediate){
			//	fIntermediateが0.5ごとにパルスが反転（つまり1.0ごとに一周期）なので注意
			if ( ( ((int)(fIntermediate * 2)) % 2 ) == 0 )	//	0なら前半周期、1なら後半周期
				return (Ty)(m_rangeMin + _Sub() * ( fIntermediate*2 - (int)(fIntermediate*2) ) );
			else
				return (Ty)(m_rangeMin + _Sub() + _Sub() * -( fIntermediate*2 - (int)(fIntermediate*2) ) );
		}
	};
	typedef TTriWave<double> CTriWave, CTriangleWave, CDoubleTriWave, CDoubleTriangleWave;
	typedef TTriWave<float> CFloatTriWave, CFloatTriangleWave;
	typedef TTriWave<int> CIntTriWave, CIntTriangleWave;

	//////////////////////////////////////////////////////////////

	//	ノコギリ波（ ／|／|／| な波形）
	template <typename Ty>
	class TSawWave : public TLineBase<Ty>
	{
	public:
		TSawWave(){}
		virtual ~TSawWave(){}

		Ty Get(float fIntermediate){
			return (Ty)(m_rangeMin + _Sub() * (fIntermediate - (int)fIntermediate) );
		}
	};
	typedef TSawWave<double> CSawWave, CDoubleSawWave;
	typedef TSawWave<float> CFloatSawWave;
	typedef TSawWave<int> CIntSawWave;

	//////////////////////////////////////////////////////////////

	//	方形波（ ＿|￣|＿|￣| な波形）
	template <typename Ty>
	class TSquareWave : public TLineBase<Ty>
	{
	public:
		TSquareWave(){}
		virtual ~TSquareWave(){}

		Ty Get(float fIntermediate){
			//	fIntermediateが0.5ごとにパルスが反転（つまり1.0ごとに一周期）なので注意
			if ( ( ((int)(fIntermediate * 2)) % 2 ) == 0 )	//	0なら前半周期、1なら後半周期
				return (Ty)(m_rangeMin);
			else
				return (Ty)(m_rangeMin + _Sub());
		}
	};
	typedef TSquareWave<double> CSquareWave, CDoubleSquareWave;
	typedef TSquareWave<float> CFloatSquareWave;
	typedef TSquareWave<int> CIntSquareWave;

}//end of math namespace



//////////////////////////////////////////////////////////////////////

#define AGH_EFFECT_MODE_TIME	(1)
#define AGH_EFFECT_MODE_FRAME	(2)

//	エフェクトコントロールの基底クラス
class CEffectControlBase : public CControlBase {
private:
	bool m_bAvailable;
protected:
	int m_nCounter;
	int m_nGoalTime;	//	Termなんてのも考えた
	int m_mode;

	void SetGoalTime(int nGoalTime){
		/*if ( m_mode == AGH_EFFECT_MODE_FRAME )
			m_nGoalTime = nGoalTime-1;	//	最初と最後のフレームも含んだ数だから。-1するんです。
		else*/
			m_nGoalTime = nGoalTime;
	}

_AGH_EVENT_ACCESS_MODIFIER:
	virtual bool OnFrame(){
		if ( IsAvailable() ){
			if ( m_mode == AGH_EFFECT_MODE_FRAME )
				m_nCounter++;
			else
				throw 0;//	TODO: とりあえず時間取得は環境依存の部分が面倒なので後回し（多分MXPとか使う・・・）

			if ( m_nCounter >= m_nGoalTime ){
				//Stop();
				//OnEffectEnd();	//	2009/05/12
				if ( OnEffectEnd() )
					Stop();
			}
		}
		return true;
	}

	//	***** This Class After Methods *****
	virtual bool OnEffectStart(){return true;}
	virtual bool OnEffectEnd(){return true;}
	virtual bool OnEffectStop(){return true;}
	virtual bool OnEffectPause(){return true;}

public:
	CEffectControlBase(){
		ResetTime();
		SetCountInFrame();
		//Stop();
		m_bAvailable = false;	//	2009/05/23 これじゃないと駄目じゃない・・・？
		ResetTime();			//	2009/05/23 これじゃないと駄目じゃない・・・？
	}
	virtual ~CEffectControlBase(){}

	void ResetTime(){ m_nCounter = 0; }

	///////////////////////////

	void Start(){
		if ( OnEffectStart() ){
			m_bAvailable = true;
			ResetTime();
		}
	}
	void Stop(){
		if ( OnEffectStop() ){
			m_bAvailable = false;
			/*ResetTime(); m_nCounterがリセットされちゃう・・・*/
		}
	}
	void Pause(){
		if ( OnEffectPause() ){
			m_bAvailable = m_bAvailable ? false : true;
		}
	}

	///////////////////////////

	bool IsAvailable(){ return m_bAvailable; }

	void SetCountInFrame(){ m_mode = AGH_EFFECT_MODE_FRAME; }
	void SetCountInTime(){ m_mode = AGH_EFFECT_MODE_TIME; }
};

////////////////////////////////////////////////////////////////////////////////////////////////////

template <typename LINE_CLASS=CIntStraightLine>
class CColorLine
{
protected:
	LINE_CLASS m_la, m_lr, m_lg, m_lb;
};

//####################

//	色のフェード
template <typename LINE_CLASS = math::CIntStraightLine>
class TColorFadeEffect : public CEffectControlBase
{
private:
	typedef CEffectControlBase _BASE;
protected:
	//agh::COLOR m_startColor;
	//agh::COLOR m_endColor;
	CVisualControlBase *m_pTarget;

	//LINE_CLASS m_lineA, m_lineR, m_lineG, m_lineB;
	//LINE_CLASS _la, _lr, _lg, _lb;
	LINE_CLASS m_la, m_lr, m_lg, m_lb;

	//	イベントハンドラ
_AGH_EVENT_ACCESS_MODIFIER:
	virtual bool OnFrame(){

		/*if ( m_timeInFrame != 0 ){
			if ( m_timeInFrame <= m_frameCounter ){
				if ( pTargetColor == NULL )
					throw CAghException("CColorFadeController::OnFrame()  Target color not setted. "
						"Please call SetParentControl() or SetTargetColorPtr()");

				CEffectControlBase::OnFrame();
			}
			else
				m_timeInFrame = 0;
		}*/
		//if ( IsAvailable() ){
			float f = m_nCounter / (float)m_nGoalTime;
			m_pTarget->SetColor(AGHCOLOR_ARGB(m_la.Get(f), m_lr.Get(f), m_lg.Get(f), m_lb.Get(f)));
		//}

			
		_BASE::OnFrame();
		return true;
	}

	//	CEffectControlBase overrided.
	virtual bool OnEffectStart(){return OnFadeStart();}
	virtual bool OnEffectStop(){return OnFadeStop();}
	virtual bool OnEffectEnd(){return OnFadeEnd();}
	virtual bool OnEffectPause(){return OnFadePause();}

	//	***** This Class After Methods *****
	virtual bool OnFadeStart(){return true;}
	virtual bool OnFadeStop(){return true;}
	virtual bool OnFadeEnd(){return true;}
	virtual bool OnFadePause(){return true;}

public:
	//	コンストラクタ
	TColorFadeEffect(){
		//m_startColor = 0xffffffff;
		//m_startColor = 0;
		//m_endColor = 0xffffffff;
		m_nGoalTime = 0;
		m_pTarget = NULL;

		/*m_la.SetRange(0,255);
		m_lr.SetRange(0,255);
		m_lg.SetRange(0,255);
		m_lb.SetRange(0,255);*/
	}
	virtual ~TColorFadeEffect(){}

	///////////////////////////////////////////////////////////

	void SetTargetControl(CVisualControlBase* pControl){
		m_pTarget = pControl;
	}

	void Setup(CVisualControlBase* pControl, agh::COLOR startColor, agh::COLOR endColor, int nGoalTime){
		SetTargetControl(pControl);
		Fade(startColor, endColor, nGoalTime);
	}

	//////////////////////

	void Fade(agh::COLOR startColor, agh::COLOR endColor, int nGoalTime){
		//m_startColor = startColor;
		//m_endColor = endColor;
		//m_nGoalTime = nGoalTime;
		SetGoalTime(nGoalTime);

		unsigned char* pbStartColor = (unsigned char*)&startColor;
		unsigned char* pbEndColor = (unsigned char*)&endColor;
		m_lb.SetRange( pbStartColor[0], pbEndColor[0] );
		m_lg.SetRange( pbStartColor[1], pbEndColor[1] );
		m_lr.SetRange( pbStartColor[2], pbEndColor[2] );
		m_la.SetRange( pbStartColor[3], pbEndColor[3] );

		Start();
	}
	void FadeIn(int nGoalTime){ Fade( 0x00ffffff, 0xffffffff, nGoalTime); }
	void FadeOut(int nGoalTime){ Fade( 0xffffffff, 0x00ffffff, nGoalTime); }
	void FadeIn(CVisualControlBase* pControl, int nGoalTime){ Setup( pControl, 0x00ffffff, 0xffffffff, nGoalTime); }
	void FadeOut(CVisualControlBase* pControl, int nGoalTime){ Setup( pControl, 0xffffffff, 0x00ffffff, nGoalTime); }

};
typedef TColorFadeEffect<> CColorFadeEffect, CFadeEffect;

//	点滅
class CBlinkController : public CEffectControlBase {
};

#endif//__SFJP_MYU__AGH_EffectControl_H__