//
// .SUMMARY:
// Defines the Point class.
//
// .DESCRIPTION
// This class defines a point in a two dimensional space.
//

#pragma once

#include <cstdio>
#include <math.h>
#include <gdefines.h>

class Point
{
    float _x, _y;  // point location

public:
    Point(float v = 0.0, float u = 0.0)
    {
        _x = v;
        _y = u;
    }
    //		Normal constructor.

    Point(double x, double y) :
        _x(static_cast<float>(x)), _y(static_cast<float>(y)) {}
    Point(const Point& p)
    {
        _x = p._x;
        _y = p._y;
    }
    //		Copy initializer.

    ~Point() = default;
    //		Empty destructor.

    void init(float v, float u)
    {
        _x = v;
        _y = u;
    }
    //		Initialize Point class.
    //		Input :
    //			u,v : point coordinates

    short get(FILE* fp);
    //		Read a point from file pointed by fp.
    //		Input :
    //			fp    : file pointer
    //		Return :
    //			TRUE  : success
    //			FALSE : failure

    short put(FILE* fp);
    //		Write a point into file pointed by fp.
    //		Input :
    //			fp    : file pointer
    //		Return :
    //			TRUE  : success
    //			FALSE : failure

    float x() const { return _x; }
    //		Return X coordinate.

    float y() const { return _y; }
    //		Return Y coordinate.

    float X() const { return _x; }
    //
    float Y() const { return _y; }

    void x(float v) { _x = v; }
    //		Set X coordinate.
    //		Input :
    //			v : float value

    void y(float u) { _y = u; }
    //		Set Y coordinate.
    //		Input :
    //			u : float value

    void addX(float v) { _x += v; }
    //		Add a value to the X coordinate.
    //		Input :
    //			v : float value

    void addY(float u) { _y += u; }
    //		Add a value to the Y coordinate.
    //		Input :
    //			u : float value

    Point operator=(Point* p);
    //		Assignment capability for class Point instances.
    //		Input :
    //			p : point pointer

    Point operator=(const Point& p);
    //		Assignment capability for class Point instances.
    //		Input :
    //			p : point

    void operator+=(const Point& p)
    {
        _x += p._x;
        _y += p._y;
    }
    //		Add a value to the point class.
    //		Input :
    //			p : point class (value to be added)

    Point operator+(Point& p)
    {
        return {_x + p._x, _y + p._y};
    }

    Point operator-(Point& p)
    {
        return {_x - p._x, _y - p._y};
    }

    Point pmax(const Point& p) const;
    //		Return a new point that represents the maximum value (X and Y
    //		coordinates) between two points.
    //		Input :
    //			p : point

    Point pmin(const Point& p) const;
    //		Return a new point that represents the minimum value (X and Y
    //		coordinates) between two points.
    //		Input :
    //			p : point

    short operator<=(const Point& p) const { return (_y <= p._y && _x <= p._x); }
    //		Verify if the current point is <= to p.
    //		Input :
    //			p : point
    //		Return :
    //			TRUE  : current point is <= to p
    //			FALSE : current point is not <= p

    short operator<(const Point& p) const { return (_y < p._y && _x < p._x); }
    //		Verify if the current point is < to p.
    //		Input :
    //			p : point
    //		Return :
    //			TRUE  : current point is < to p
    //			FALSE : current point is not < p

    Point radian() { return Point(_x * M_PI / 180., _y * M_PI / 180.); }
    //		Convert to coordinates from degrees to radians

    Point degree() { return Point((_x / M_PI) * 180., (_y / M_PI) * 180.); }
    //		Convert to coordinates from radians to degrees

    void print(char* txt = nullptr)
    {
        printf("%s: %f %f\n", (txt ? txt : "Point"), _x, _y);
    }

    short tooBig()
    {
        return (_x > BIGFLOAT || _x < -BIGFLOAT || _y > BIGFLOAT || _y < -BIGFLOAT);
    }
    //		Verify if current point value is MAXFLOAT.

    int isValidGeo()
    {
        return ((_x >= -180.) && (_x <= 360.) && (_y >= -90.) && (_y <= 90.));
    }
};
