/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
 * Copyright (c) 2012 University of British Columbia, Vancouver
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation;
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Author: Alexander Schloegl <alexander.schloegl@gmx.de>
 */

#ifndef PLC_CABLE_H_
#define PLC_CABLE_H_

#include <cmath>
#include <iostream>
#include <complex>

#include <ns3/object.h>
#include <ns3/type-id.h>
#include <ns3/spectrum-model.h>

#include "plc-defs.h"
#include "plc-value.h"

// Cable model parameters
#define EPS_0 	8.854188e-12 	// F/m
#define MU_0	12.566371e-7	// H/m
#define MU_R	1
#define RHO		2.82e-8			// for aluminium (multiple references; to fit Dostert's curves)
#define TAND	0.01			// depends on insulation
#define MU		(MU_0 * MU_R)
#define EPS_R	4
#define EPS_K	2.3 //dielektricka konstanta izolační vrstvy XLPE
#define EPS_P	(EPS_0 * EPS_R)

#define cond_al		37.7e6
#define cond_cu		58.108e6


////////////////////////////AXEKCY240 primární parametry////////////////////////
#define AXEKCY240_C		4.5e-10 
#define AXEKCY240_L		5.7e-7 

////////////////////////////AXEKVCEY240 primární parametry////////////////////////
#define AXEKVCEY240_C	3.2e-10
#define AXEKVCEY240_L	5.2e-7



#define NAYY150SE_D		1.8e-3		// insulation, m
#define NAYY150SE_A		6e-4		// conductor area, 4*150e-6m^2
#define NAYY150SE_THETA	3.6e-3		// 2*NAYY150SE_D
#define NAYY150SE_R		13.82e-3	// radius, m, r = sqrt(A/pi)

#define NAYY50SE_D		1.4e-3		// insulation, m
#define NAYY50SE_A		2e-4		// conductor area, 4*50e-6m^2
#define NAYY50SE_THETA	2.8e-3		// 2*NAYY50SE_D
#define NAYY50SE_R		7.98e-3		// radius, m, r = sqrt(A/pi)

//_K NAYY95SE
#define NAYY95SE_D		1.6e-3		// insulation, m
#define NAYY95SE_A		3.8e-4		// conductor area, 4*95e-6m^2
#define NAYY95SE_THETA	3.2e-3		// 2*NAYY95SE_D
#define NAYY95SE_R		11e-3		// radius, m, r = sqrt(A/pi)

//_K NAYY240SE
#define NAYY240SE_D		2.2e-3		// insulation, m
#define NAYY240SE_A		9.6e-4		// conductor area, 4*2405e-6m^2
#define NAYY240SE_THETA	4.4e-3		// 2*NAYY240SE_D
#define NAYY240SE_R		17.48e-3	// radius, m, r = sqrt(A/pi)

//_K NAYY185SE
#define NAYY185SE_D		2e-3		// insulation, m
#define NAYY185SE_A		7.4e-4		// conductor area, 4*185e-6m^2
#define NAYY185SE_THETA	4e-3		// 2*NAYY185SE_D
#define NAYY185SE_R		15.35e-3	// radius, m, r = sqrt(A/pi)

//_K AYKY4x50
#define AYKY4x50_D			1.4e-3		// insulation, m
#define AYKY4x50_A			2e-4		// conductor area
#define AYKY4x50_THETA		2.8e-3		// 2*AYKY4x50_D
#define AYKY4x50_R			7.98e-3		// radius

//_K AES4x120
#define AES4x120_R				6.18e-3
#define AES4x120_CD				15.96e-3			//6.18+1.8*2
#define AES4x120_TAND			0.04
#define AES4x120_MR				1.000023		//pro hliník
#define AES4x120_ER				4

//#define AL3X95XLPE
#define AL3X95XLPE_EPS_R	4
#define AL3X95XLPE_D		3.584e-3
#define AL3X95XLPE_A		0.892e-3
#define AL3X95XLPE_SIGMA	58e6
#define AL3X95XLPE_TAND		4e-2
#define AL3X95XLPE_KAPPA	0.285714286
#define AL3X95XLPE_R_A		10e-3
#define AL3X95XLPE_R_I		9.52e-3
//#define AL3X95XLPE_TAND		0.004

//AlFe4x50
#define AlFe4x50_R0k		0.1563	 //ohms na km
#define AlFe4x50_G0k		0.1		 // za sucha, S/km
#define AlFe4x50_r			4.8		//mm
#define AlFe4x50_d			0.4
#define AlFe4x50_epsr		1		// za sucha
#define AlFe4x50_mir		1		// za sucha
#define AlFe4x50_rho		0.0267

