#ifndef BOX_HPP_INCLUDED
#define BOX_HPP_INCLUDED

#include <iostream>
#include <cstdint>
#include "Point.hpp"

class Point;

/** @addtogroup Types
* @{ */
class Box
{
    public:
        /**
		* @brief The X of where the Box starts
		* @par Description
		* The X of where the Box starts
		*/
        std::int32_t X;
        /**
		* @brief The Y of where the Box starts
		* @par Description
		* The Y of where the Box starts
		*/
        std::int32_t Y;
        /**
		* @brief The Width of the Box
		* @par Description
		* The Width of the Box
		*/
        std::int32_t Width;
        /**
		* @brief The Height of the Box
		* @par Description
		* The Height of the Box
		*/
        std::int32_t Height;

        /**
        * @brief Default Constructor, constructs a Box with -1 as the X, Y, Width, and Height
        * @par Description
        *   Default Constructor, constructs a Box with -1 as the X, Y, Width, and Height
        */
        Box();
        /**
        * @brief Constructs a Box based on X, Y, Width, and Height
		* @param std::int32_t X The X of where the Box begins
		* @param std::int32_t Y The Y of where the Box begins
		* @param std::int32_t Width The Width of the Box to be constructed
		* @param std::int32_t Height The Height of the Box to be constructed
		*/
        Box(std::int32_t X, std::int32_t Y, std::int32_t Width, std::int32_t Height);
        /**
        * @brief Constructs a Box, by copying another
		* @param const Box& B The Box to "copy"
		*/
        Box(const Box& B);

        /**
        * @brief Returns a random Point using Uniform Distribution
        * @return A random Point using Uniform Distribution
        * @see @ref UniformRandomDocs
        * @see @ref MissChanceFollowupDocs
        */
        Point GetUniformRandomPoint() const;
        /**
        * @brief Returns a random Point using Binomial Distribution
        * @return A random Point using Binomial Distribution
        * @see @ref BinomialRandomDocs
        * @see @ref MissChanceFollowupDocs
        */
        Point GetBinomialRandomPoint(double ProbabilityX, double ProbabilityY) const;
        /**
        * @brief Returns a random Point using Normal Distribution
        * @return A random Point using Normal Distribution
        * @see @ref NormalRandomDocs
        * @see @ref MissChanceFollowupDocs
        */
        Point GetNormalRandomPoint(double PercentageDeviationX, double PercentageDeviationY) const;

        Point GetHybridRandomPoint(double ProbabilityX, double ProbabilityY, double StandardDeviationX, double StandardDeviationY, double PointGenAccuracy) const;
        Point GetProfileHybridRandomPoint() const;
        Point GetProfileHybridRandomPoint(double PointGenAccuracy) const;

        /**
		* @brief Returns True if the Box contains a Point
		* @return True if the Box contains a Point
		* @par Example
		* @code
		*   Box B(25, 25, 100, 100);
		*   Debug::Info << B.contains(Point(30, 30));
		* @endcode
		*/
        bool Contains(Point P) const;
        /**
		* @brief Returns True if the Box contains both X, and Y
		* @return True if the Box contains both X, and Y
		* @par Example
		* @code
		*   Box B(25, 25, 100, 100);
		*   Debug::Info << B.contains(30, 30);
		* @endcode
		*/
        bool Contains(std::int32_t X, std::int32_t Y) const;
        /**
		* @brief Returns True if the Box contains another Box
		* @return True if the Box contains another Box
		* @par Example
		* @code
		*   Box A(25, 25, 100, 100);
		*   Box B(30, 30, 10, 10);
		*   Debug::Info << A.contains(B);
		* @endcode
		*/
        bool Contains(Box Box) const;
        /**
		* @brief Returns the X2 of the Box
		* @return The X2 of the Box
		* @par Example
		* @code
		*   Box B(25, 25, 100, 100);
		*   Debug::Info << B.GetX2() << ", " << B.GetY2();
		* @endcode
		*/
        std::int32_t GetX2() const;
        /**
		* @brief Returns the Y2 of the Box
		* @return The Y2 of the Box
		* @par Example
		* @code
		*   Box B(25, 25, 100, 100);
		*   Debug::Info << B.GetX2() << ", " << B.GetY2();
		* @endcode
		*/
        std::int32_t GetY2() const;
        /**
		* @brief Returns True if the Box is within the bounds of Client Canvas
		* @return True if the Box is within the bounds of Client Canvas
		*/
        bool OnScreen() const;
        /**
		* @brief Returns True if the Box's X, Y, Width, and Height are greater than greater than or equal to 0
		* @return True if the Box's X, Y, Width, and Height are greater than or equal to 0
		*/
        bool IsValid() const;
        bool operator==(const Box& B) const;
        bool operator!=(const Box& B) const;
        friend std::ostream& operator<<(std::ostream& OS, const Box& B);
        operator bool() const;
        ~Box();
};

/** @} */

#endif // BOX_HPP_INCLUDED
