#ifndef _COMPLEX_H
#define _COMPLEX_H

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <math.h>

#if HAVE_LIBFFTW
  #include <fftw.h>
  typedef fftw_complex complex;
#else
  typedef struct {
  	double re, im;
  } complex;
#endif

/*
 * Complex multiplication.
 */
extern __inline__ complex cmul(complex x, complex y)
{
	complex z;

	z.re = x.re * y.re - x.im * y.im;
	z.im = x.re * y.im + x.im * y.re;

	return z;
}

/*
 * Complex addition.
 */
extern __inline__ complex cadd(complex x, complex y)
{
	complex z;

	z.re = x.re + y.re;
	z.im = x.im + y.im;

	return z;
}

/*
 * Complex subtraction.
 */
extern __inline__ complex csub(complex x, complex y)
{
	complex z;

	z.re = x.re - y.re;
	z.im = x.im - y.im;

	return z;
}

/*
 * Complex multiply-and-add.
 */
extern __inline__ complex cmac(complex *a, complex *b, int len)
{
	complex sum = cmul(a[0], b[0]);
	int i;

	for (i = 1; i < len; i++)
		sum = cadd(sum, cmul(a[i], b[i]));

	return sum;
}

/*
 * Complex ... yeah, what??? Returns a complex number that has the
 * properties: |z| = |x| * |y|  and  arg(z) = arg(y) - arg(x)
 */
extern __inline__ complex ccor(complex x, complex y)
{
	complex z;

	z.re = x.re * y.re + x.im * y.im;
	z.im = x.re * y.im - x.im * y.re;

	return z;
}

/*
 * Real part of the complex ???
 */
extern __inline__ double ccorI(complex x, complex y)
{
	return x.re * y.re + x.im * y.im;
}

/*
 * Imaginary part of the complex ???
 */
extern __inline__ double ccorQ(complex x, complex y)
{
	return x.re * y.im - x.im * y.re;
}

/*
 * Modulo (absolute value) of a complex number.
 */
extern __inline__ double cmod(complex x)
{
	return sqrt(x.re * x.re + x.im * x.im);
}

/*
 * Square of the absolute value (power).
 */
extern __inline__ double cpwr(complex x)
{
	return (x.re * x.re + x.im * x.im);
}

/*
 * Argument of a complex number.
 */
extern __inline__ double carg(complex x)
{
	return atan2(x.im, x.re);
}

/*
 * Complex square root.
 */
extern __inline__ complex csqrt(complex x)
{
	complex z;

	z.re = sqrt(cmod(x) + x.re) / M_SQRT2;
	z.im = x.im / z.re / 2;

	return z;
}

#endif