//AlFe4x35
#define AlFe4x35_R0k		0.5022	//ohms na kilomtr
#define AlFe4x35_G0k		0.1 // za sucha
#define AlFe4x35_r			4.05	//Millimeters
#define AlFe4x35_d			10
#define AlFe4x35_epsr		1		// za sucha
#define AlFe4x35_mir		1		// za sucha
#define AlFe4x35_rho		0.0267  //nohm m

//AlFe4x25
#define AlFe4x25_R0k		0.877	//ohms na kilomtr
#define AlFe4x25_G0k		0.1 // za sucha
#define AlFe4x25_r			3.375	//Millimeters
#define AlFe4x25_d			10
#define AlFe4x25_epsr		1		// za sucha
#define AlFe4x25_mir		1		// za sucha
#define AlFe4x25_rho		0.0267  //nohm m

//AYKY3x120
#define AYKY3x120_70_D			1.6e-3		// insulation, m
#define AYKY3x120_70_A			4.3e-4		// conductor area, 3*120+70e-6m^2
#define AYKY3x120_70_THETA		3.2e-3		// 2*NAYY150SE_D
#define AYKY3x120_70_R			12.36e-3	// radius

//AES4x50
#define AES4x50_R				3.98e-3
#define AES4x50_CD				10.76e-3			//6.98+1.4*2
#define AES4x50_TAND			0.04
#define AES4x50_MR				1.000023		//pro hliník
#define AES4x50_ER				4 			

#define Aluminium_CONDUCTIVITY 3.7e7
#define COPPER_CONDUCTIVITY	5.96e7 // (S/m) at 20 degree celcius
#define NYCY70SM35_R_O 8.448e-3 // radius to outer conductor
#define NYCY70SM35_R_I 7.048e-3 // inner conductor radius

///////// CYKY3x2.5
#define CYKY_EPS_R			4
#define CYKY_D				3.584e-3
#define CYKY_A				0.892e-3
#define CYKY_SIGMA			58e6
#define CYKY_TAND			4e-2

///////// CYKY3x2.5 RLCG parameters
#define CYKY_R0			9.34
#define CYKY_L			0.96e-6
#define CYKY_C			17.5e-12
#define CYKY_G0			34.7
//#define CYKY_l			5
#define CYKY_l			0.35
//#define CYKY_l			1






namespace ns3 {

/**
 *	This class describes lossy transmission lines with the two wire conductor theory for TEM waves.
 *	Based on the distributed circuit parameters R',G',L',C' the characteristic impedance z_c
 *	and the propagation constant gamma are calculated.
 */
class PLC_Cable : public Object
{
public:
	static TypeId GetTypeId(void);

	/**
	 * Constructor
	 */
	PLC_Cable () {}

	/**
	 * Constructor
	 * @param sm  The used spectrum model
	 */
	PLC_Cable(Ptr<const SpectrumModel> sm);

	virtual void Calculate() = 0;

	/**
	 *
	 * @param R Distributed resistance
	 * @param G Distributed conductance
	 * @param L Distributed inductance
	 * @param C Distributed capacity
	 * @param sm Spectrum model
	 */
	PLC_Cable(const PLC_FreqSelectiveResistance& R, const PLC_FreqSelectiveConductance& G, const PLC_FreqSelectiveInductance& L, const PLC_FreqSelectiveCapacitance& C, Ptr<const SpectrumModel> sm);

	void SetSpectrumModel(Ptr<const SpectrumModel> sm);
	Ptr<const SpectrumModel> GetSpectrumModel(void) { return m_spectrum_model; }

	/**
	 * Get the characteristic impedance of the cable
	 * @return z_c
	 */
	PLC_FreqSelectiveImpedance GetCharImp(void) const;

	/**
	 * Get the propagation constant of the cable
	 * @return gamma
	 */
	PLC_FreqSelectiveImpedance GetTransConst(void) const;

	/**
	 * Get the wave propagation speed for the lossless line as an approximation to calculate a signal's
	 * propagation delay
	 * @return v
	 */
	double GetPropSpeedApprox(void) { return v; }

	/**
	 *
	 * @return The used spectrum model
	 */
	Ptr<const SpectrumModel> GetSpectrumModel(void) const { return m_spectrum_model; }

	/**
	 * Cable mutex lock functions
	 */
//	void Lock() 		{ m_cable_mutex.Lock(); }
//	void Unlock()	{ m_cable_mutex.Unlock(); }

