#ifndef __CUVECT2_HPP__
#define __CUVECT2_HPP__

namespace amscuda
{

    class cuvect2
    {
        public:
        double x;
        double y;


        __host__ __device__ cuvect2();
        __host__ __device__ ~cuvect2();
        __host__ __device__ cuvect2(double _x, double _y);

        __host__ __device__ double& operator[](const int I);
        __host__ __device__ const double& operator[](const int I) const;

        __host__ __device__ cuvect2 operator+(cuvect2 lhs);
        __host__ __device__ cuvect2 operator-(cuvect2 lhs);
        __host__ __device__ cuvect2 operator*(double lhs);
        __host__ __device__ cuvect2 operator/(double lhs);
        __host__ __device__ friend cuvect2 operator-(cuvect2 rhs);
    };

    class cumat2
    {
        public:
        double dat[4];

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

        __host__ __device__ cumat2 operator+(cumat2 lhs);
        __host__ __device__ cumat2 operator-(cumat2 lhs);
        __host__ __device__ cumat2 operator*(double lhs);
        __host__ __device__ cumat2 operator/(double lhs);
        __host__ __device__ cuvect2 operator*(cuvect2 lhs);
        __host__ __device__ cumat2 operator*(cumat2 lhs);
        __host__ __device__ friend cumat2 operator-(cumat2 rhs);

        __host__ __device__ double det();
        __host__ __device__ cumat2 transpose();
        __host__ __device__ cumat2 inverse();
    };

    __host__ __device__ double cuvect2_dot(cuvect2 a, cuvect2 b);
    __host__ __device__ double cuvect2_cross(cuvect2 a, cuvect2 b);
    __host__ __device__ double cuvect2_norm(cuvect2 a);
    __host__ __device__ cuvect2 cuvect2_normalize(cuvect2 a);
    __host__ __device__ cuvect2 cuvect2_proj(cuvect2 a, cuvect2 b);

    //2x2 matrix operations
    //matrix order is assumed to be mat[I,J] = mat[I+3*J]

    //transpose a 2x2 matrix in place
    __host__ __device__ void mat2_transpose(double *mat2inout);
    
    //copies src to dest
    __host__ __device__ void mat2_copy(double *mat2_dest, const double *mat2_src);
    
    //inverts mat?inout[4]
    __host__ __device__ void mat2_inverse(double *mat2inout);
    
    //rotatin matrix from angle
    __host__ __device__ void mat2_rot_from_angle(double angle, double *mat2);

    //multiplies c = a*b
    __host__ __device__ void mat2_mult(double *mat2a, double *mat2b, double *mat2c);

    // ret = a*b
    __host__ __device__ cuvect2 mat2_mult(double *mat2a, cuvect2 b);



    void test_cuvect2_1();
    

}; //end namespace amscuda

#endif

