#pragma once

class TBall;
class TFlipperEdge;

struct vector2
{
	float X;
	float Y;

	bool operator==(const vector2& vec)
	{
		return X == vec.X && Y == vec.Y;
	}
	bool operator!=(const vector2& vec)
	{
		return X != vec.X || Y != vec.Y;
	}
};

struct vector3 :vector2
{	
	vector3() = default;
	vector3(float x, float y) : vector3{ x, y, 0 } {}
	vector3(float x, float y, float z) : vector2{ x, y }, Z(z) {}
	float Z;
};

struct vector2i
{
	int X;
	int Y;
};

struct rectangle_type
{
	int XPosition;
	int YPosition;
	int Width;
	int Height;
};

struct circle_type
{
	vector2 Center;
	float RadiusSq;
};

struct ray_type
{
	vector2 Origin;
	vector2 Direction;
	float MaxDistance;
	float MinDistance;
	int CollisionMask;
};

struct line_type
{
	vector2 PerpendicularC;
	vector2 Direction;
	vector2 Origin;
	vector2 End;
	float MinCoord;
	float MaxCoord;
	vector2 RayIntersect;
};

struct wall_point_type
{
	vector2 Pt0;
	vector2 Pt1;
};

struct ramp_plane_type
{
	vector3 BallCollisionOffset;
	vector2 V1;
	vector2 V2;
	vector2 V3;
	float GravityAngle1;
	float GravityAngle2;
	vector2 FieldForce;
};

struct RectF
{
	float XMax, YMax, XMin, YMin;

	void Merge(RectF aabb);
};

enum class FlipperIntersect
{
	none = -1,
	lineA = 0,
	lineB = 1,
	circlebase = 2,
	circleT1 = 3
};


class maths
{
public:
	static void enclosing_box(const rectangle_type& rect1, const rectangle_type& rect2, rectangle_type& dstRect);
	static bool rectangle_clip(const rectangle_type& rect1, const rectangle_type& rect2, rectangle_type* dstRect);
	static float ray_intersect_circle(const ray_type& ray, const circle_type& circle);
	static float normalize_2d(vector2& vec);
	static void line_init(line_type& line, float x0, float y0, float x1, float y1);
	static float ray_intersect_line(const ray_type& ray, line_type& line);
	static void cross(const vector3& vec1, const vector3& vec2, vector3& dstVec);
	static float cross(const vector2& vec1, const vector2& vec2);
	static float magnitude(const vector3& vec);
	static float magnitudeSq(const vector2& vec);
	static int magnitudeSq(const vector2i& vec);
	static void vector_add(vector2& vec1Dst, const vector2& vec2);
	static vector2 vector_sub(const vector2& vec1, const vector2& vec2);
	static vector3 vector_sub(const vector3& vec1, const vector3& vec2);
	static vector2 vector_mul(const vector2& vec1, float val);
	static float basic_collision(TBall* ball, vector2* nextPosition, vector2* direction, float elasticity,
	                             float smoothness,
	                             float threshold, float boost);
	static float Distance_Squared(const vector2& vec1, const vector2& vec2);
	static float DotProduct(const vector2& vec1, const vector2& vec2);
	static float Distance(const vector2& vec1, const vector2& vec2);
	static void SinCos(float angle, float& sinOut, float& cosOut);
	static void RotatePt(vector2& point, float sin, float cos, const vector2& origin);
	static float distance_to_flipper(TFlipperEdge* flipper, const ray_type& ray1, ray_type& ray2);
	static void RotateVector(vector2& vec, float angle);
	static void find_closest_edge(ramp_plane_type* plane, int planeCount, wall_point_type* wall, vector2& lineEnd,
	                              vector2& lineStart);
};
