/*Complex.java*/
/**
 * Complex Number Class
 * @author Singh T. Junior and Umberto Ravaioli, Maestro Series, Amanogawa
 * @version 1.0
 */

public final class Complex extends Object implements Cloneable, java.io.Serializable{
		/* All primitive data types are automatically serializable. */
		private double u; //Real Part
		private double v; //Imaginary Part

		/* These are the types of String Conversions. */
		public static final int CARTESIAN=0;
		public static final int POLAR_DEGREE=1;
		public static final int POLAR_RADIAN=2;

/** 
 * Main Constructor 
 */
public Complex(double x, double y){
		u=x;
		v=y;
}

public Complex(){
		this(0.0,0.0);	
}

public Object clone(){
	try{
		Complex ZZ = new Complex();
		ZZ.setReal(this.u);
		ZZ.setImaginary(this.v);
		return ZZ;
	}
	catch (Exception e){
		return null;
	}
}
	
/**
 * Complex conjugate a complex number. Ex: z.Conjugate();
 * @param none
 * @return void
 */
public synchronized void Conjugate(){
		u=u;
		v=-v;
}


public static final Complex Conjugate(Complex z){
	Complex mytmp = new Complex(z.Real(),-z.Imaginary());
	return mytmp;
}   


/** 
 * Returns real part of the complex number. Ex: d = z.Real();
 * @param none
 * @return double: real part
 */
public double Real() {
		return u;
}

public static final double Real(Complex z){
		return z.Real();
}


/**
 * Returns imaginary part of the complex number. Ex: d = z.Imaginary();
 * @param none
 * @return double: imaginary part
 */
public double Imaginary() {
		return v;
}

public static final double Imaginary(Complex z){
		return z.Imaginary();
}


/** 
 * Returns magnitude of the complex number. Ex: d = z.Magnitude();
 * @param none
 * @return double: magnitude
 */
public double Magnitude() {
		return Math.sqrt(u*u+v*v);
}       

public static final double Magnitude(Complex z){
	return z.Magnitude();
}

/** 
 * Returns magnitude square of the complex number. Ex: d = z.Magnitude();
 * @param none
 * @return double: magnitude
 */
public double Magnitude2() {
		return (u*u+v*v);
}

public static final double Magnitude2(Complex z){
		return z.Magnitude2();
}

/**
 * Returns atan(v/u) of the complex number. Ex: theta = z.Arg1();
 * @param none
 * @return double: angle from -Pi/2 to Pi/2
 */
public double Arg1() {
		return Math.atan(v/u);
}


public static final double Arg1(Complex z){
		return z.Arg1();
}

public double Arg1(int tipo){
	if(tipo == POLAR_DEGREE){
		return Arg1()*180/Math.PI;
	}
	else{
		return Arg1();
	}
}

public static final double Arg1(Complex z, int tipo){
	if(tipo == POLAR_DEGREE){
		return Arg1(z)*180/Math.PI;
	}
	else{
		return Arg1(z);
	}
}


/**
 * Returns atan2(v,u) of a complex number. Ex: theta = z.Arg2();
 * @param none
 * @return double: angle from -PI to PI
 */
public double Arg2() {
		return Math.atan2(v,u);
}


public static final double Arg2(Complex z){
		return z.Arg2();
}

public double Arg2(int tipo){
	if(tipo==POLAR_DEGREE){
		return Arg2()*180/Math.PI;
	}
	else{
		return Arg2();
	}
}

public static final double Arg2(Complex z, int tipo){
	if(tipo==POLAR_DEGREE){
		return z.Arg2()*180/Math.PI;
	}
	else{
		return z.Arg2();
	}
}

/** 
 * Adds a complex number to another one. Ex: z1.Add(z2)  --> z1 = z1 + Z2;
 * @param z	Complex number
 * @return void
 */
public synchronized void Add(Complex z){
		u+=z.u;
		v+=z.v;
}

public static final Complex Add(Complex z1, Complex z2){
		Complex tmp = (Complex)z1.clone();
		tmp.Add(z2);
		return tmp;
}


/**
 * Adds a double precision number to a complex number. Ex: z.Add(d) --> z = z + d;
 * @param d 	double precision  number
 * @return void
 */
public synchronized  void Add(double x){
		u+=x;
}

public static final Complex Add(Complex z, double x){
	Complex tmp = (Complex)z.clone();
	tmp.Add(x);
	return tmp;
}

public static final Complex Add(double x, Complex z){
	return Complex.Add(z,x);
}


/** 
 * Subtracts a complex number from another one. Ex: z1.Subtract(z2)  --> z1 = z1- z2;
 * @param z	Complex number
 * @return void
 */
public synchronized void Subtract(Complex z){
		u-=z.u;
		v-=z.v;
}


public static final Complex Subtract(Complex z1, Complex z2){
		Complex tmp;
		tmp = (Complex)z1.clone();
		tmp.Subtract(z2);
		return tmp;
}

public static final Complex Subtract(double x, Complex z){
		Complex tmp;
		tmp = new Complex(x-z.Real(),-z.Imaginary());
		return tmp;
}

/**
 * Subtracts a double precision number from a complex one. Ex: z.Subtract(d) --> z = z - d;
 * @param d 	double precision  number
 * @return void
 */
public synchronized void Subtract(double x){
		u-=x;
}

public static final Complex Subtract(Complex z, double x){
	Complex tmp;
	tmp = (Complex)z.clone();
	tmp.Subtract(x);
	return tmp;
}

/**
 * Multiplies a complex number to another complex one. Ex: z.Multiply(c) --> z = z * c;
 * @param c 	complex  number
 * @return void
 */
public synchronized void Multiply (Complex z) {
	double tempx = u;
	double tempy = v;
		u=tempx*z.u-tempy*z.v;
		v=tempx*z.v+tempy*z.u;
}


public static final Complex Multiply (Complex z1, Complex z2){
	Complex tmp;
	tmp = (Complex)z1.clone();
	tmp.Multiply(z2);
	return tmp;
}


/**
 * Multiplies a complex number to a double. Ex: z.Multiply(d) --> z = z * d;
 * @param d 	double precision  number
 * @return void
 */
public synchronized void  Multiply(double x){
	u=u*x;
	v=v*x;
}

public static final Complex Multiply(Complex z, double x){
	Complex tmp;
	tmp = (Complex)z.clone();
	tmp.Multiply(x);
	return tmp;
}

public static final Complex Multiply(double x, Complex z){
	return Complex.Multiply(z,x);
}


/**
 * Divides a complex number by another complex one. Ex: z.Divide(c) --> z = z / c;<BR>
 * Warning: It does not check for division by zero!
 * @param c 	complex  number
 * @return void
 */
public synchronized void Divide(Complex z){
	double tempx = u;
	double tempy = v;
	double rz=z.Magnitude();
	u=(tempx*z.u+tempy*z.v)/(rz*rz);
	v=(tempy*z.u-tempx*z.v)/(rz*rz);
}


public static final Complex Divide (Complex z1, Complex z2){
	Complex tmp;
	tmp = (Complex)z1.clone();
	tmp.Divide(z2);
	return tmp;
}
	


/**
 * Divides a complex number by a double. Ex: z.Divide(d) --> z = z / d;<BR>
 * Warning: It does not check for division by zero!
 * @param d 	double precision  number
 * @return void
 */
public synchronized void Divide(double x){
	u=u/x;
	v=v/x;
}


public static final Complex Divide(Complex z, double x){
	Complex tmp;
	tmp = (Complex)z.clone();
	tmp.Divide(x);
	return tmp;
}
	
public static final Complex Divide(double x, Complex z){
	Complex tmp;
	double mag2;
	tmp = (Complex)z.clone();
	tmp.Conjugate();
	tmp.Multiply(x);
	mag2=tmp.Magnitude2();
	tmp.Divide(mag2);
	return tmp;
}


/** 
 * Exponential function. Ex:  z.Exp();<BR>
 * Recall Euler's: exp(c) = exp(u+iv) = exp(u) * Complex(Cos(v),Sin(v))
 * @param none
 * @return void 
 */
public synchronized void Exp(){
	double tr, ti, temp;
	temp = Math.exp(u);
	tr = Math.cos(v)*temp;
	ti = Math.sin(v)*temp;
	u=tr;
	v=ti;
}


public static final Complex Exp(Complex z){
	Complex tmp;
	tmp = (Complex) z.clone();
	tmp.Exp();
	return tmp;
}	 

public static final Complex Sinh(Complex z){
	Complex tmp, tmp1, tmp2;
	tmp1=Complex.Exp(z);
	tmp2=Complex.Exp(Complex.Multiply(z,-1.0));
	tmp=Complex.Divide(Complex.Subtract(tmp1,tmp2),2.0);
	return tmp;
}

public static final Complex Cosh(Complex z){
	Complex tmp, tmp1, tmp2;
	tmp1=Complex.Exp(z);
	tmp2=Complex.Exp(Complex.Multiply(z,-1.0));
	tmp=Complex.Divide(Complex.Add(tmp1,tmp2),2.0);
	return tmp;
}


public static final Complex Tanh(Complex z){
	Complex tmp, tmp1, tmp2;
	tmp1=Complex.Exp(z);
	tmp2=Complex.Exp(Complex.Multiply(z,-1.0));
	tmp=Complex.Divide(Complex.Subtract(tmp1,tmp2),Complex.Add(tmp1,tmp2));
	return tmp;
}



/** 
 * Power function. Ex: z.Pow(x);<BR>
 * @param double precision x
 * @return  void 
 */
public synchronized void Pow(double x){
	double am, at;
	am = Math.pow(this.Magnitude(),x);
	at = this.Arg2()*x;
	u=am*Math.cos(at);
	v=am*Math.sin(at);
}

public static final Complex Pow(Complex z, double x){
	Complex tmp;
	tmp = (Complex) z.clone();
	tmp.Pow(x);
	return tmp;
}

/**
 * Return a string containing the complex number. Ex: z.toString()<BR>
 * Format: u + j v   or u - j v
 * @param none
 * @return String 
 */
public final String toString(){
	String tmp;
	if(v>=0.0){
		tmp = String.valueOf((u))+" + j "+String.valueOf((v)); 
		
	}
	else {
		tmp = String.valueOf((u))+" - j "+String.valueOf((Math.abs(v)));
	}
	return tmp;
}
/*
private double rounder(double x, int res){
	if(Math.abs(x)*Math.pow(10,res)>1.0*Integer.MAX_VALUE){
	    return x;
	}
	if(x>=0.0){
	    return (int)(Math.abs(x)*Math.pow(10,res)+0.5)/Math.pow(10,res);
	}
	else{
	    return -(int)(Math.abs(x)*Math.pow(10,res)+0.5)/Math.pow(10,res);
	}
}
*/
public final String toString(int tipo, int res){
	String tmp;
	double dtmp1, dtmp2;
	Complex ctmp1;
	dtmp2=MaestroA.rounder(v,res);
	dtmp1=MaestroA.rounder(u,res);
	
	ctmp1=new Complex(dtmp1,dtmp2);
	tmp=ctmp1.toString();
	switch(tipo)
	{
	   case POLAR_DEGREE:
	     dtmp1=MaestroA.rounder(this.Magnitude(),res);
	     if(dtmp1 == 0.0){dtmp2 = 0.0;}
	     else{
		dtmp2=MaestroA.rounder(this.Arg2()*180/Math.PI,res);
		
	     }
	     //tmp=""+dtmp1+" { "+dtmp2+" deg }";
	     tmp=""+dtmp1+"   |_ "+dtmp2+" \u00ba ";
           break;
	   case POLAR_RADIAN:
	     dtmp1=MaestroA.rounder(this.Magnitude(),res);
	     if(dtmp1 == 0.0){dtmp2 = 0.0;}
	     else{
		dtmp2=MaestroA.rounder(this.Arg2(),res);
	     }
	     //tmp=""+dtmp1+" { "+dtmp2+" rad }";
	     tmp=""+dtmp1+"   |_ "+dtmp2+" rad ";
           break;
        }
	return tmp;
}
public final String toString(int tipo, int res1, int res2){
	String tmp;
	double dtmp1, dtmp2;
	Complex ctmp1;
	dtmp2=MaestroA.rounder(v,res1);
	dtmp1=MaestroA.rounder(u,res1);
	
	ctmp1=new Complex(dtmp1,dtmp2);
	tmp=ctmp1.toString();
	switch(tipo)
	{
	   case POLAR_DEGREE:
	     dtmp1=MaestroA.rounder(this.Magnitude(),res1);
	     if(dtmp1 == 0.0){dtmp2 = 0.0;}
	     else{
		dtmp2=MaestroA.rounder(this.Arg2()*180/Math.PI,res2);
		
	     }
	     //tmp=""+dtmp1+" { "+dtmp2+" deg }";
	     tmp=""+dtmp1+"   |_ "+dtmp2+" \u00ba ";
           break;
	   case POLAR_RADIAN:
	     dtmp1=MaestroA.rounder(this.Magnitude(),res1);
	     if(dtmp1 == 0.0){dtmp2 = 0.0;}
	     else{
		dtmp2=MaestroA.rounder(this.Arg2(),res2);
	     }
	     //tmp=""+dtmp1+" { "+dtmp2+" rad }";
	     tmp=""+dtmp1+"   |_ "+dtmp2+" rad ";
           break;
        }
	return tmp;
}
public final String toString(int tipo, int res, boolean roundoff){
	String tmp;
	double dtmp1, dtmp2;
	Complex ctmp1;
	dtmp2=MaestroA.rounder(v,res,roundoff);
	dtmp1=MaestroA.rounder(u,res,roundoff);
	
	ctmp1=new Complex(dtmp1,dtmp2);
	tmp=ctmp1.toString();
	switch(tipo)
	{
	   case POLAR_DEGREE:
	     dtmp1=MaestroA.rounder(this.Magnitude(),res,roundoff);
	     
	     if(dtmp1 == 0.0){dtmp2 = 0.0;}
	     else{dtmp2=MaestroA.rounder(this.Arg2()*180/Math.PI,res,roundoff);}
	     //tmp=""+dtmp1+" { "+dtmp2+" deg }";
	     tmp=""+dtmp1+"   |_ "+dtmp2+" \u00ba ";
           break;
	   case POLAR_RADIAN:
	   
	     dtmp1=MaestroA.rounder(this.Magnitude(),res,roundoff);
	     if(dtmp1 == 0.0){dtmp2 = 0.0;}
	     else{dtmp2=MaestroA.rounder(this.Arg2(),res,roundoff);}
	     //tmp=""+dtmp1+" { "+dtmp2+" rad }";
	     tmp=""+dtmp1+"   |_ "+dtmp2+" rad ";
           break;
        }
	return tmp;
}


public static final String toString(Complex z){
	String tmp;
	if(z.Imaginary()>=0.0){
		tmp = String.valueOf((z.Real()))+" + j "+String.valueOf(z.Imaginary());
	}
	else {
		tmp = String.valueOf((z.Real()))+" - j "+String.valueOf(z.Imaginary());
	}
	return tmp;
}

/**
 * Return a string containing the complex number. Ex: z.toString(Complex.POLAR_DEGREE)<BR>
 * Format: mag(theta), theta in degrees.  
 * @param none
 * @return String 
 */
public final String toString(int tipo){
	String tmp;
	tmp=this.toString();
	switch(tipo)
	{
	   case POLAR_DEGREE:
	     tmp=""+this.Magnitude()+" ["+this.Arg2()*180/Math.PI+" \u00ba]";
           break;
	   case POLAR_RADIAN:
	     tmp=""+this.Magnitude()+" ["+this.Arg2()+" rad]";
           break;
        }
	return tmp;
}

public static final String toString(Complex z, int tipo){
	return z.toString(tipo);
}


/**
 * Set real part of a complex number. Ex: z.setReal(x)
 * @param x double precision
 * @return void
 */
public synchronized final void setReal(double u){
        this.u=u;
}

public synchronized static final void setReal(Complex z, double u){
	z.setReal(u);
}

/**
 * Set imaginary part of a complex number. Ex: z.setImaginary(x)
 * @param x double precision
 * @return void
 */
public synchronized final void setImaginary(double v){
        this.v=v;
}

public synchronized static final void setImaginary(Complex z, double v){
	z.setImaginary(v);
}

public boolean equals(Complex z){
	if(u == z.Real() && v == z.Imaginary()){
		return true;
	}
	else{
		return false;
	}
}
}//End of Complex
