/*
 * Copyright 2015 - 2025 gary@drinkingtea.net
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#pragma once

#include <ox/std/concepts.hpp>
#include <ox/std/error.hpp>

namespace ox {

class Point {
	public:
		static constexpr auto TypeName = "net.drinkingtea.ox.Point";
		static constexpr auto TypeVersion = 1;
		int32_t x = 0;
		int32_t y = 0;

		constexpr Point() noexcept = default;

		constexpr Point(int x, int y) noexcept;

		explicit constexpr Point(class Vec2 const&pt) noexcept;

		constexpr Point operator+(const Point &p) const noexcept;

		constexpr Point operator-(const Point &p) const noexcept;

		constexpr Point operator*(const Point &p) const noexcept;

		constexpr Point operator/(const Point &p) const noexcept;


		constexpr Point operator+=(const Point &p) noexcept;

		constexpr Point operator-=(const Point &p) noexcept;

		constexpr Point operator*=(const Point &p) noexcept;

		constexpr Point operator/=(const Point &p) noexcept;


		constexpr Point operator+(int i) const noexcept;

		constexpr Point operator-(int i) const noexcept;

		constexpr Point operator*(int i) const noexcept;

		constexpr Point operator/(int i) const noexcept;


		constexpr Point operator+=(int i) noexcept;

		constexpr Point operator-=(int i) noexcept;

		constexpr Point operator*=(int i) noexcept;

		constexpr Point operator/=(int i) noexcept;


		constexpr bool operator==(const Point&) const noexcept;

		constexpr bool operator!=(const Point&) const noexcept;

		explicit constexpr operator class Vec2() const noexcept;
};

constexpr Point::Point(int x, int y) noexcept {
	this->x = x;
	this->y = y;
}

constexpr Point Point::operator+(const Point &p) const noexcept {
	auto out = *this;
	out.x += p.x;
	out.y += p.y;
	return out;
}

constexpr Point Point::operator-(const Point &p) const noexcept {
	auto out = *this;
	out.x -= p.x;
	out.y -= p.y;
	return out;
}

constexpr Point Point::operator*(const Point &p) const noexcept {
	auto out = *this;
	out.x *= p.x;
	out.y *= p.y;
	return out;
}

constexpr Point Point::operator/(const Point &p) const noexcept {
	auto out = *this;
	out.x /= p.x;
	out.y /= p.y;
	return out;
}

constexpr Point Point::operator+=(const Point &p) noexcept {
	x += p.x;
	y += p.y;
	return *this;
}

constexpr Point Point::operator-=(const Point &p) noexcept {
	x -= p.x;
	y -= p.y;
	return *this;
}

constexpr Point Point::operator*=(const Point &p) noexcept {
	x *= p.x;
	y *= p.y;
	return *this;
}

constexpr Point Point::operator/=(const Point &p) noexcept {
	x /= p.x;
	y /= p.y;
	return *this;
}


constexpr Point Point::operator+(int i) const noexcept {
	auto out = *this;
	out.x += i;
	out.y += i;
	return out;
}

constexpr Point Point::operator-(int i) const noexcept {
	auto out = *this;
	out.x -= i;
	out.y -= i;
	return out;
}

constexpr Point Point::operator*(int i) const noexcept {
	auto out = *this;
	out.x *= i;
	out.y *= i;
	return out;
}

constexpr Point Point::operator/(int i) const noexcept {
	auto out = *this;
	out.x /= i;
	out.y /= i;
	return out;
}

constexpr Point Point::operator+=(int i) noexcept {
	x += i;
	y += i;
	return *this;
}

constexpr Point Point::operator-=(int i) noexcept {
	x -= i;
	y -= i;
	return *this;
}

constexpr Point Point::operator*=(int i) noexcept {
	x *= i;
	y *= i;
	return *this;
}

constexpr Point Point::operator/=(int i) noexcept {
	x /= i;
	y /= i;
	return *this;
}

constexpr bool Point::operator==(const Point &p) const noexcept {
	return x == p.x && y == p.y;
}

constexpr bool Point::operator!=(const Point &p) const noexcept {
	return x != p.x || y != p.y;
}

template<typename T>
constexpr Error model(T *io, ox::CommonPtrWith<Point> auto *obj) noexcept {
	OX_RETURN_ERROR(io->template setTypeInfo<Point>());
	OX_RETURN_ERROR(io->field("x", &obj->x));
	OX_RETURN_ERROR(io->field("y", &obj->y));
	return {};
}

}
