#pragma once
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Weverything"
#include <boost/serialization/serialization.hpp>
#pragma clang diagnostic pop
#include <cmath>

struct Vec3 {
	double X{0};
	double Y{0};
	double Z{0};

	Vec3& operator+=(const Vec3& v) {
		X += v.X;
		Y += v.Y;
		Z += v.Z;
		return *this;
	}

	Vec3& operator-=(const Vec3& v) {
		X -= v.X;
		Y -= v.Y;
		Z -= v.Z;
		return *this;
	}

	Vec3& operator*=(double d) {
		X *= d;
		Y *= d;
		Z *= d;
		return *this;
	}

	Vec3& operator*=(const Vec3& v) {
		X *= v.X;
		Y *= v.Y;
		Z *= v.Z;
		return *this;
	}

	Vec3& operator/=(double d) {
		X /= d;
		Y /= d;
		Z /= d;
		return *this;
	}

	template <class Archive> void serialize(Archive& ar, const unsigned int version) {
		(void)version;
		ar& X;
		ar& Y;
		ar& Z;
	}

  private:
	friend class boost::serialization::access;
};
BOOST_IS_MPI_DATATYPE(Vec3) // performance hint allowed for contiguous data

Vec3 operator-(Vec3 v1, const Vec3& v2) {
	v1 -= v2;
	return v1;
}

Vec3 operator+(Vec3 v1, const Vec3& v2) {
	v1 += v2;
	return v1;
}

Vec3 operator*(Vec3 v1, const Vec3& v2) {
	v1 *= v2;
	return v1;
}

Vec3 operator*(Vec3 v, double d) {
	v *= d;
	return v;
}

Vec3 operator/(Vec3 v, double d) {
	v /= d;
	return v;
}

inline double Norm(const Vec3& v) { return std::sqrt(v.X * v.X + v.Y * v.Y + v.Z * v.Z); }

inline double Distance(const Vec3& v1, const Vec3& v2) { return Norm(v1 - v2); }
