
#ifndef _COMPLEX_H
#define _COMPLEX_H


/** >Composite Data Types
		The Origin C complex class implements a complex number data type containing both a Real and
		an Imaginary component.
	Example:
		complex cc(4.5, 7.8);
		out_double("Real part = ", cc.m_re);
		out_double("Imaginary part = ", cc.m_im);
		cc  = cc.Conjugate();
		out_double("Real part = ", cc.m_re);
		out_double("Imaginary part = ", cc.m_im);
*/ 
class complex
{
public:

	/**	
		default constructor which constructs a complex value with both the real and the imaginary
		part being zero.
	Parameters:
		None
	Example:
		void	run_complex()
		{
			complex		c;
			
			// Display the value:
			out_complex("value = ", c);
		}
	*/
	complex();
	
	/**	
		constructor which constructs a complex value with from the real argument such that
		the real part becomes the value of the argument and the imaginary part is zero.
	Parameters:
		dReal = the real part
	Example:
		void	run_complex()
		{
			complex		c(7.89);
			
			// Display the value:
			out_complex("value = ", c);
		}
	*/
	complex(double dReal);
	
	
	/**	
		constructor which constructs a complex value from the real and imaginary values.
	Parameters:
		dReal = the real part
		dImaginary = the imaginary part
	Example:
		void	run_complex()
		{
			complex		c(3.45, 6.78);
			
			// Display the value:
			out_complex("value = ", c);
		}
	*/
	complex(double dReal, double dImaginary);
	
	
	/**	
		constructor which constructs a complex value from another complex value.
	Parameters:
		cc = the source comples value
	Example:
		void	run_complex()
		{
			complex		cc(1.2, 3.4);
			complex		c(cc);
			
			// Display the value:
			out_complex("value = ", c);
		}
	*/
	complex(complex cc);

	/**	
		it returns the complex conjugate of the value
	Parameters:
		None.
	Return:
		The complex conjugate
	Example:
		void	run_complex_Conjugate()
		{
			complex		cc(1.2, 3.4);
			complex		cconj = cc.Conjugate();
			
			// Display the values:
			out_complex("original value = ", cc);
			out_complex("conjugate value = ", cconj);
		}
	*/
	complex Conjugate();
	
	/**
		returns the phase in radians, of the complex value.
	Parameters:
		None.
	Return:
		The phase
	Example:
		void	run_complex_GetPhase()
		{
			complex		cc(1., -1.);
			
			// Display the phase:
			out_double("phase = ", cc.GetPhase());	// shoulde be -0.7854 (=-PI/4)
		}
	*/
	double GetPhase();
	
	/**
		returns the amplitude(modulus) of the complex value.
	Parameters:
		None.
	Return:
		The amplitude
	Example:
		void	run_complex_GetAmplitude()
		{
			complex		cc(1., -1.);
			
			// Display the amplitude:
			out_double("amplitude = ", cc.GetAmplitude());	// shoulde be 1.4142 (=sqrt(2))
		}
	*/
	double GetAmplitude();
	
	/**
		the property representing the real part of the complex value.
	Example:
		void	run_complex_real_part()
		{
			complex		cc(4.5, 7.8);
			
			out_double("real part = ", cc.m_re);
		}
	*/
	double m_re;
	
	/**
		the property representing the imaginary part of the complex value.
	Example:
		void	run_complex_imaginary_part()
		{
			complex		cc(4.5, 7.8);
			
			out_double("imaginary part = ", cc.m_im);
		}

	*/
	double m_im;
};



/** >Complex Numbers
		returns the real part of the complex value.
	Parameters:
		cc = the complex value.
	Return:
		the real part
	Example:
		void	run_complex_Re()
		{
			complex		cc(4.5, 7.8);
			
			// Display the real part:
			out_double("real part = ", Re(cc));
		}
*/
//double Re(complex cc);
// better implement as macros so that can do Re(aa) = 1;
#define Re(_CC)	(_CC.m_re)

/** >Complex Numbers
		returns the imaginary part of the complex value.
	Parameters:
		cc = the complex value.
	Return:
		the imaginary part
	Example:
		void	run_complex_Im()
		{
			complex		cc(4.5, 7.8);
			
			// Display the imaginary part:
			out_double("imaginary part = ", Im(cc));
		}
*/
//double Im(complex cc);
// better implement as macros so that can do Im(aa) = 1;
#define Im(_CC)	(_CC.m_im)

/** >Complex Numbers
		it returns the complex conjugate of the value
	Parameters:
		cc = the complex value whose conjugate is sought.
	Return:
		The complex conjugate
	Example:
		void	run_complex_Conj()
		{
			complex		cc(1.2, 3.4);
			complex		cconj = Conj(cc);
			
			// Display the values:
			out_complex("original value = ", cc);
			out_complex("conjugate value = ", cconj);
		}
*/
complex Conj(complex cc);

/** >Character/String Manipulation
	Parameters:
		lpcsz = the string containing a complex data.
	Return:
		Returns complex data from a string
	Example:
		void 	run_complex_atoc()
		{
			complex 	cc;
			string 		str = "  2 + 1.35i";
			
			cc = atoc(str);	
			
			// Display the value:
			out_complex("value = ",cc);		
		}		
	
*/
complex atoc(LPCSTR lpcsz);

