//#####################################################################
// Copyright 2013.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class TENSORS_FORWARD
//##################################################################### 
#ifndef __TENSORS_FORWARD__
#define __TENSORS_FORWARD__

#include <Core/Tensors/TENSORS_FORWARD.h>
#include <Core/Math_Tools/cube.h>
#include <Core/Matrices/MATRIX.h>
#include <Core/Matrices/PRIMITIVE_MATRICES.h>
#include <Core/Matrices/SYMMETRIC_MATRIX.h>
#include <Core/Vectors/VECTOR.h>
#include <cmath>
namespace PhysBAM{

// general T_ijk
template<class T,int mm,int nn=mm,int pp=nn> class TENSOR;
template<class T,int uu,int mm,int nn=mm> class SYMMETRIC_TENSOR;
template<class T,int mm,int nn=mm,int pp=nn> class ZERO_TENSOR;
template<class T,int uu,int mm,int nn=mm> class VEC_ID_TENSOR;
template<class T,int uu,int mm> class VEC_ID_SYM_TENSOR;
template<class T> class PERMUTATION_TENSOR;
template<class T,int m> class DIAGONAL_TENSOR;

template<class T> struct IS_TENSOR{static const int value=0;};
template<class T,int m,int n,int p> struct IS_TENSOR<ZERO_TENSOR<T,m,n,p> > {static const int value=1;};
template<class T,int m,int n,int p> struct IS_TENSOR<TENSOR<T,m,n,p> > {static const int value=1;};
template<class T,int u,int m,int n> struct IS_TENSOR<SYMMETRIC_TENSOR<T,u,m,n> > {static const int value=1;};
template<class T,int u,int m,int n> struct IS_TENSOR<VEC_ID_TENSOR<T,u,m,n> > {static const int value=1;};
template<class T,int u,int m> struct IS_TENSOR<VEC_ID_SYM_TENSOR<T,u,m> > {static const int value=1;};
template<class T> struct IS_TENSOR<PERMUTATION_TENSOR<T> > {static const int value=1;};
template<class T,int m> struct IS_TENSOR<DIAGONAL_TENSOR<T,m> > {static const int value=1;};

template<int s,class T> struct IS_SYM_TENSOR{static const int value=0;};
template<class T,int m,int n> struct IS_SYM_TENSOR<0,ZERO_TENSOR<T,m,n,n> > {static const int value=1;};
template<class T,int m,int n> struct IS_SYM_TENSOR<1,ZERO_TENSOR<T,n,m,n> > {static const int value=1;};
template<class T,int m,int n> struct IS_SYM_TENSOR<2,ZERO_TENSOR<T,n,n,m> > {static const int value=1;};
template<int s,class T,int m,int n> struct IS_SYM_TENSOR<s,SYMMETRIC_TENSOR<T,s,m,n> > {static const int value=1;};
template<int s,class T,int m,int n> struct IS_SYM_TENSOR<s,VEC_ID_TENSOR<T,s,m,n> > {static const int value=1;};
template<int s,class T,int m> struct IS_SYM_TENSOR<s,VEC_ID_SYM_TENSOR<T,s,m> > {static const int value=1;};
template<class T,int m,int s> struct IS_SYM_TENSOR<s,DIAGONAL_TENSOR<T,m> > {static const int value=1;};

static constexpr int ten_zero=12;
static constexpr int ten_perm=11;
static constexpr int ten_diag=10;
static constexpr int ten_vec_id_sym=7; // 7 8 9
static constexpr int ten_vec_id=4; // 4 5 6
static constexpr int ten_sym=1;// 1 2 3
static constexpr int ten_gen=0;

template<class T,int type,int m,int n,int p> struct TEN_TYPE_{typedef void TYPE;};
template<class T,int m,int n,int p> struct TEN_TYPE_<T,ten_zero,m,n,p>{typedef ZERO_TENSOR<T,m,n,p> TYPE;};
template<class T> struct TEN_TYPE_<T,ten_perm,3,3,3>{typedef PERMUTATION_TENSOR<T> TYPE;};
template<class T,int m> struct TEN_TYPE_<T,ten_diag,m,m,m>{typedef DIAGONAL_TENSOR<T,m> TYPE;};
template<class T,int m> struct TEN_TYPE_<T,ten_vec_id_sym+0,m,m,m>{typedef VEC_ID_SYM_TENSOR<T,0,m> TYPE;};
template<class T,int m> struct TEN_TYPE_<T,ten_vec_id_sym+1,m,m,m>{typedef VEC_ID_SYM_TENSOR<T,1,m> TYPE;};
template<class T,int m> struct TEN_TYPE_<T,ten_vec_id_sym+2,m,m,m>{typedef VEC_ID_SYM_TENSOR<T,2,m> TYPE;};
template<class T,int m,int n> struct TEN_TYPE_<T,ten_vec_id+0,m,n,n>{typedef VEC_ID_TENSOR<T,0,m,n> TYPE;};
template<class T,int m,int n> struct TEN_TYPE_<T,ten_vec_id+1,n,m,n>{typedef VEC_ID_TENSOR<T,1,m,n> TYPE;};
template<class T,int m,int n> struct TEN_TYPE_<T,ten_vec_id+2,n,n,m>{typedef VEC_ID_TENSOR<T,2,m,n> TYPE;};
template<class T,int m,int n> struct TEN_TYPE_<T,ten_sym+0,m,n,n>{typedef SYMMETRIC_TENSOR<T,0,m,n> TYPE;};
template<class T,int m,int n> struct TEN_TYPE_<T,ten_sym+1,n,m,n>{typedef SYMMETRIC_TENSOR<T,1,m,n> TYPE;};
template<class T,int m,int n> struct TEN_TYPE_<T,ten_sym+2,n,n,m>{typedef SYMMETRIC_TENSOR<T,2,m,n> TYPE;};
template<class T,int m,int n,int p> struct TEN_TYPE_<T,ten_gen,m,n,p>{typedef TENSOR<T,m,n,p> TYPE;};
template<class T,int t,int m,int n,int p> using TEN_TYPE=typename TEN_TYPE_<T,t,m,n,p>::TYPE;
}
#endif
