//  complex : headerfile for the free standard C++ library
//  
//  Copyright (C) 1999 by the free standard C++ Library Team
//                        see AUTHORS for more details
//
//  Homepage : http://www.inf.fu-berlin.de/~mkrueger/fscl/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Library General Public
//  License as published by the Free Software Foundation; either	
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Library General Public License for more details.
//  You should have received a copy of the GNU Library General Public
//  License along with this library; if not, write to the Free
//  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//  version : 0.1 last modified : 17.09.99

#ifndef __CPP_COMPLEX
#define __CPP_COMPLEX

#include<cstddef>
#include<new>

#include<istream>
#include<ostream>

namespace std {
	
	// 26.2.2 Template class complex
	template<class T>
	class complex
	{
		public:
			typedef T value_type;

			complex(const T& re = T(), const T& im = T())
			{
				r = re;
				i = im;
			}			

			/* constructor :
			complex(const complex x);
			 unneccessary
			*/

			template<class X>
			complex(const complex<X>& x)
			{
				operator=(x);
			}

			T real() const
			{
				return r;
			}

			T imag() const
			{
				return i;
			}

			complex<T>& operator= (const T& x)
			{
				r = x; 
				i = 0;
				return *this;
			}

			complex<T>& operator+=(const T& x)
			{
				r += x;
				return *this;
			}			
			complex<T>& operator-=(const T& x)
			{
				r -= x;
				return *this;
			}

			complex<T>& operator*=(const T& x)
			{
				r *= x;
				i *= x;
				return *this;
			}
			complex<T>& operator/=(const T& x)
			{
				r /= x;
				i /= x;
				return *this;
			}			

			// I think this = operator is nicer
			template<class X>
			complex<T>& operator= (const complex<X>& x) 
			{
				r = (T)x.r;
				i = (T)x.i;
				return *this;
			}

			template<class X>
			complex<T>& operator+=(const complex<X>& x)
			{
				r += (T)x.r;
				i += (T)x.i;
				return *this;
			}

			template<class X> 
			complex<T>& operator-=(const complex<X>& x)
			{
				r -= (T)x.r;
				i -= (T)x.i;
				return *this;
			}
			
			template<class X>
			complex<T>& operator*=(const complex<X>& x)
			{
				T tmp = r * (T)x.r - i * (T)x.i;
				i = r * (T)x.i + i * (T)x.r;
				r = tmp;
				return *this;
			}

			template<class X> 
			complex<T>& operator/=(const complex<X>& x)
			{
				T nr, ni;
				T t, d;
				if (real() <= imag()) {
					t = (T) x.real() / x.imag();
					d = (T) x.imag() * (1 + t * t);
					nr = (real() * t + imag()) / d;
					ni = (imag() * t - real()) / d;
				} else {
					t = (T) x.imag() / x.real();
					d = (T) x.real() * (1 + t * t);
					nr = (real() + imag() * t) / d;
					ni = (imag() - real() * t) / d;
				}
				r = nr;
				i = ni;
				return *this;
			}

		private:
			T r, i;
	};

	/* !!! I hate specializations !!!
	   with the template constructor these things should be unneccessary, 
	   but mail if I'm wrong. (mkrueger@inf.fu-berlin.de)
	   
	class complex<float>;
	class complex<double>;
	class complex<long double>;
	*/

	// 26.2.6 operators:
	template<class T>
	complex<T> operator+(const complex<T>& x, const complex<T>& y)
	{
		return complex<T>(x) += y;
	}
	template<class T>
	complex<T> operator+(const complex<T>& x, const T& a)
	{
		return complex<T>(x) += a;
	}
	template<class T>
	complex<T> operator+(const T& a, const complex<T>& x)
	{
		return complex<T>(x) += a;
	}

	template<class T>
	complex<T> operator-(const complex<T>& x, const complex<T>& y)
	{
		return complex<T>(x) -= y;
	}
	template<class T>
	complex<T> operator-(const complex<T>& x, const T& a)
	{
		return complex<T>(x) -= a;
	}
	template<class T>
	complex<T> operator-(const T& a, const complex<T>& x)
	{
		return complex<T>(x) -= a;
	}

	template<class T>
	complex<T> operator*(const complex<T>& x, const complex<T>& y)
	{
		return complex<T>(x) *= y;
	}
	template<class T>
	complex<T> operator*(const complex<T>& x, const T& a)
	{
		return complex<T>(x) *= a;
	}
	template<class T>
	complex<T> operator*(const T& a, const complex<T>& x)
	{
		return complex<T>(x) *= a;
	}

	template<class T>
	complex<T> operator/(const complex<T>& x, const complex<T>& y)
	{
		return complex<T>(x) /= y;
	}
	template<class T>
	complex<T> operator/(const complex<T>& x, const T& a)
	{
		return complex<T>(x) /= a;
	}
	template<class T>
	complex<T> operator/(const T& a, const complex<T>& x)
	{
		return complex<T>(x) /= a;
	}

	template<class T>
	complex<T> operator+(const complex<T>&x)
	{
		return complex<T>(x);
	}	
	template<class T>
	complex<T> operator-(const complex<T>& x)
	{
		return complex<T>(-x.real(), -x.imag());
	}
	
