/*!
 	@file
 	@brief	普通のカウンタテンプレート
 		インライン定義してあるので、普通の値と変わらないはず
 
 		Stepを超えた ++,-- は同じ回数反対にしないと戻ってこない
 */

#ifndef NormalCounter_h
#define NormalCounter_h

#include"../../Setup/CompileMode.h"


namespace Maid
{
	/*!
	 	@class CCounter Counter.h
	 	@brief 普通のカウンタテンプレート
	 */
	template<class T, class A=T>
	class CCounter
	{
	public:
		CCounter( T Value=0 );

		CCounter<T,A>& operator++()		{ Inc(); return (*this); }
		CCounter<T,A>  operator++(int)	{ CCounter<T,A> _Tmp = *this; Inc(); return (_Tmp); }
		CCounter<T,A>& operator--()		{ Dec(); return (*this); }
		CCounter<T,A>  operator--(int)	{ CCounter<T,A> _Tmp = *this; Dec(); return (_Tmp); }

		operator T() const { return Get(); }


		void	Set( T Start, T End, int Step );

		void	Inc();
		void	Dec();
		void	Reset( int NewStep=0 ) { m_NowStep=min(m_Step,NewStep); }

		T	Get()	  const;
		T	GetStart()const	{ return m_Start;	}
		T	GetEnd()  const	{ return m_End;		}
		int	GetStep() const	{ return m_Step;	}
		int	GetNowStep()const{ return m_NowStep;}

		bool	IsEnd()   const{ return m_Step==0 || m_Step<=m_NowStep; }
		bool	IsBegin() const{ return m_Step==0 || m_NowStep<=0; }


	private:
		T	m_Start;
		T	m_End;
		int	m_Step;
		int	m_NowStep;
	};





	/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
	//! コンストラクタ
	/*!
	 	@param  Value		[i ]	初期値（デフォルトで０）
	 */
	template<class T, class A> CCounter<T,A>::CCounter( T Value )
	{
		Set( Value, Value, 0 );
	};


	/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
	//! カウンタの初期化
	/*!
	 	@param  Start		[i ]	初期値
	 	@param  End			[i ]	終了値
	 	@param  Step		[i ]	終了値になるまでに何回インクリメントするか
	\n								Step==0 の時は常に End が返る
	 */
	template<class T, class A>
	void CCounter<T,A>::Set( T Start, T End, int Step )
	{
		m_Start	= Start;
		m_End	= End;
		m_Step		= Step;
		m_NowStep	= 0;
	};

	/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
	//! カウンタのインクリメント
	/*!
	 */
	template<class T, class A>
	void CCounter<T,A>::Inc()
	{
		//	クリップはしない（実際に取得するときにクリップする）
		m_NowStep++;
	}


	/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
	//! カウンタのデクリメント
	/*!
	 */
	template<class T, class A>
	void CCounter<T,A>::Dec()
	{
		//	クリップはしない（実際に取得するときにクリップする）
		m_NowStep--;
	}


	/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
	//! 現在の値を取得する
	/*!
		@return 現在の値
	 */
	template<class T, class A>
	T CCounter<T,A>::Get()const
	{
		if( IsEnd()		) { return m_End;	}
		if( IsBegin()	) { return m_Start; }

		if( m_Start>m_End ) { return A(m_End) + A(m_Start-m_End) * A(m_Step-m_NowStep) / A(m_Step) ; }
		return A(m_Start) + A(m_End-m_Start) * A(m_NowStep) / A(m_Step) ;
	}
}

#endif
