#pragma once

#include "Types.hpp"

namespace TSE
{
    class Vector2;
    class Vector3;
    class Color;
    class Quaternion;

    class Vector4
    {
        public:
        #pragma region members
        float x = 0, y = 0, z = 0, w = 0;
        #pragma endregion members

        #pragma region consts
        static const Vector4 one;
        static const Vector4 zero;
        #pragma endregion consts

        #pragma region ctor
        /// @brief default constructer constructs a Vector4 with (0,0,0,0)
        Vector4();
        /// @brief constructor with custom values
        /// @param _x x component
        /// @param _y y component
        /// @param _z z component
        /// @param _w w component
        Vector4(float _x, float _y, float _z, float _w);
        /// @brief copy constructor
        /// @param other the vector4 to be copied
        Vector4(const Vector4& other);
        /// @brief converter constructer. it converts a Vector2 to a vector4 where z and w gets value 0
        /// @param other the Vector2 to be converted
        Vector4(const Vector2& other);
        /// @brief converter constructer. it converts a Vector3 to a vector4 where w gets value 0
        /// @param other the Vector3 to be converted
        Vector4(const Vector3& other);
        /// @brief converter constructer. it converts a Color to a vector4
        /// @param other the Color to be converted
        Vector4(const Color& other);
        /// @brief converter constructer. it converts a Quaternion to a vector4
        /// @param other the Quaternion to be converted
        Vector4(const Quaternion& other);
        #pragma endregion ctor

        #pragma region methods
        /// @brief checks if the individual components have valid values aka are not nan
        /// @return are the values valid
        bool IsValid() const;
        /// @brief gives you the vector4 as a string representation. mostly for debugging
        /// @return the vector4 in a format like (x|y|z|w)
        string ToString() const;
        /// @brief creates a Vector2 with the same values as the Vector4, the w and y component gets disregarded
        /// @return the Vector4 as a Vector2
        Vector2 ToVector2() const;
        /// @brief creates a Vector3 with the same values as the Vector4, the w component gets disregarded
        /// @return the Vector4 as a Vector3
        Vector3 ToVector3() const;
        /// @brief creates a Color with the same values as the Vector4
        /// @return the Vector4 as a Color
        Color ToColor() const;
        /// @brief creates a Quaternion with the same values as the Vector4
        /// @return the Vector4 as a Quaternion
        Quaternion ToQuaternion() const;

        #pragma region operators
        Vector4 operator+(const Vector4& other) const;
        Vector4 operator+=(const Vector4& other);
        Vector4 operator-(const Vector4& other) const;
        Vector4 operator-=(const Vector4& other);
        Vector4 operator*(const Vector4& other) const;
        Vector4 operator*=(const Vector4& other);
        Vector4 operator/(const Vector4& other) const;
        Vector4 operator/=(const Vector4& other);
        Vector4 operator*(const float other) const;
        Vector4 operator*=(const float other);
        Vector4 operator/(const float other) const;
        Vector4 operator/=(const float other);
        bool operator==(const Vector4& other) const;
        bool operator!=(const Vector4& other) const;
        #pragma endregion operators
        #pragma endregion methods
    };
} // namespace TSE