#pragma dll(ONAG)

/** >Complex Numbers
		it returns the complex square root of the complex value
	Parameters:
		z = the complex value whose square root is sought.
	Return:
		The square root
	Example:
		void	run_complex_sqrt()
		{
			complex		cc(0., 8.);
			
			out_complex("sqrt = ", sqrt(cc));
		}
*/
complex sqrt(complex z);

/** >Complex Numbers
		it returns the complex sine of the complex value
	Parameters:
		z = the complex value whose sine is sought.
	Return:
		The sine
	Example:
		void	run_complex_sin()
		{
			complex		cc(0.5, 0.8);
			
			out_complex("sin = ", sin(cc));
		}
*/
complex sin(complex z);

/** >Complex Numbers
		it returns the complex cosine of the complex value
	Parameters:
		z = the complex value whose cosine is sought.
	Return:
		The cosine
	Example:
		void	run_complex_cos()
		{
			complex		cc(0.5, 0.8);
			
			out_complex("cos = ", cos(cc));
		}
*/
complex cos(complex z);

/** >Complex Numbers
		it returns the complex tangent of the complex value
	Parameters:
		z = the complex value whose tangent is sought.
	Return:
		The tangent
	Example:
		void	run_complex_tan()
		{
			complex		cc(0.5, 0.8);
			
			out_complex("tan = ", tan(cc));
		}
*/
complex tan(complex z);

/** >Complex Numbers
		returns the amplitude (modulus) of the complex value.
	Parameters:
		z = the complex value whose amplitude is sought.
	Return:
		The amplitude
	Example:
		void	run_complex_cabs()
		{
			complex		cc(1., -1.);
			
			// Display the amplitude:
			out_double("amplitude = ", cabs(cc));	// shoulde be 1.4142 (=sqrt(2))
		}
*/
double cabs(complex z);

/** >Complex Numbers
		returns the logarithm of the complex value.
	Parameters:
		z = the complex value whose logarithm is sought.
	Return:
		The logarithm
	Example:
		void	run_complex_log()
		{
			complex		cc(100., 3.);
			
			// Display the log:
			out_complex("log = ", log(cc));
		}
*/
complex log(complex z);

/** >Complex Numbers
		returns the exponent exp(z) of the complex value.
	Parameters:
		z = the complex value whose exponent is sought.
	Return:
		exp(z)
	Example:
		void	run_complex_exp()
		{
			complex		cc(0.5., 0.3.);
			
			out_complex("exp = ", exp(cc));
		}
*/
complex exp(complex z);

/** >Complex Numbers
		returns the power of the complex value such that the power
		is an integer
	Parameters:
		z = the complex value whose power is sought.
		n = the power
	Return:
		z^n
	Example:
		void	run_complex_ipow()
		{
			complex			cc(sqrt(3.), 1.);	// the complex number whose real part
												// is the square root of 3, and imaginary part is 1.
												// so that its phase is 30 degrees and amplitude is 2.
			int				n = 3;
			
			complex			cresult = ipow(cc, n);
			
			out_complex("Input = ", cc);
			out_int("power = ", n);
			out_complex("ipow = ", cresult);	// the result should be such that its amplitude is 8 (which
												// is 2 to the power 3) and whose phase is 90 degrees (which
												// is 30 degrees times 3).
		}
*/
complex ipow(complex z, int n);

/** >Complex Numbers
		returns the power of the complex value such that the power
		is a double value
	Parameters:
		z = the complex value whose power is sought.
		x = the power
	Return:
		z^x
	Example:
		void	run_complex_rpow()
		{
			complex			cc(sqrt(3.), 1.);	// the complex number whose real part
												// is the square root of 3, and imaginary part is 1.
												// so that its phase is 30 degrees and amplitude is 2.
			double			x = 3.;
			
			complex			cresult = rpow(cc, x);
			
			out_complex("Input = ", cc);
			out_double("power = ", x);
			out_complex("rpow = ", cresult);	// the result should be such that its amplitude is 8 (which
												// is 2 to the power 3.) and whose phase is 90 degrees (which
												// is 30 degrees times 3.).
		}
*/
complex rpow(complex z, double x);

/** >Complex Numbers
		returns the power of the complex value such that the power
		is a complex value
	Parameters:
		z1 = the complex value whose power is sought.
		z2 = the power
	Return:
		z1^z2
	Example:
		void	run_complex_cpow()
		{
			complex			z1(2., 1.);	
			complex			z2(3., 2.);
			
			complex			cresult = cpow(z1, z2);
			
			out_complex("base = ", z1);
			out_complex("power = ", z2);
			out_complex("cpow = ", cresult);
		}
*/
complex cpow(complex z1, complex z2);

/** >Basic I/O
		outputs a complex value
	Parameters:
		lpcstr = a pointer to a string which will preceed the value.
		z = the complex value to be output.
	Return:
		number of characters that are output.
	Example:
		void	run_complex_out_complex()
		{
			complex		cc(4.5, 7.8);
			
			out_complex("The value = ", cc);
		}
*/
int out_complex(LPCSTR lpcstr, complex z);



// the following functions are implemented in sys_utils.c, which is always automatically loaded


#endif // !_COMPLEX_H