#define MPMG_GUARDIAN

#ifndef MGML_GLOBALS
	#include "MGML_GLOBALS.h"
#endif

namespace MPMG_INTIMATE
{
 struct Stop
 { static universal_call void exec(){}
   
   template<class Env>
   static universal_call void exec(Env& env){}

   template<class Lhs,class Rhs>
   static universal_call void exec(Lhs& lhs,Rhs& rhs){}
 };


};

// метапрограммирование 
namespace MPMG
{
static const int DEFAULT  = ~(~0u >> 1); // наименьшее число int 
static const int endValue = ~(~0u >> 1);


template<bool>
struct STATIC_ASSERT;

template<>
struct STATIC_ASSERT<true> {};




//============================================================== IF
template<bool condition,class Then,class Else>
struct IF
{typedef Then RET;
};

template<class Then,class Else>
struct IF<false,Then,Else>
{ typedef Else RET;
};
//============================================================== IF


//============================================================== SWITCH
struct NilCase {};

template<int tag_,class Type_,class Next_ = NilCase>
struct CASE
{
	enum {tag = tag_};
	typedef Type_ Type;
	typedef Next_ Next;
};

template<int tag,class Case>
class SWITCH
{
	typedef typename Case::Next NextCase;
	enum {
		caseTag = Case::tag,
		found = (caseTag == tag || caseTag == (int)DEFAULT)
	};
public:
	typedef typename IF<found,
		typename Case::Type,
		typename SWITCH<tag,NextCase>::RET
	>::RET RET;
};

template<int tag>
class SWITCH<tag,NilCase>
{
public:
	typedef NilCase RET;
};
//============================================================== SWITCH



//============================================================== CONS
struct End
{
	typedef End Head;
	typedef End Tail;
};

template<class Head_,class Tail_ = End>
struct Cons
{
	typedef Head_  Head;
	typedef Tail_  Tail;
};


// возвращает длину списка
template<class List>
struct Length
{
	enum {RET = Length<typename List::Tail>::RET + 1}; 
};

template<>
struct Length<End>
{
	enum {RET=0};
};

// добавляет один элемент к списку
template<class List1,class List2>
struct Append
{
	enum {curr_lenght = Length< List1 >::RET };

	typedef typename Cons<typename List1::Head, 
		                  typename IF<curr_lenght == 1,
								     typename Cons<List2,End>, 
								   typename  Append<typename List1::Tail,List2>::RET >::RET > RET;		             
};

template<class List2>
struct Append<End,List2>
{
	typedef List2 RET;
};

// пуст ли список?
template<class List>
struct IsEmpty
{
	enum {RET = false};
};

template<>
struct IsEmpty<End>
{
	enum {RET = true};
};


// последний элемент списка.
template<class List>
struct Last
{
	enum {curr_lenght = Length< List >::RET };

	typedef typename IF<curr_lenght == 1,
		               Cons<typename List::Head,typename End>, 
					 typename Last<typename List::Tail>::RET >::RET RET;

};

template<>
struct Last<End>
{
	typedef End RET;
};


// отрезает один элемент списка.
template<class List>
struct Cut_Off
{
	enum {curr_lenght = Length< List >::RET };

	typedef typename Cons<typename List::Head, 
		               typename IF<curr_lenght == 2,
									End, 
								typename Cut_Off<typename List::Tail>::RET >::RET > RET;

};

template<>
struct Cut_Off<End>
{
	typedef End RET;
};


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


};




namespace _MGML_VEC
{
template<class T>
struct ZeroIter
{
   inline static universal_call void exec(T* c,const T* a,const T* b){}
   inline static universal_call void exec(T* c,const T* a,const T b){}
   inline static universal_call void exec(T* c,const T* b){}
   inline static universal_call void exec(T* c,const T b){}
};

};

