#include "Point.h"
//#include "Rect.h"

//#include "Common/String/Conversion.h"
//#include "Common/System/Comparison.h"

//#include SFML_HEADER("SFML/System/Vector2.hpp")
//#include QT_HEADER("QtCore/QPoint")

Point::Point(const std::string &str)
{
    this->FromString(str);
}

//Copy constructor.
Point::Point(const Point &point)
{
    *this = point;
}

/*
//Keeps the point within 'rect'.
void Point::KeepWithin(const Rect &rect)
{
    this->x = ::KeepWithin(rect.Left(), this->x, rect.Right());
    this->y = ::KeepWithin(rect.Top(), this->y, rect.Bottom());
}

//Keeps the point outside of 'rect'.
void Point::KeepWithout(const Rect &rect)
{
    this->x = ::KeepWithout(rect.Left(), this->x, rect.Right());
    this->y = ::KeepWithout(rect.Top(), this->y, rect.Bottom());
}

//Snaps the point to the nearest edge of 'rect', regardless of
//whether the point is inside or outside the rectangle.
void Point::SnapToEdge(const Rect &rect)
{
    this->KeepWithin(rect);
    this->KeepWithout(rect);
}

//STATIC:
//Returns 'true' if 'value.x' is greater than 'min.x' and less than 'max.x', and the same for the 'y' member.
bool Point::IsWithin(const Point &min, const Point &value, const Point &max)
{
    return ((min.x <= value.x && value.x < max.x)
         && (min.y <= value.y && value.y < max.y));
}

bool Point::IsWithin(const Point &value, const Point &max)
{
    return Point::IsWithin(Point(0,0), value, max);
}

//STATIC:
//Keeps 'value.x' between 'min.x' and 'max.x', with 'loops.x' being the number of times it had to loop around.
//Does the same with the 'y' member. Negative loops return a negative number.
Point Point::LoopInRange(const Point &min, const Point &value, const Point &max, Point &loops)
{
    //int *loopX = (loops? &loops->x : nullptr);
    //int *loopY = (loops? &loops->y : nullptr);
    
    Point result;
    result.x = ::LoopInRange(min.x, value.x, max.x, &loops.x);
    result.y = ::LoopInRange(min.y, value.y, max.y, &loops.y);
    
    return result;
}

//STATIC:
Point Point::LoopInRange(const Point &value, const Point &max, Point &loops)
{
    return Point::LoopInRange(Point(0,0), value, max, loops);
}*/

bool Point::operator==(const Point &other) const
{
    return (this->x == other.x && this->y == other.y);
}

bool Point::operator!=(const Point &other) const
{
    return !(*this == other);
}

Point &Point::operator=(const Point &other)
{
    if(this == &other) return *this; //Self-assignment protection.

    this->x = other.x;
    this->y = other.y;

    return *this;
}

Point &Point::operator+=(const Point &other)
{
    this->x += other.x;
    this->y += other.y;

    return *this;
}

Point &Point::operator-=(const Point &other)
{
    this->x -= other.x;
    this->y -= other.y;

    return *this;
}

Point &Point::operator*=(const Point &other)
{
    this->x *= other.x;
    this->y *= other.y;

    return *this;
}

Point &Point::operator/=(const Point &other)
{
  this->x /= other.x;
  this->y /= other.y;

  return *this;
}

Point &Point::operator%=(const Point &other)
{
  this->x %= other.x;
  this->y %= other.y;

  return *this;
}

Point Point::operator+(const Point &other) const
{
    Point point(*this);
    point += other;

    return point;
}

Point Point::operator-(const Point &other) const
{
    Point point(*this);
    point -= other;

    return point;
}

Point Point::operator*(const Point &other) const
{
    Point point(*this);
    point *= other;

    return point;
}

Point Point::operator/(const Point &other) const
{
    Point point(*this);
    point /= other;

    return point;
}

Point Point::operator%(const Point &other) const
{
    Point point(*this);
    point %= other;

    return point;
}

//Additive-inverse operator.
Point Point::operator-() const
{
    return Point(-(this->x), -(this->y));
}

/*
//Packs the Point into a Uint32, with 16 bits for x, and 16 for y. Since both x and y can be negative,
//this leaves just 15 bits for the numeral component, meaning (-32768 to 32768) in both x and y.
uint32_t Point::ToUint32() const
{
    uint32_t data = 0;
    data |= (((int16_t)this->x) & 0x0000FFFF);
    data |= (((int16_t)this->x) & 0x0000FFFF) << 15;

    return data;
}

void Point::FromUint32(uint32_t data)
{
    this->x = (int16_t)((data & 0x0000FFFF)      );
    this->y = (int16_t)((data & 0xFFFF0000) >> 15);
}

std::string Point::ToString() const
{
    return PointToString(*this);
}

void Point::FromString(const std::string &str)
{
    *this = StringToPoint(str);
}

SFML_ONLY
(
    sf::Vector2f Point::ToSfmlVector2f() const
    {
        return sf::Vector2f(float(this->x), float(this->y));
    }

    void Point::FromSfmlVector2f(sf::Vector2f vector)
    {
        this->x = value_type(vector.x);
        this->y = value_type(vector.y);
    }
)

QT_ONLY
(
    QPoint Point::ToQPoint() const
    {
        return QPoint(this->x, this->y);
    }

    void Point::FromQPoint(QPoint point)
    {
        this->x = point.x();
        this->y = point.y();
    }
)*/
