#ifndef LINALG_VECTOR_HPP
#define LINALG_VECTOR_HPP

#include "share.hpp"
#include "point.hpp"

namespace visual_engine {
namespace detail {
namespace linalg {

class point;

class vector final {
    coord_t x_, y_, z_;

public:
    vector(coord_t x, coord_t y, coord_t z) : x_(x), y_(y), z_(z) {}
    vector(const point& p);
    // vector(const matrix::matrix_t<float> &mtx);

    void    console_dump() const;
    bool    is_valid()     const;
    coord_t length()       const;
    vector  normalized()   const;
    vector& normalize();

    vector  product     (const vector& vec) const;
    coord_t scal_product(const vector& vec) const;
    bool operator==(const vector& vec) const {
        return equal(vec.x_, x_) &&
               equal(vec.y_, y_) &&
               equal(vec.z_, z_);
    }

    vector operator+(const vector& vec) {
        return {x_ + vec.x_, y_ + vec.y_, z_ + vec.z_};
    }

    vector operator-(const vector& vec) {
        return {x_ - vec.x_, y_ - vec.y_, z_ - vec.z_};
    }

    void rotate(const vector &v);

    coord_t get_x(void) const { return x_; }
    coord_t get_y(void) const { return y_; }
    coord_t get_z(void) const { return z_; }
};

} // namespace linalg
} // namespace detail

using typename detail::linalg::vector;

template<typename T>
vector operator*(const vector& vec, T num) {
    return vector{vec.get_x() * num, vec.get_y() * num, vec.get_z() * num};
}

template<typename T>
vector operator*(T num, const vector& vec) {
    return vector{vec.get_x() * num, vec.get_y() * num, vec.get_z() * num};
}

} // namespace visual_engine

#endif // LINALG_VECTOR_HPP
