#ifndef Foundation_Math_Rotate_INCLUDED
#define Foundation_Math_Rotate_INCLUDED

#include <foundation/Math/misc.hpp>

namespace Tn {

namespace math {

template <typename T>
struct Rotate {
    
    typedef T component_type;
    
    Vec<3,T> face;
    Vec<3,T> up;
    
    Rotate(const Vec<3,T> f, const Vec<3,T> u) : face(f), up(u) {}
};

typedef Rotate<float> Rotatef;
typedef Rotate<double> Rotated;
    
template <typename T>
struct RotateXDeg {

    RotateXDeg() : degrees(T(0)) {}
    RotateXDeg(T d) : degrees(d) {}

    T degrees;
};


template <typename T>
struct RotateYDeg {

    RotateYDeg() : degrees(T(0)) {}
    RotateYDeg(T d) : degrees(d) {}

    T degrees;
};


template <typename T>
struct RotateZDeg {

    RotateZDeg() : degrees(T(0)) {}
    RotateZDeg(T d) : degrees(d) {}

    T degrees;
};

typedef RotateXDeg<float> RotateXDegf;
typedef RotateYDeg<float> RotateYDegf;
typedef RotateZDeg<float> RotateZDegf;

typedef RotateXDeg<double> RotateXDegd;
typedef RotateYDeg<double> RotateYDegd;
typedef RotateZDeg<double> RotateZDegd;


template <typename T>
struct RotateXRad {

    RotateXRad() : radians(T(0)) {}
    RotateXRad(T r) : radians(r) {}

    T radians;
};


template <typename T>
struct RotateYRad {

    RotateYRad() : radians(T(0)) {}
    RotateYRad(T r) : radians(r) {}

    T radians;
};


template <typename T>
struct RotateZRad {

    RotateZRad() : radians(T(0)) {}
    RotateZRad(T r) : radians(r) {}

    T radians;
};

typedef RotateXRad<float> RotateXRadf;
typedef RotateYRad<float> RotateYRadf;
typedef RotateZRad<float> RotateZRadf;

typedef RotateXRad<double> RotateXRadd;
typedef RotateYRad<double> RotateYRadd;
typedef RotateZRad<double> RotateZRadd;


template <typename T>
struct RotateXPos90 {};
template <typename T>
struct RotateYPos90 {};
template <typename T>
struct RotateZPos90 {};

typedef RotateXPos90<float> RotateXPos90f;
typedef RotateYPos90<float> RotateYPos90f;
typedef RotateZPos90<float> RotateZPos90f;

typedef RotateXPos90<double> RotateXPos90d;
typedef RotateYPos90<double> RotateYPos90d;
typedef RotateZPos90<double> RotateZPos90d;

template <typename T>
struct RotateXNeg90 {};
template <typename T>
struct RotateYNeg90 {};
template <typename T>
struct RotateZNeg90 {};

typedef RotateXNeg90<float> RotateXNeg90f;
typedef RotateYNeg90<float> RotateYNeg90f;
typedef RotateZNeg90<float> RotateZNeg90f;

typedef RotateXNeg90<double> RotateXNeg90d;
typedef RotateYNeg90<double> RotateYNeg90d;
typedef RotateZNeg90<double> RotateZNeg90d;


template <typename T>
struct RotateX180 {};
template <typename T>
struct RotateY180 {};
template <typename T>
struct RotateZ180 {};

typedef RotateX180<float> RotateX180f;
typedef RotateY180<float> RotateY180f;
typedef RotateZ180<float> RotateZ180f;

typedef RotateX180<double> RotateX180d;
typedef RotateY180<double> RotateY180d;
typedef RotateZ180<double> RotateZ180d;

} // end namespace math

} // end namespace Tn


template <typename T>
inline bool isIdentity(Tn::math::RotateXDeg<T> const & rotate) {
    return rotate.degrees == T(0);
}


template <typename T>
inline bool isIdentity(Tn::math::RotateYDeg<T> const & rotate) {
    return rotate.degrees == T(0);
}


template <typename T>
inline bool isIdentity(Tn::math::RotateZDeg<T> const & rotate) {
    return rotate.degrees == T(0);
}


template <typename T>
inline bool isIdentity(Tn::math::RotateXRad<T> const & rotate) {
    return rotate.radians == T(0);
}


template <typename T>
inline bool isIdentity(Tn::math::RotateYRad<T> const & rotate) {
    return rotate.radians == T(0);
}


template <typename T>
inline bool isIdentity(Tn::math::RotateZRad<T> const & rotate) {
    return rotate.radians == T(0);
}

#endif