	/**
	 *
	 * @return Distributed resistance (frequency dependent)
	 */
	PLC_FreqSelectiveResistance *GetDistResRef(void) { return &R; }

	/**
	 *
	 * @return Distributed conductance (frequency dependent)
	 */
	PLC_FreqSelectiveResistance *GetDistConRef(void) { return &G; }

private:
	mutable PLC_Mutex 			m_cable_mutex;

protected:
	virtual void DoDispose();

	Ptr<const SpectrumModel> 	m_spectrum_model;

	/**
	 * distributed resistance
	 */
	PLC_FreqSelectiveResistance R;
	/**
	 * distributed conductance
	 */
	PLC_FreqSelectiveConductance G;
	/**
	 * distributed inductance
	 */
	PLC_FreqSelectiveInductance L;
	/**
	 * distributed capacitance
	 */
	PLC_FreqSelectiveCapacitance C;
	/**
	 * characteristic impedance
	 */
	Ptr<PLC_FreqSelectiveImpedance> z_c;
	/**
	 * transmission constant
	 */
	Ptr<PLC_FreqSelectiveImpedance> gamma;

	/**
	 * Popagation speed
	 *
	 * assumption: flat propagation over lossless medium
	 */
	double v;

	/**
	 * Calculates characteristic impedance of the cable
	 */
	void CalcCharImp(void);

	/**
	 * Calculates propagation constant of the cable
	 */
	void CalcTransConst(void);
};

/**
 * Coaxial model for the three core concentric cable
 * from "Powerline Communications" by K. Dostert
 */
class PLC_ThreeCoreConcentricCable : public PLC_Cable
{
public:
	static TypeId GetTypeId(void);

	PLC_ThreeCoreConcentricCable() : PLC_Cable() {}

	virtual void Calculate() = 0;

	/**
	 *
	 * @param eps_r dielectric constant
	 * @param kappa specific conductivity
	 * @param r_a Cable radius
	 * @param r_i Conductor sector radius
	 * @param tand Tangents loss angle
	 * @param sm Spectrum model
	 */
	
	PLC_ThreeCoreConcentricCable(double r, double lconst, double c, double g, double l, Ptr<const SpectrumModel> sm);

	//PLC_ThreeCoreConcentricCable(double eps_r, double kappa, double r_a, double r_i, double tand, Ptr<const SpectrumModel> sm);
	PLC_ThreeCoreConcentricCable(PLC_FreqSelectiveRealValue eps_r, double kappa, double r_a, double r_i, PLC_FreqSelectiveRealValue tand, Ptr<const SpectrumModel> sm);

	//Výpočet RLCG parametrů
	void Calculate(double r, double lconst, double c, double g, double l, Ptr<const SpectrumModel> sm);

	//void Calculate(double eps_r, double kappa, double r_a, double r_i, double tand, Ptr<const SpectrumModel> sm);
	void Calculate(PLC_FreqSelectiveRealValue eps_r, double kappa, double r_a, double r_i, PLC_FreqSelectiveRealValue tand, Ptr<const SpectrumModel> sm);
	};


/**
 * Model for a four sector cable
 */
class PLC_FourSectorPowerSupplyCable : public PLC_Cable
{
public:
	static TypeId GetTypeId(void);

	PLC_FourSectorPowerSupplyCable() : PLC_Cable() {}

	virtual void Calculate() = 0;

	/**
	 * @param radius Radius of the cable
	 * @param conductor_distance Distance between conductors
	 * @param tan_loss_angle Tangents loss angle
	 * @param epsilon_r Dielectric constant
	 * @param rho
	 * @param sm
	 */
	PLC_FourSectorPowerSupplyCable(double radius, double conductor_distance, double tan_loss_angle, double epsilon_r, double rho, Ptr<const SpectrumModel> sm);
	PLC_FourSectorPowerSupplyCable(double radius, double conductor_distance, PLC_FreqSelectiveRealValue tan_loss_angle, PLC_FreqSelectiveRealValue epsilon_r, double rho, Ptr<const SpectrumModel> sm);
	void Calculate(double radius, double conductor_distance, double tan_loss_angle, double epsilon_r, double rho, Ptr<const SpectrumModel> sm);
	void Calculate(double radius, double conductor_distance, PLC_FreqSelectiveRealValue tan_loss_angle, PLC_FreqSelectiveRealValue epsilon_r, double rho, Ptr<const SpectrumModel> sm);
};

/**
 * Model for a overhead powerline _K
 */
class PLC_Overheadpowerline : public PLC_Cable
{
public:
	static TypeId GetTypeId(void);

	PLC_Overheadpowerline() : PLC_Cable() {}

