#ifndef FULLSTATICCOOLEYTUKEY_H
#define FULLSTATICCOOLEYTUKEY_H

#include<iostream>
#include<complex>

#include"ReverseBits.h"
#include"CtrlTmpl.h"
//#include"Print.h"
//#include"Unit.h"

#include"StaticReal.h"
#include"StaticMathlib.h"

template<typename Env>
struct FSCalcLoop3Cond
//all variannts of lower bits of indices
{
	static const bool cond = (Env::i < Env::count);
};

template<typename Enviroment>
struct FSCalcLoop3Body
{
	struct Env
	{
		typedef typename Enviroment::Conf Conf;
		typedef typename Conf::Complex Complex;
		typedef typename Conf::Int Int;
		typedef typename Conf::Float Float;
		static const Int stride = Enviroment::stride;
		static const Int step = Enviroment::step;
		
		static const Int curOfst0 = Enviroment::offset0;
		static const Int curOfst1 = Enviroment::offset1;
		static const Int offset0 = Enviroment::offset0 + step;
		static const Int offset1 = offset0 + stride;
		static const Int count = Enviroment::count;
		static const Int i = Enviroment::i + 1;
					
		static void exec(Float wr, Float wi)
		{
			Enviroment::exec(wr, wi);
			Complex x0 = Conf::buffer[curOfst0];
			Complex x1 = Conf::buffer[curOfst1];
			/*
			std::cerr << "\nindex for x0: " << curOfst0 << ", x0 =" << x0
						<< ", index for x1: " << curOfst1 << ", x0 =" << x1
						<< ", wr = " << vwr << ", wi = " << vwi << "\t(Static)";
			*/
			x1 = Complex(x1.real()*wr - x1.imag()*wi
									, x1.imag()*wr + x1.real()*wi);
			Conf::buffer[curOfst0] = x0 + x1;
			Conf::buffer[curOfst1] = x0 - x1;
		}
	};
};
		
template<typename Env>
struct FSCalcLoop2Cond
//all variannts of upper bits of indices
{
	static const bool cond = (Env::m < Env::mmax);
};

template<typename Enviroment>
struct FSCalcLoop2Body
{
	struct Env
	{
		typedef typename Enviroment::Conf Conf;
		typedef typename Conf::Int Int;
		typedef typename Conf::Float Float;
		static const Int mmax = Enviroment::mmax;
		static const Int count = Enviroment::count;
		static const Int stride = Enviroment::stride;
		static const Int step = Enviroment::step;
		
		struct InitEnv
		{
			typedef typename Enviroment::Conf Conf;
			static const Int stride = Enviroment::stride;
			static const Int step = Enviroment::step;
			static const Int count = Enviroment::count;
			
			static const Int offset0 = Enviroment::m;
			static const Int offset1 = offset0 + stride;
			static const Int i = 0;			
			
			static void exec(Float wr, Float wi)
			{;}
		};
		
		typedef typename For<InitEnv, FSCalcLoop3Cond, FSCalcLoop3Body>::Result InnerLoopResult;
	
		typedef typename Enviroment::wpr wpr;
		typedef typename Enviroment::wpi wpi;
			
		typedef typename Enviroment::wr wtemp;
		typedef typename StaticMulReal<typename Enviroment::wr,wpr>::result wr_1t;
		typedef typename StaticMulReal<typename Enviroment::wi,wpi>::result wr_2t;
		typedef typename StaticSubReal<wr_1t,wr_2t>::result wr_1_2t;
		typedef typename StaticAddReal<wr_1_2t,typename Enviroment::wr>::result wr;
		
		typedef typename StaticMulReal<typename Enviroment::wi,wpr>::result wi_1t;
		typedef typename StaticMulReal<wtemp,wpi>::result wi_2t;
		typedef typename StaticAddReal<wi_1t,wi_2t>::result wi_1_2t;
		typedef typename StaticAddReal<wi_1_2t,typename Enviroment::wi>::result wi;
		
		static const Int m = Enviroment::m + 1;			
		
		static void exec(void)
		{
			Float vwr = StaticFromReal<typename Enviroment::wr>::get();
			Float vwi = StaticFromReal<typename Enviroment::wi>::get();
			
			Enviroment::exec();
			InnerLoopResult::exec(vwr, vwi);
		}
	};
};

template<typename Env>
struct FSCalcLoop1Cond
{
	static const bool cond = (Env::p > 0);
};

template<typename Enviroment>
struct FSCalcLoop1Body
{
	
	struct Env
	{
		typedef typename Enviroment::Conf Conf;
		typedef typename Conf::Int Int;
		typedef typename Conf::Float Float;
					
		static const Int mmax = Enviroment::mmax * 2;
		static const Int count = Enviroment::count / 2;			
		static const Int p = Enviroment::p - 1;				
			
		struct InitEnv
		{
			typedef typename Enviroment::Conf Conf;
			static const Int stride = Enviroment::mmax;
			static const Int step = stride * 2;
			static const Int mmax = Enviroment::mmax;
			static const Int count = Enviroment::count;			
			static const Int m = 0;	
				
			typedef typename StaticIntToReal<int,Float,Conf::direction * 2>::value thetaQN;
			typedef typename StaticIntToReal<int,Float,Enviroment::mmax>::value thetaQD;
			typedef typename StaticIntToReal<int,Float,Enviroment::mmax * 2>::value thetaQ_halfD;
			typedef typename StaticDivReal<thetaQN, thetaQD>::result thetaQ;
			typedef typename StaticDivReal<thetaQN, thetaQ_halfD>::result thetaQ_half;
			typedef typename StaticSinQ<thetaQ_half>::result wtemp;
			typedef typename StaticMulReal<wtemp,wtemp>::result wpr_;
			typedef typename StaticRealConst<Float>::one wr;
			typedef typename StaticRealConst<Float>::zero wi;
			typedef typename StaticMulReal<typename StaticIntToReal<int,Float,-2>::value,wpr_>::result wpr;
			typedef typename StaticSinQ<thetaQ>::result wpi;
			static void exec(void)
			{
				/*
				std::cerr << "\n\tthetaQ/4: " << StaticFromReal<thetaQ>().value/4
							<< ", wtemp: " << StaticFromReal<wtemp>().value
							<< ", wpr: " << StaticFromReal<wpr>().value
							<< ", wpi: " << StaticFromReal<wpi>().value;
				*/
			}
		};
		
		typedef typename For<InitEnv, FSCalcLoop2Cond, FSCalcLoop2Body>::Result InnerLoopResult;
		
		static void exec(void)
		{
			Enviroment::exec();
			InnerLoopResult::exec();
		}
	};
};

template<typename Config>
struct FullStaticFFTCalc
{
	typedef Config Conf;
	typedef typename Conf::Int Int;
	typedef typename Conf::UInt UInt;
	static const Int num = Conf::size;
	static const Int nbits = Int(BitsForStaticN<UInt, UInt(num - 1)>::result);
	
	struct InitEnv
	{
		typedef Config Conf;
		static const Int p = nbits;
		static const Int mmax = 1;// ==2^0
		static const Int count = num / 2;// ==2^(bits-1)
		static void exec()
		{
			;
		}
	};
	
	typedef typename For<InitEnv, FSCalcLoop1Cond, FSCalcLoop1Body>::Result Code;
	
	static void exec(void)
	{
		Code::exec();
	}
};

#endif //STATICCOOLEYTUKEY_H
