/**
 * 
 * Komplexe Zahl z = a + ib
 * 
 * @author ingosturm
 * 
 */
/**
 * var a Realteil, var b Imaginärteil Darstellung in kartesischer, allgemeiner
 * Form var r Radius, var phi Winkel -π<=0<=+π Darstellung in Polarkoordinaten
 */
function Z(a, b, r, phi) {

	/**
	 * Trigonometrische Form: Polarkoordinaten (Arithmetische Form mit a & b
	 * wird ergänzt, wenn nicht vorgegeben)
	 * 
	 * @param a
	 *            Null (wird automatisch berechnet)
	 * @param b
	 *            Null (wird automatisch berechnet)
	 * @param r
	 *            Radius
	 * @param phi
	 *            -π<=0<=+π
	 */
	if (a == .0 && b == .0) {
		this.a = r * Math.cos(phi);
		this.b = r * Math.sin(phi);
		this.r = r;
		this.phi = phi;
	} else {
		/**
		 * Arithmetische Form: Karthesische Koordinaten (Polarkoordinaten r &
		 * phi werden berechnet)
		 * 
		 * @param a
		 *            real
		 * @param b
		 *            imaginär
		 */
		this.a = a;
		this.b = b;
		this.r = Math.sqrt(a * a + b * b);
		this.phi = getPhi(a, b);
	}

	/**
	 * Betrag (Modul) r von z
	 * 
	 * @return r = sqrt(a**2 + b**2)
	 */
	Z.prototype.rZ = function() {
		let r = Math.sqrt(this.a * this.a + this.b * this.b);
		if (!isNumber(r)) {
			r = 0.0;
			throw new ArithmeticException("Z-overflow");
		}
		return r;
	}

	/**
	 * Vergleich z = z ?
	 */
	Z.prototype.isEqualZ = function(z) {
		if ((Math.abs(this.a - z.reZ()) <= .1E-12)
				&& ((Math.abs(this.b - z.imZ()) <= .1E-12)))
			return true;
		else
			return false;
	}

	/**
	 * Addition z = z + z
	 * 
	 * @return Z komplexe Zahl
	 */
	Z.prototype.addZ = function(z) {
		let re;
		let im;
		re = this.a + z.reZ();
		im = this.b + z.imZ();
		if (!isNumber(re) || !isNumber(im)) {
			re = .0;
			im = .0;
			throw new ArithmeticException("Z-overflow");
		}
		return new Z(re, im, .0, .0);
	}

	/**
	 * Quadrat z**2 = a**2 - b**2 + i2ab
	 * 
	 * @return Z komplexe Zahl
	 */
	Z.prototype.quadratZ = function() {
		let re, im;
		im = 2 * this.a * this.b;
		re = this.a * this.a - this.b * this.b;
		if (!isNumber(re) || !isNumber(im)) {
			re = .0;
			im = .0;
			throw new ArithmeticException("Z-overflow");
		}
		return new Z(re, im, .0, .0);
	}

	/**
	 * Power z**n = r**n(cosnPhi + icosnPhi)
	 * 
	 * @param n
	 *            reeller Exponent
	 * @return Z komplexe Zahl
	 */
	Z.prototype.powerZ = function(n) {
		let pr, w, re, im;
		pr = Math.pow(this.r, n);
		w = this.phi * n;
		re = pr * Math.cos(w);
		im = pr * Math.sin(w);
		if (!isNumber(re) || !isNumber(im)) {
			re = .0;
			im = .0;
			throw new ArithmeticException("Z-overflow");
		}
		return new Z(re, im, .0, .0);
	}

	/**
	 * @return the a real of z prototype=static
	 */
	Z.prototype.reZ = function() {
		return this.a;
	}

	/**
	 * @return the b imagine of z prototype=static
	 */
	Z.prototype.imZ = function() {
		return this.b;
	}
}
/**
 * 
 * Utility function's
 * 
 */
/**
 * Convert degrees to radiant
 * 
 * @param degrees
 * @returns rad
 */
function degToRad(degrees) {
	return degrees * Math.PI / 180;
};

/**
 * utility-function: get phi by point(x,y)
 * 
 * @param x
 * @param y
 * @returns phi
 */
function getPhi(x, y) {
	let phi = 0;

	if (x != .0)
		phi = Math.atan(y / x);
	else if (y > .0)
		phi = Math.PI / 2.0;
	else if (y < .0)
		phi = 3.0 * Math.PI / 2.0;
	else
		phi = 0.0;
	return phi;
}

/**
 * Check is Number by javascript
 * 
 * @param val
 * @returns true or false
 */
function isNumber(val) {
	if (typeof val === "number") {
		return isFinite(val);
	}
	return false;
}