#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(const float &_x, const float &_y, const float &_z);
        
        
        __host__ __device__ float& operator[](const int &I);
        __host__ __device__ const float& operator[](const int &I) const;

        __host__ __device__ cuvect3f operator+(const cuvect3f &rhs);
        __host__ __device__ cuvect3f operator-(const cuvect3f &rhs);
        __host__ __device__ cuvect3f operator*(const float &rhs);
        __host__ __device__ cuvect3f operator/(const float &rhs);
        __host__ __device__ friend cuvect3f operator-(const cuvect3f &rhs);

        __host__ __device__ cuvect3f& operator+=(const cuvect3f &rhs);
        __host__ __device__ cuvect3f& operator-=(const cuvect3f &rhs);
        __host__ __device__ cuvect3f& operator/=(const float &rhs);
        __host__ __device__ cuvect3f& operator*=(const float &rhs);

    };

    class cumat3f
    {
        public:
        float m00,m10,m20; //named references to force register use?
        float m01,m11,m21; //switched to column-major-order to match GLSL/lapack
        float m02,m12,m22;

        __host__ __device__ cumat3f();
        __host__ __device__ ~cumat3f();
        __host__ __device__ cumat3f(
            const float & _m00, const float & _m01, const float & _m02,
            const float & _m10, const float & _m11, const float & _m12,
            const float & _m20, const float & _m21, const float & _m22
        );

        __host__ __device__ explicit cumat3f(const float *data9);
        

        __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__ const float& operator[](const int &I) const;
        __host__ __device__ const float& operator()(const int &I, const int &J) const;
        __host__ __device__ const float& at(const int &I, const int &J) const;

        __host__ __device__ cumat3f operator+(const cumat3f &rhs);
        __host__ __device__ cumat3f operator-(const cumat3f &rhs);
        __host__ __device__ cumat3f operator*(const float &rhs);
        __host__ __device__ cumat3f operator/(const float &rhs);
        __host__ __device__ cuvect3f operator*(const cuvect3f &rhs);
        __host__ __device__ cumat3f operator*(const cumat3f &rhs);
        __host__ __device__ friend cumat3f operator-(const cumat3f &rhs);
        
        __host__ __device__ float det();
        __host__ __device__ cumat3f transpose();
        __host__ __device__ cumat3f inverse();

        __host__ __device__ float* data(); //pointer to float[9] representation of matrix
        __host__ __device__ const float* data() const; //pointer to float[9] representation of matrix

        //In place operations (to save GPU register use)
        __host__ __device__ cumat3f& operator+=(const cumat3f &rhs);
        __host__ __device__ cumat3f& operator-=(const cumat3f &rhs);
        __host__ __device__ cumat3f& operator/=(const float &rhs);
        __host__ __device__ cumat3f& operator*=(const float &rhs);
        __host__ __device__ cumat3f& operator*=(const cumat3f &rhs);
        
    };

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

    __host__ __device__ cumat3f hodge_dual(const cuvect3f &vin);
    __host__ __device__ cuvect3f hodge_dual(const cumat3f &min);
    __host__ __device__ cumat3f rotmat_from_axisangle(const cuvect3f &axis, const float &angle);

    __host__ void test_cudavectf_logic1();

};

#include <amsculib2/cuvect3f_legacy.hpp>

#endif

