package audiovis.dsp;

/**
	Complex number representation.
**/
@:forward(real, imag) @:notNull @:pure
abstract Complex({
	final real:Float;
	final imag:Float;
})
{
	public inline function new(real:Float, imag:Float)
		this = {real: real, imag: imag};

	/**
		Makes a Complex number with the given Float as its real part and a zero imag part.
	**/
	@:from
	public static inline function fromReal(r:Float)
		return new Complex(r, 0);

	/**
		Complex argument, in radians.
	**/
	public var angle(get, never):Float;

	inline function get_angle()
		return Math.atan2(this.imag, this.real);

	/**
		Complex module.
	**/
	public var magnitude(get, never):Float;

	inline function get_magnitude()
		return Math.sqrt(this.real * this.real + this.imag * this.imag);

	@:op(A + B)
	public inline function add(rhs:Complex):Complex
		return new Complex(this.real + rhs.real, this.imag + rhs.imag);

	@:op(A - B)
	public inline function sub(rhs:Complex):Complex
		return new Complex(this.real - rhs.real, this.imag - rhs.imag);

	@:op(A * B)
	public inline function mult(rhs:Complex):Complex
		return new Complex(this.real * rhs.real - this.imag * rhs.imag, this.real * rhs.imag + this.imag * rhs.real);

	/**
		Returns the complex conjugate, does not modify this object.
	**/
	public inline function conj():Complex
		return new Complex(this.real, -this.imag);

	/**
		Multiplication by a real factor, does not modify this object.
	**/
	public inline function scale(k:Float):Complex
		return new Complex(this.real * k, this.imag * k);

	public inline function copy():Complex
		return new Complex(this.real, this.imag);

	/**
		The imaginary unit.
	**/
	public static final im = new Complex(0, 1);

	/**
		The complex zero.
	**/
	public static final zero = new Complex(0, 0);

	/**
		Computes the complex exponential `e^(iw)`.
	**/
	public static inline function exp(w:Float)
		return new Complex(Math.cos(w), Math.sin(w));
}