#ifndef __AMSMATHUTIL25_VEC4F_HPP__
#define __AMSMATHUTIL25_VEC4F_HPP__

namespace ams
{

class vec4f; 
class mat4f;

class vec4f
{
public:
    float x;
    float y;
    float z;
    float w;

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

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

//vector operations
float vec4f_dot(vec4f v1, vec4f v2);
float vec4f_norm(vec4f v);
vec4f vec4f_normalize(vec4f v);
float vec4f_dist(vec4f v1, vec4f v2);
vec4f vec4f_proj(vec4f v1, vec4f v2);

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

class mat4f
{
public:
    float data[16];

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

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

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

    mat4f operator*(float rhs) const;
    mat4f operator/(float rhs) const;
    vec4f operator*(vec4f rhs) const;

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

    float det();
    mat4f inverse();
    void invert();
    mat4f transpose();
    void dotranspose();
};

//matrix operations
mat4f mat4f_eye();
mat4f mat4f_zeros();
mat4f mat4f_ones();

mat4f mat4f_mult(mat4f a, mat4f b);
vec4f mat4f_mult(vec4f a, mat4f b);
vec4f mat4f_mult(mat4f a, vec4f b);

float mat4f_det(mat4f a);
mat4f mat4f_inverse(mat4f a);
mat4f mat4f_transpose(mat4f a);

}; //end namespace ams

#endif