	virtual void Calculate() = 0;


	/**
	 * @param radius Radius of the cable
	 * @param conductor_distance Distance between conductors
	 * @param tan_loss_angle Tangents loss angle
	 * @param epsilon_r Dielectric constant
	 * @param rho
	 * @param sm
	 */

	PLC_Overheadpowerline(double Rok, double Gok, double radius, double conductor_distance, double mi_r, double epsilon_r, double rho, Ptr<const SpectrumModel> sm);
	PLC_Overheadpowerline(double radius, double conductor_distance, double mi_r, double epsilon_r, double tand, Ptr<const SpectrumModel> sm);


	void Calculate(double Rok, double Gok, double radius, double conductor_distance, double mi_r, double epsilon_r, double rho, Ptr<const SpectrumModel> sm);

	void Calculate(double radius, double conductor_distance, double mi_r, double epsilon_r, double tand, Ptr<const SpectrumModel> sm);
};

/**
 * Model for a MV powerline _K
 */
//_K DP JAKUB PETRŮJ
class PLC_MediumVoltageline : public PLC_Cable
{
public:
	static TypeId GetTypeId(void);

	PLC_MediumVoltageline() : PLC_Cable() {}

	virtual void Calculate() = 0;


			
	PLC_MediumVoltageline(double L_, double C_, Ptr<const SpectrumModel> sm);

	

	void Calculate(double L_, double C_, Ptr<const SpectrumModel> sm);

	
	
};

/**
 * Parameter model for the power supply cable NAYY150SE
 */
class PLC_NAYY150SE_Cable : public PLC_FourSectorPowerSupplyCable
{
public:
	static TypeId GetTypeId(void);

	PLC_NAYY150SE_Cable() : PLC_FourSectorPowerSupplyCable() {}
	PLC_NAYY150SE_Cable(Ptr<const SpectrumModel> sm);
	void Calculate();
};

/**
 * Parameter model for the power supply cable NAYY50SE
 */
class PLC_NAYY50SE_Cable : public PLC_FourSectorPowerSupplyCable
{
public:
	static TypeId GetTypeId(void);

	PLC_NAYY50SE_Cable() : PLC_FourSectorPowerSupplyCable() {}
	PLC_NAYY50SE_Cable(Ptr<const SpectrumModel> sm);
	void Calculate();
};

/**
 * Parameter model for the power supply cable NAYY95SE; _K
 */
//_K DP JAKUB PETRŮJ
class PLC_NAYY95SE_Cable : public PLC_FourSectorPowerSupplyCable
{
public:
	static TypeId GetTypeId(void);

	PLC_NAYY95SE_Cable() : PLC_FourSectorPowerSupplyCable() {}
	PLC_NAYY95SE_Cable(Ptr<const SpectrumModel> sm);
	void Calculate();
};

/**
 * Parameter model for the power supply cable NAYY240SE; _K
 */
//_K DP JAKUB PETRŮJ
class PLC_NAYY240SE_Cable : public PLC_FourSectorPowerSupplyCable
{
public:
	static TypeId GetTypeId(void);

	PLC_NAYY240SE_Cable() : PLC_FourSectorPowerSupplyCable() {}
	PLC_NAYY240SE_Cable(Ptr<const SpectrumModel> sm);
	void Calculate();
};

/**
 * Parameter model for the power supply cable NAYY240SE; _K
 */
//_K DP JAKUB PETRŮJ
class PLC_NAYY185SE_Cable : public PLC_FourSectorPowerSupplyCable
{
public:
	static TypeId GetTypeId(void);

	PLC_NAYY185SE_Cable() : PLC_FourSectorPowerSupplyCable() {}
	PLC_NAYY185SE_Cable(Ptr<const SpectrumModel> sm);
	void Calculate();
};

/**
 * Parameter model for the power supply cable NAYY4x150; _K
 */
class PLC_NAYY4x150_Cable : public PLC_FourSectorPowerSupplyCable
{
public:
	static TypeId GetTypeId(void);

	PLC_NAYY4x150_Cable() : PLC_FourSectorPowerSupplyCable() {}
	PLC_NAYY4x150_Cable(Ptr<const SpectrumModel> sm);
	void Calculate();
};

/**
 * Parameter model for the power supply cable AYKY4x50; _K
 */
class PLC_AYKY4x50_Cable : public PLC_FourSectorPowerSupplyCable
{
public:
	static TypeId GetTypeId(void);

