#ifndef __CUVECT3F_HPP__
#define __CUVECT3F_HPP__

namespace amscuda
{

    class cuvect3f
    {
        public:
        float x;
        float y;
        float z;

        __host__ __device__ cuvect3f();
        __host__ __device__ ~cuvect3f();
        __host__ __device__ cuvect3f(float _x, float _y, float _z);
        
        
        __host__ __device__ float& operator[](const int I);
        __host__ __device__ const float& operator[](const int I) const;

        __host__ __device__ cuvect3f operator+(cuvect3f lhs);
        __host__ __device__ cuvect3f operator-(cuvect3f lhs);
        __host__ __device__ cuvect3f operator*(float lhs);
        __host__ __device__ cuvect3f operator/(float lhs);
    };

    class cumat3f
    {
        public:
        float dat[9];

        __host__ __device__ cumat3f();
        __host__ __device__ ~cumat3f();
        __host__ __device__ float& operator[](const int I);
        __host__ __device__ float& operator()(const int I, const int J);
        __host__ __device__ float& at(const int I, const int J);

        __host__ __device__ cumat3f operator+(cumat3f lhs);
        __host__ __device__ cumat3f operator-(cumat3f lhs);
        __host__ __device__ cumat3f operator*(float lhs);
        __host__ __device__ cumat3f operator/(float lhs);
        __host__ __device__ cuvect3f operator*(cuvect3f lhs);
        __host__ __device__ cumat3f operator*(cumat3f lhs);

        __host__ __device__ float det();
        __host__ __device__ cumat3f transpose();
        __host__ __device__ cumat3f inverse();
    };

    __host__ __device__ float cuvect3f_dot(cuvect3f a, cuvect3f b);
    __host__ __device__ cuvect3f cuvect3f_cross(cuvect3f a, cuvect3f b);
    __host__ __device__ float cuvect3f_norm(cuvect3f a);
    __host__ __device__ cuvect3f cuvect3f_normalize(cuvect3f a);
    __host__ __device__ cuvect3f cuvect3f_proj(cuvect3f a, cuvect3f b);

    //3x3 matrix operations
    //matrix order is assumed to be mat[I,J] = mat[I+3*J]
    
    //transposes a 3x3 (9 element) matrix
    __host__ __device__ void mat3f_transpose(float *mat3inout);

    //copies src to dest
    __host__ __device__ void mat3f_copy(float *mat3f_dest, const float *mat3f_src);

    //returns determinant of 3x3 matrix
    __host__ __device__ float mat3f_det(float *mat3in);

    //inverts a 3x3 (9 element) matrix
    __host__ __device__ void mat3f_inverse(float *mat3inout);

    __host__ __device__ cuvect3f mat3f_mult(float *mat3in, cuvect3f cvin);
    __host__ __device__ void mat3f_mult(float *matina, float *matinb, float *matout);

    __host__ __device__ void mat3f_hodgedual(cuvect3f vecin, float *matout);
    __host__ __device__ void mat3f_hodgedual(float *matin, cuvect3f vecout);

    //returns direction cosine rotation matrix from axis and angle
    __host__ __device__ void mat3f_rot_from_axisangle(cuvect3f axis, float angle, float *matout);

    __host__ void test_cudavectf_logic1();

};

#endif