	template<class T> 
	bool operator==(const complex<T>& x, const complex<T>& y)
	{
		return x.real() == y.real() && x.imag() == y.imag();
	}
	template<class T> 
	bool operator==(const complex<T>&x, const T& y)
	{
		return x.real() == y && x.imag() == 0;
	}
	template<class T> 
	bool operator==(const T& a, const complex<T>& x)
	{
		return x == a;
	}	

	template<class T> 
	bool operator!=(const complex<T>& x, const complex<T>& y)
	{
		return !(x == y);
	}
	template<class T> 
	bool operator!=(const complex<T>& x, const T& a) 
	{
		return !(x == a);
	}
	template<class T> 
	bool operator!=(const T& a, const complex<T>& x)
	{
		return !(x == a);
	}

	template<class T, class charT, class traits>
	basic_istream<charT, traits>& operator>>(basic_istream<charT, traits>& is, complex<T>& x)
	{ // should read : A, (A), (A, B)
		char ch, ch2;
		T r, i;
		is >> ch;
		if (ch != '(') {
			is.putback(ch);
			is >> r;
			x = r;
		} else {
			is >> r >> ch;
			if (ch == ')') {
				x = r;
				return is;
			}
			is >> i;
			x = complex<T>(r,i);
			is >> ch2;
			if (ch != ',' || ch2 != ')')
				is.setstate(ios_base::failbit);
		}
		return is;
	}

	template<class T, class charT, class traits>
	basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, const complex<T>& x)
	{
		return os << '(' << x.real() << ',' << x.imag() << ')';
	}

	// 26.2.7 values:

	template<class T> 
	T real(const complex<T>& x)
	{
		return x.real();
	}
	template<class T> 
	T imag(const complex<T>& x)
	{
		return x.imag();
	}

	template<class T> 
	T abs(const complex<T>& x)
	{
		return hypot(real(x), imag(x));
	}
	template<class T> 
	T arg(const complex<T>& x)
	{
		return atan2 (imag(x), real(x));
	}
	template<class T> 
	T norm(const complex<T>& x)
	{
		return real(x) * real(x) + imag(x) * imag(x);
	}

	template<class T> 
	complex<T> conj(const complex<T>& x)
	{
		return complex<T> (real(x), -imag (x));
	}
	template<class T> 
	complex<T> polar(const T& a, const T& x)
	{
		return complex<T> (a * cos(x), a * sin(x));
	}

	// 26.2.8 transcendentals:	
	template<class T> 
	complex<T> sin  (const complex<T>& x)
	{
		return complex<T> (sin (real (x)) * cosh (imag (x)), cos (real (x)) * sinh (imag (x)));
	}
	
	template<class T> 
	complex<T> sinh (const complex<T>& x)
	{
		return complex<T> (sinh (real (x)) * cos (imag (x)), cosh (real (x)) * sin (imag (x)));
	}

	template<class T> 
	complex<T> cos  (const complex<T>& x)
	{
		return complex<T>(cos (real (x)) * cosh (imag (x)), - sin (real (x)) * sinh (imag (x)));
	}
	template<class T>
	complex<T> cosh (const complex<T>& x)
	{
		return complex<T>(cosh (real (x)) * cos (imag (x)), sinh (real (x)) * sin (imag (x)));
	}

	template<class T> 
	complex<T> tan  (const complex<T>& x)
	{ // TODO
	}
	template<class T> 
	complex<T> tanh (const complex<T>& x)
	{ // TODO
	}

	template<class T>
	complex<T> exp  (const complex<T>& x)
	{
		return polar (T (exp (real (x))), imag (x));
	}
	template<class T>
	complex<T> log  (const complex<T>& x)
	{
		return complex<T> (log (abs (x)), arg (x));
	}
	template<class T>
	complex<T> log10(const complex<T>& x)
	{ // TODO : TEST CORECTNESS
		return complex<T> (log (abs (x)) / log (10), arg (x));	
	}

	template<class T> 
	complex<T> pow(const complex<T>& x, int n)
	{
		if (n == 0)
			return complex<T> (1.0);
		complex<T> r (1.0);
		complex<T> tmp(x);
		if (n < 0) {
			n = -n;
			tmp = 1 / tmp;
		}
		while (1) {
			if (n & 1)
				r *= tmp;
			if (y >>= 1)
				tmp *= tmp;
			else
				return r;
	    }
	}

	template<class T> 
	complex<T> pow(const complex<T>& x, const T& a)
	{
		return exp (T(a) * log (x));
	}
	template<class T> 
	complex<T> pow(const complex<T>& x, const complex<T>& y)
	{
		T logr = log (abs (x));
		T a = arg (x);
		return polar (T (exp (logr * real (y) - imag (y) * a)),
					  T (imag (y) * logr + real (y) * a));
	}
	template<class T> 
	complex<T> pow(const T& a, const complex<T>& x)
	{
		return exp (x * T (log (a)));
	}

	template<class T> 
	complex<T> sqrt (const complex<T>& x)
	{
		T r = abs (x);
		T nr, ni;
		if (r == 0.0)
			nr = ni = r;
		else if (real (x) > 0) {
				nr = sqrt (0.5 * (r + real (x)));
				ni = imag (x) / nr / 2;
		} else {
			ni = sqrt (0.5 * (r - real (x)));
			if (imag (x) < 0)
				ni = - ni;
			nr = imag (x) / ni / 2;
		}
		return complex<T> (nr, ni); 
	}
}

#endif
