#pragma once
#include "Core/EnginePtr.h"

namespace storm {
	class Str;
	class StrBuf;
	namespace geometry {
		STORM_PKG(core.geometry);

		class Vector;
		class Point;

		/**
		 * A homogenous (projective) coordinate in 3D-space.
		 */
		class Vector4 {
			STORM_VALUE;
		public:
			// Zero.
			STORM_CTOR Vector4();

			// Initialize.
			STORM_CTOR Vector4(Float x, Float y, Float z);
			STORM_CTOR Vector4(Float x, Float y, Float z, Float w);
			STORM_CAST_CTOR Vector4(const Point &p);
			STORM_CAST_CTOR Vector4(const Vector &v);

			// Coordinates.
			Float x;
			Float y;
			Float z;
			Float w;

			// Compute the length squared of the vector. Cheaper to compute than the length.
			Float STORM_PURE_FN lengthSq() const;

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

			// Compute the taxicab/manhattan length (i.e. x + y + z).
			Float STORM_PURE_FN taxiLength() const;

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

		wostream &operator <<(wostream &to, const Vector &s);


		inline Bool STORM_PURE_FN operator ==(Vector4 a, Vector4 b) {
			return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w;
		}
		inline Bool STORM_PURE_FN operator !=(Vector4 a, Vector4 b) {
			return !(a == b);
		}


		// TODO: What operators make sense to have for projective coordinates?
	}
}
