#ifndef __AMSMATHUTIL25_VEC4_HPP__
#define __AMSMATHUTIL25_VEC4_HPP__

namespace ams
{

class vec4; 
class mat4;

class vec4
{
public:
    double x;
    double y;
    double z;
    double w;

    vec4();
    vec4(double _x, double _y, double _z, double _w);
    vec4(const vec4 &rhs);
    vec4& operator=(const vec4 &rhs);
    bool operator==(vec4 rhs);
    
    vec4 operator+(vec4 rhs) const;
    vec4 operator-(vec4 rhs) const;
    vec4 operator*(double rhs) const;
    vec4 operator/(double rhs) const;
    friend vec4 operator-(vec4 rhs);

    double& operator[](int ind);
    const double& operator[](int ind) const;
};

//vector operations
double vec4_dot(vec4 v1, vec4 v2);
double vec4_norm(vec4 v);
vec4 vec4_normalize(vec4 v);
double vec4_dist(vec4 v1, vec4 v2);
vec4 vec4_proj(vec4 v1, vec4 v2);

//vector operations (old nomenclature)
double vdot(vec4 v1, vec4 v2);
double vnorm(vec4 v);
vec4 vnormalize(vec4 v);
double vdist(vec4 v1, vec4 v2);
vec4 vproj(vec4 v1, vec4 v2);

class mat4
{
public:
    double data[16];

    mat4();
    mat4(
        double _xx, double _yx, double _zx, double _wx,
        double _xy, double _yy, double _zy, double _wy,
        double _xz, double _yz, double _zz, double _wz,
        double _xw, double _yw, double _zw, double _ww
    );
    mat4(const double *_data);
    mat4(const mat4 &rhs);
    mat4(const vec4 _col1, const vec4 _col2, const vec4 _col3, const vec4 _col4);

    mat4& operator=(const mat4 rhs);
    bool operator==(const mat4 rhs);

    mat4 operator+(mat4 rhs) const;
    mat4 operator-(mat4 rhs) const;
    mat4 operator*(mat4 rhs) const;
    mat4 operator/(mat4 rhs) const;

    mat4 operator*(double rhs) const;
    mat4 operator/(double rhs) const;
    vec4 operator*(vec4 rhs) const;

    double& operator()(int I, int J);
    double& operator[](int I);
    const double& operator()(int I, int J) const;
    const double& operator[](int I) const;
    double& at(int I, int J);
    const double& at(int I, int J) const;

    double det();
    mat4 inverse();
    void invert();
    mat4 transpose();
    void dotranspose();
};

//matrix operations
mat4 mat4_eye();
mat4 mat4_zeros();
mat4 mat4_ones();

mat4 mat4_mult(mat4 a, mat4 b);
vec4 mat4_mult(vec4 a, mat4 b);
vec4 mat4_mult(mat4 a, vec4 b);

double mat4_det(mat4 a);
mat4 mat4_inverse(mat4 a);
mat4 mat4_transpose(mat4 a);

}; //end namespace ams

#endif