namespace MGML_MATH
{


//=================================================================================== скалярное произведение
template <int n,class T> 
struct DotMult
{
   inline static universal_call T exec(const T* a,const T* b)
   {
	   return (*a)*(*b) + DotMult<n-1,T>::exec(a+1,b+1);
   }
};

template<class T>
struct DotMult<0,T>
{
   inline static universal_call T exec(const T* a,const T* b)
   {
	   return 0;
   }
};
// \\=================================================================================== скалярное произведение

//=================================================================================== копирование векторов
template <int n,class T> 
struct MovVec
{
   inline static universal_call void exec(T* a,const T* b)
   {
     *a = *b;
	   MovVec<n-1,T>::exec(a+1,b+1);
   }
};

template<class T>
struct MovVec<0,T>:public _MGML_VEC::ZeroIter<T> { };
// \\ ===================================================================================копирование векторов

//=================================================================================== сумма векторов
template <int n,class T> 
struct AddVec
{
   inline static universal_call void exec(T* c,const T* a,const T* b)
   {
    *c = *a + *b;
	AddVec<n-1,T>::exec(c+1,a+1,b+1);
   }

   inline static universal_call void exec(T* c,const T* a,const T b)
   {
    *c = *a + b;
	AddVec<n-1,T>::exec(c+1,a+1,b);
   }

   inline static universal_call void exec(T* c,const T* b)
   {
    *c += *b;
	AddVec<n-1,T>::exec(c+1,b+1);
   }

   inline static universal_call void exec(T* c,const T b)
   {
    *c += b;
	AddVec<n-1,T>::exec(c+1,b);
   }
};

template<class T>
struct AddVec<0,T>: public _MGML_VEC::ZeroIter<T> { };
// \\=================================================================================== сумма векторов

//=================================================================================== разность векторов
template <int n,class T> 
struct SubVec
{
   inline static universal_call void exec(T* c,const T* a,const T* b)
   {
    *c = *a - *b;
     SubVec<n-1,T>::exec(c+1,a+1,b+1);
   }

   inline static universal_call void exec(T* c,const T* a,const T b)
   {
    *c = *a - b;
	SubVec<n-1,T>::exec(c+1,a+1,b);
   }

   inline static universal_call void exec(T* c,const T* b)
   {
    *c -= *b;
	SubVec<n-1,T>::exec(c+1,b+1);
   }

   inline static universal_call void exec(T* c,const T b)
   {
    *c -= b;
	SubVec<n-1,T>::exec(c+1,b);
   }
};

template<class T>
struct SubVec<0,T>: public _MGML_VEC::ZeroIter<T> { };
// \\=================================================================================== разность векторов

//=================================================================================== покомпонентное умножение векторов
template <int n,class T> 
struct MulVec
{
   inline static universal_call void exec(T* c,const T* a,const T* b)
   {
    *c = (*a)*(*b);
     MulVec<n-1,T>::exec(c+1,a+1,b+1);
   }

   inline static universal_call void exec(T* c,const T* a,const T b)
   {
    *c = (*a)*b;
	MulVec<n-1,T>::exec(c+1,a+1,b);
   }

   inline static universal_call void exec(T* c,const T* b)
   {
    *c *= *b;
	MulVec<n-1,T>::exec(c+1,b+1);
   }

   inline static universal_call void exec(T* c,const T b)
   {
    *c *= b;
	MulVec<n-1,T>::exec(c+1,b);
   }
};

template<class T>
struct MulVec<0,T>: public _MGML_VEC::ZeroIter<T> { };
// \\=================================================================================== покомпонентное умножение векторов



//=================================================================================== покомпонентное деление векторов
template <int n,class T> 
struct DivVec
{
   inline static universal_call void exec(T* c,const T* a,const T* b)
   {
    *c = (*a)/(*b);
     DivVec<n-1,T>::exec(c+1,a+1,b+1);
   }

   inline static universal_call void exec(T* c,const T* a,const T b)
   {
    *c = (*a)/b;
	DivVec<n-1,T>::exec(c+1,a+1,b);
   }

   inline static universal_call void exec(T* c,const T* b)
   {
    *c /= *b;
	DivVec<n-1,T>::exec(c+1,b+1);
   }

   inline static universal_call void exec(T* c,const T b)
   {
    *c /= b;
	DivVec<n-1,T>::exec(c+1,b);
   }
};

template<class T>
struct DivVec<0,T>: public _MGML_VEC::ZeroIter<T> { };
// \\=================================================================================== покомпонентное деление векторов

};

