/***************************************************************************
                           complex.h  -  description
                             -------------------
    begin                : lun feb 24 2003
    copyright            : (C) 2003 by  Armando Navarro-Vazquez
    email                : qoajnv@usc.es
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
#if !defined COMPLEX_H
#define COMPLEX_H

template <class T> class Complex {

  public:

  Complex() {re=0.0f; im=0.0f;}
  Complex(T r) {re=r; im=0.0f;}
  Complex(T r,T i) {re=r; im=i;}
  template <class X>
  Complex(const Complex<X>& b) { re=b.re; im=b.im; }
  //Complex(const U& a) {re=a; im=a; }
  T re; T im;
  //operadores suma monarios
  template <class X> Complex& operator+=(const X&a)
  {
    re+=a;
    return *this;
  }

  template<class X> Complex& operator+=(const Complex<X>& a)
  {
    re+=a.re;
    im+=a.im;
    return *this;
  }
  
   /* Complex& operator+=(Complex& a)
    {
      re+=a.re;
      im+=a.im;
      return *this;
    } */

  template <class X> Complex operator+(const X& a)
  {
    Complex c(a);
    c+=(*this);
    return c;
  }
    

    //operadores resta monarios
  template <class X> Complex& operator-=(const X&a)
  {
    re-=a;
    return *this;
  }

  template<class X> Complex& operator-=(const Complex<X>& a)
  {
    re-=a.re;
    im-=a.im;
    return *this;
  }

  Complex& operator-=(const Complex& a)
  {
    re-=a.re;
    im-=a.im;
    return *this;
  }

  template <class X> Complex operator-(const X& a)
  {
    Complex c(*this);
    c-=a;
    return c;
  }

  //operadores producto monarios
  template <class X>  Complex& operator*=(const X &a)
  {
    re*=a;
    im*=a;
    return *this;
  }
    

  template <class X>  Complex& operator*=(const Complex<X>& a)
  {
    Complex c(*this);
    re=c.re*a.re-c.im*a.im;
    im=c.re*a.im + c.im*a.re;
    return *this;
  }

  template <class X> Complex operator*(const X& a)
  {
    Complex c(a);
    c*=(*this);
    return c;
  }

    //operadores division monarios
  template <class X>  Complex& operator/=(const X& a)
  {
    re/=a;
    im/=a;
    return *this;
  }

   //do division as recomended by numerical recipes
  Complex& operator/=(const Complex& b)
  {
    Complex a(*this);
    T r,den;
    if (fabs(b.re) >= fabs(b.im))
    {
      r=b.im/b.re;
      den=b.re+r*b.im;
      re=(a.re+r*a.im)/den;
      im=(a.im-r*a.re)/den;
    }
    else
    {
      r=b.re/b.im;
      den=b.im+r*b.re;
      re=(a.re*r+a.im)/den;
      im=(a.im*r-a.re)/den;
    }
    return *this;
  }

  template <class X> Complex operator/(const X& a)
  {
    Complex c(a);
    c/=(*this);
    return c;
  }

  void power() { re=sqrt((re*re)+(im*im)); im=0.0f;}
  void magnitude() {re=re*re+im*im; im=0.0f; }
  
  T norm() { return sqrt( (re*re) + (im*im) ); }


};

  //operadores suma binarios
/*template<class T> inline Complex<T> operator + (const  Complex<T>& a, const Complex<T>& b)
  {
    Complex<T> c;
    c.re=a.re+b.re;
    c.im=a.im+b.im;
    return c;
  }    */

template<class X, class T>  inline Complex<T>operator +(const X& a, const Complex<T>& b)
{
  Complex<T> c;
  c.re=a+b.re;
  c.im=b.im;
  return c;
}  

/*template <class T, class X>  inline Complex<T> operator +(const Complex<T>& a, const X& b)
  {
    Complex<T> c;
    c.re=a.re+b;
    c.im=a.im;
    return c;

    }    */
      //operadores resta binarios
/*template <class T> inline Complex <T> operator - (const Complex<T>&a, const Complex<T>& b)
  {
    Complex<T> c;
    c.re=a.re-b.re;
    c.im=a.im-b.im;
    return c;
  }  */

template <class X,class T> inline Complex <T> operator -(const X& a, const Complex<T>& b)
{
  Complex<T> c;
  c.re=a-b.re;
  c.im=b.im;
  return c;
}  

/*template <class T, class X> inline Complex <T>  operator -(const Complex<T>& a, const X& b)
  {
    Complex<T> c;
    c.re=a.re-b;
    c.im=a.im;
    return c;

}  */     

//operadores producto binarios


/*template <class T> Complex<T> inline operator * (const Complex<T>& a, const Complex<T>& b)
{
  Complex<T> c;
  c.re=a.re*b.re-a.im*b.im;
  c.im=a.im*b.re+a.re*b.im;
  return c;
}  */
//If we define the following two templates both gcc3.2.2 and icc compilers are not able to resolve the
//ambiguity, since there is a Complex(T r) constructor the previous template should be enough

template <class X, class T> inline Complex<T> operator * (const X& a, const Complex<T>& b)
{
  Complex<T> c(b);
  c*=a;
  return c;
}   

/*template <class T, class X> inline Complex<T> operator * (const Complex<T>& a, const X& b)
{
  return b*a;
} */   

//operadores division binarios
/*template <class T> inline Complex<T> operator / (Complex<T> a, const Complex<T>& b)
{
  a/=b;

  return a;
} */  

template <class X, class T> inline Complex<T> operator / (const X& a, const Complex<T>& b)
{
  Complex<T> c(a,0.0);

  return c/=b;
}   

/*template <class T, class X> inline Complex<T> operator / (const Complex<T>& a, const X& b)
{
  Complex<T> c(a);
  return c/=b;
}   */

template <class T> inline Complex<T> expi(const T& a)
{
  return Complex<T>(cos(a),sin(a));
}
//special functions


template <class T>  inline T magnitude(Complex<T> a)
{

  return T(a.re*a.re + a.im*a.im);
}




template <class T> inline T power(const Complex<T>& a)
{
  return T(sqrt(a.re*a.re+a.im*a.im));
}


typedef Complex<float> fcomplex;
#endif



