#ifdef _MSC_VER
// this extra #define is only needed for Microsoft Visual C++
#define _USE_MATH_DEFINES
#include <cmath>
#else
#include <cmath>
#endif

#include <complex>
#include <iostream>
#include <iomanip>
using namespace std;

/*
Uitgangspunten:
-	een Component
	-	is een abstracte base class
	-	heeft een impedantie Z die afhankelijk is van de frequentie f
	-	kan geprint worden
-	een R (weerstand)
	-	is een soort Component
	-	heeft een waarde (value)
	-	Z(f)=value+j*0
-	een L (spoel)
	-	is een soort Component
	-	heeft een waarde (value)
	-	Z(f)=0+j*2*pi*f*value
-	een C (condensator)
	-	is een soort Component
	-	heeft een waarde (value)
	-	Z(f)=0-j/(2*pi*f*value)
-	een S (Serie schakeling)
	-	is een soort Component
	-	is een samenstelling van twee Componenten
	-	Z(f)=Z1(f)+Z2(f)
-	een P (Parallel schakeling)
	-	is een soort Component
	-	is een samenstelling van twee Componenten
	-	Z(f)=1/(1/Z1(f)+1/Z2(f))
*/

class Component {
public:
	virtual ~Component() {
	}
	virtual complex<double> Z(double f) const=0; // bereken de impedantie Z (een complex
						                              // getal) bij de frequentie f
	virtual void print(ostream& o) const=0;      // print
};

ostream& operator<<(ostream& o, const Component& c) {
	c.print(o);
	return o;
}

class R: public Component { // R=Weerstand
public:
	R(double r): value(r) {
	}
	virtual complex<double> Z(double f) const {
		return value;
	}
	virtual void print(ostream& o) const {
		o<<"R("<<value<<")";
	}
private:
	double value;
};

class L: public Component { // L=Spoel
public:
	L(double l): value(l) {
	}
	virtual complex<double> Z(double f) const {
		return complex<double>(0, 2*M_PI*f*value);
	}
	virtual void print(ostream& o) const {
		o<<"L("<<value<<")";
	}
private:
	double value;
};

class C: public Component { // C=Condensator
public:
	C(double c): value(c) {
	}
	virtual complex<double> Z(double f) const {
		return complex<double>(0, -1/(2*M_PI*f*value));
	}
	virtual void print(ostream& o) const {
		o<<"C("<<value<<")";
	}
private:
	double value;
};

class S: public Component { // S=Serie schakeling van twee componenten
public:
	S(const Component& c1, const Component& c2): comp1(c1), comp2(c2) {
	}
	virtual complex<double> Z(double f) const {
		return comp1.Z(f)+comp2.Z(f);
	}
	virtual void print(ostream& o) const {
		o<<"("<<comp1<<"+"<<comp2<<")";
	}
private:
	const Component& comp1;
	const Component& comp2;
	S(const S&);              // voorkom gebruik
	void operator=(const S&); // voorkom gebruik
};

class P: public Component { // P=Parallel schakeling van twee componenten
public:
	P(const Component& c1, const Component& c2): comp1(c1), comp2(c2) {
	}
	virtual complex<double> Z(double f) const {
		return (comp1.Z(f)*comp2.Z(f)) / (comp1.Z(f)+comp2.Z(f));
	}
	virtual void print(ostream& o) const {
		o<<"("<<comp1<<"//"<<comp2<<")";
	}
private:
	const Component& comp1;
	const Component& comp2;
	P(const P&);              // voorkom gebruik
	void operator=(const P&); // voorkom gebruik
};

void printImpedanceTable(const Component& c) {
	cout<<"Impedantie tabel voor: "<<c<<endl<<endl;
	cout<<"freq\tZ"<<endl;
	for (double freq(10);freq<10E6;freq*=10)
		cout<<setw(5)<<freq<<'\t'<<c.Z(freq)<<endl;
	cout<<endl<<endl;
}

int main() {
	R r1(1E2);
	C c1(1E-6);
	L l1(3E-2);
	S s1(r1, c1);
	S s2(r1, l1);
	P p(s1, s2);
	printImpedanceTable(p);
	cin.get();
	return 0;
}

