#ifndef CORE_MATRIX_H
#define CORE_MATRIX_H

#include "math/Quaternion.h"
#include "utils/ArrayString.h"

namespace Core {
    class Matrix final {
        Vector4 data[4];

    public:
        Matrix();

        Matrix& unit();

        Matrix& set(int index, const Vector4& v);

        Matrix transpose();

        const float* getValues() const;

        Matrix& operator*=(const Matrix& other);
        Matrix operator*(const Matrix& other) const;
        Vector3 operator*(const Vector3& v) const;

        Matrix& scale(const Vector3& v);
        Matrix& scale(float f);

        Matrix& translate(const Vector3& v);
        Matrix& translateX(float tx);
        Matrix& translateY(float ty);
        Matrix& translateZ(float tz);
        Matrix& translateTo(const Vector3& v);

        Matrix& rotateX(float degrees);
        Matrix& rotateY(float degrees);
        Matrix& rotateZ(float degrees);
        Matrix& rotate(const Quaternion& q);

        // returns true on error and calls the error callback
        template<int L>
        check_return bool toString(ArrayString<L>& s) const {
            return s.append('[') || s.append(data[0]) || s.append(", ") ||
                   s.append(data[1]) || s.append(", ") || s.append(data[2]) ||
                   s.append(", ") || s.append(data[3]) || s.append("]");
        }

    private:
        Matrix& rotate(float degrees, int a, int b);
    };
}

#endif