#pragma once
#include "Angle.h"
#include "Vector.h"
#include "Point.h"

namespace storm {
	namespace geometry {
		STORM_PKG(core.geometry);

		class Transform;

		/**
		 * A rotation in 2 or 3 dimensions.
		 *
		 * Represented as a quaternion. The Transform class generalizes the transformation into a
		 * general matrix. Note that this representation aims to be easy to understand from a 3D
		 * perspective. As such, the `w` component is actually the real part of the quaternion. This
		 * is since it makes `x`, `y`, and `z` represent the rotation director, and `w` the angle.
		 */
		class Rotation {
			STORM_VALUE;
		public:
			// Default initialization, to no rotation at all.
			STORM_CTOR Rotation() : x(0.0f), y(0.0f), z(0.0f), w(1.0f) {}

			// Initialize to particular values.
			STORM_CTOR Rotation(Float x, Float y, Float z, Float w) : x(x), y(y), z(z), w(w) {}

			// Create a particular rotation around an axis.
			STORM_CTOR Rotation(Vector axis, Angle angle);

			// Individual components.
			Float x;
			Float y;
			Float z;
			Float w;

			// Squared length of the quaternion.
			Float STORM_PURE_FN lengthSq() const;

			// Compute the length of the quaternion.
			Float STORM_PURE_FN length() const;

			// Normalize the quaternion.
			Rotation STORM_PURE_FN normalized() const;

			// Compute the axis from the component. Note: if the rotation is zero, returns the
			// vector (0, 0, 0). Also, loss in precision might occur.
			Vector STORM_PURE_FN axis() const;

			// Compute the rotation angle.
			Angle STORM_PURE_FN angle() const;

			// Output.
			void STORM_FN toS(StrBuf *to) const;
		};

		// Operations.
		Rotation STORM_PURE_FN operator +(Rotation a, Rotation b);
		Rotation STORM_PURE_FN operator *(Rotation a, Float b);
		Rotation STORM_PURE_FN operator /(Rotation a, Float b);
		Rotation STORM_PURE_FN operator *(Rotation a, Rotation b);
		Rotation &STORM_FN operator +=(Rotation &a, Rotation b);
		Rotation &STORM_FN operator *=(Rotation &a, Float b);
		Rotation &STORM_FN operator /=(Rotation &a, Float b);

		// Transform points and vectors.
		Vector STORM_PURE_FN operator *(Vector o, Rotation r);
		Point STORM_PURE_FN operator *(Point o, Rotation r);

	}
}