	PLC_AYKY4x50_Cable() : PLC_FourSectorPowerSupplyCable() {}
	PLC_AYKY4x50_Cable(Ptr<const SpectrumModel> sm);
	void Calculate();
};

/**
 * Parameter model for the power supply cable AYKY3x120_70; _K
 */
class PLC_AYKY3x120_70_Cable : public PLC_FourSectorPowerSupplyCable
{
public:
	static TypeId GetTypeId(void);

	PLC_AYKY3x120_70_Cable() : PLC_FourSectorPowerSupplyCable() {}
	PLC_AYKY3x120_70_Cable(Ptr<const SpectrumModel> sm);
	void Calculate();
};

/**
 * Parameter model for the power supply cable AlFe4x50; _K
 */
class PLC_AlFe4x50_Cable : public PLC_Overheadpowerline
{
public:
	static TypeId GetTypeId(void);

	PLC_AlFe4x50_Cable() : PLC_Overheadpowerline() {}
	PLC_AlFe4x50_Cable(Ptr<const SpectrumModel> sm);
	void Calculate();
};

/**
 * Parameter model for the power supply cable AlFe4x35; _K
 */
class PLC_AlFe4x35_Cable : public PLC_Overheadpowerline
{
public:
	static TypeId GetTypeId(void);

	PLC_AlFe4x35_Cable() : PLC_Overheadpowerline() {}
	PLC_AlFe4x35_Cable(Ptr<const SpectrumModel> sm);
	void Calculate();
};

/**
 * Parameter model for the power supply cable AlFe4x25; _K
 */
class PLC_AlFe4x25_Cable : public PLC_Overheadpowerline
{
public:
	static TypeId GetTypeId(void);

	PLC_AlFe4x25_Cable() : PLC_Overheadpowerline() {}
	PLC_AlFe4x25_Cable(Ptr<const SpectrumModel> sm);
	void Calculate();
};

/**
 * Parameter model for the power supply cable AL3x95XLPE
 */
class PLC_AL3x95XLPE_Cable : public PLC_ThreeCoreConcentricCable
{
public:
	static TypeId GetTypeId(void);

	PLC_AL3x95XLPE_Cable() : PLC_ThreeCoreConcentricCable() {}
	PLC_AL3x95XLPE_Cable(Ptr<const SpectrumModel> sm);
	void Calculate();
};

/**
 * Parameter model for the power supply cable NYCY70SM35; _K
 */
class PLC_NYCY70SM35_Cable : public PLC_ThreeCoreConcentricCable
{
public:
	static TypeId GetTypeId(void);

	PLC_NYCY70SM35_Cable() : PLC_ThreeCoreConcentricCable() {}
	PLC_NYCY70SM35_Cable(Ptr<const SpectrumModel> sm);
	void Calculate();
};

/**
 * Parameter model for the power supply cable AES4x120; _K
 */
class PLC_AES4x120_Cable : public PLC_Overheadpowerline
{
public:
	static TypeId GetTypeId(void);

	PLC_AES4x120_Cable() : PLC_Overheadpowerline() {}
	PLC_AES4x120_Cable(Ptr<const SpectrumModel> sm);
	void Calculate();
};

/**
 * Parameter model for the power supply cable AES4x50; _K
 */
class PLC_AES4x50_Cable : public PLC_Overheadpowerline
{
public:
	static TypeId GetTypeId(void);

	PLC_AES4x50_Cable() : PLC_Overheadpowerline() {}
	PLC_AES4x50_Cable(Ptr<const SpectrumModel> sm);
	void Calculate();
};

/**
 * Parameter model for the power supply cable CYKY3x2.5
 */
class PLC_CYKY_Cable : public PLC_ThreeCoreConcentricCable
{
public:
	static TypeId GetTypeId(void);

	PLC_CYKY_Cable() : PLC_ThreeCoreConcentricCable() {}
	PLC_CYKY_Cable(Ptr<const SpectrumModel> sm);
	void Calculate();
};

//_K DP JAKUB PETRŮJ
class PLC_AXEKCY240 : public PLC_MediumVoltageline
{
public:
	static TypeId GetTypeId(void);

	PLC_AXEKCY240() : PLC_MediumVoltageline() {}
	PLC_AXEKCY240(Ptr<const SpectrumModel> sm);
	void Calculate();
};
//_K DP JAKUB PETRŮJ
class PLC_AXEKVCEY240 : public PLC_MediumVoltageline
{
public:
	static TypeId GetTypeId(void);

	PLC_AXEKVCEY240() : PLC_MediumVoltageline() {}
	PLC_AXEKVCEY240(Ptr<const SpectrumModel> sm);
	void Calculate();
};
}

#endif /* PLC_CABLE_H_ */

