/*! \file clu_subs.h
 *
 * \brief C++ porting of CLU functions and subroutines.
 *
 * This library includes a collection of functions that are used to solve the
 * scattering problem in the case of a cluster of spheres. The functions that
 * were generalized from the case of the single sphere are imported the `sph_subs.h`
 * library. As it occurs with the single sphere case functions, in most cases, the
 * results of calculations do not fall back to fundamental data types. They are
 * rather multi-component structures. In order to manage access to such variety
 * of return values, most functions are declared as `void` and they operate on
 * output arguments passed by reference.
 */

#ifndef INCLUDE_CLU_SUBS_H_
#define INCLUDE_CLU_SUBS_H_

/*! \brief C++ porting of APC
 *
 * \param zpv: `double ****`
 * \param le: `int`
 * \param am0m: Matrix of complex.
 * \param w: Matrix of complex.
 * \param sqk: `double`
 * \param gapr: `double **`
 * \param gapp: Matrix of complex.
 */
void apc(
	 double ****zpv, int le, std::complex<double> **am0m, std::complex<double> **w,
	 double sqk, double **gapr, std::complex<double> **gapp
);

/*! \brief C++ porting of APCRA
 *
 * \param zpv: `double ****`
 * \param le: `int`
 * \param am0m: Matrix of complex.
 * \param inpol: `int` Polarization type.
 * \param sqk: `double`
 * \param gaprm: `double **`
 * \param gappm: Matrix of complex.
 */
void apcra(
	   double ****zpv, const int le, std::complex<double> **am0m, int inpol, double sqk,
	   double **gaprm, std::complex<double> **gappm
);

/*! \brief C++ porting of CDTP
 *
 * \param z: `complex<double>`
 * \param am: Matrix of complex.
 * \param i: `int`
 * \param jf: `int`
 * \param k: `int`
 * \param nj: `int`
 */
std::complex<double> cdtp(
			  std::complex<double> z, std::complex<double> **am, int i, int jf,
			  int k, int nj
);

/*! \brief C++ porting of CGEV
 *
 * \param ipamo: `int`
 * \param mu: `int`
 * \param l: `int`
 * \param m: `int`
 * \return result: `double`
 */
double cgev(int ipamo, int mu, int l, int m);

/*! \brief C++ porting of CMS
 *
 * \param am: Matrix of complex.
 * \param c1: `C1 *`
 * \param c1ao: `C1_AddOns *`
 * \param c4: `C4 *`
 * \param c6: `C6 *`
 */
void cms(std::complex<double> **am, C1 *c1, C1_AddOns *c1ao, C4 *c4, C6 *c6);

/*! \brief C++ porting of CRSM1
 *
 * \param vk: `double` Wave number.
 * \param exri: `double` External medium refractive index.
 * \param c1: `C1 *`
 * \param c1ao: `C1_AddOns *`
 * \param c4: `C4 *`
 * \param c6: `C6 *`
 */
void crsm1(double vk, double exri, C1 *c1, C1_AddOns *c1ao, C4 *c4, C6 *c6);

/*! \brief C++ porting of GHIT
 *
 * \param ihi: `int`
 * \param ipamo: `int`
 * \param nbl: `int`
 * \param l1: `int`
 * \param m1: `int`
 * \param l2: `int`
 * \param m2: `int`
 * \param c1: `C1 *`
 * \param c1ao: `C1_AddOns *`
 * \param c4: `C4 *`
 * \param c6: `C6 *`
 */
std::complex<double> ghit(
			  int ihi, int ipamo, int nbl, int l1, int m1, int l2, int m2, C1 *c1,
			  C1_AddOns *c1ao, C4 *c4, C6 *c6
);

/*! \brief C++ porting of HJV
 *
 * \param exri: `double` External medium refractive index.
 * \param vk: `double` Wave number.
 * \param jer: `int &` Reference to error code flag.
 * \param lcalc: `int &` Reference to the highest order accounted for in calculation.
 * \param arg: `complex\<double\> &`
 * \param c1: `C1 *`
 * \param c1ao: `C1_AddOns *`
 * \param c4: `C4 *`
 */
void hjv(
	 double exri, double vk, int &jer, int &lcalc, std::complex<double> &arg,
	 C1 *c1, C1_AddOns *c1ao, C4 *c4
);

/*! \brief C++ porting of LUCIN
 *
 * \param am: Matrix of complex.
 * \param nddmst: `const int`
 * \param n: `int`
 * \param ier: `int &`
 */
void lucin(std::complex<double> **am, const int nddmst, int n, int &ier);

/*! \brief C++ porting of MEXTC
 *
 * \param vk: `double` Wave number.
 * \param exri: `double` External medium refractive index.
 * \param fsac: Matrix of complex
 * \param cextlr: `double **`
 * \param cext: `double **`
 */
void mextc(double vk, double exri, std::complex<double> **fsac, double **cextlr, double **cext);

/*! \brief C++ porting of PCROS
 *
 * This function is intended to evaluate the particle cross-section. QUESTIUON: correct?
 * \param vk: `double` Wave number.
 * \param exri: `double` External medium refractive index.
 * \param c1: `C1 *`
 * \param c1ao: `C1_AddOns *`
 * \param c4: `C4 *`
 */
void pcros(double vk, double exri, C1 *c1, C1_AddOns *c1ao, C4 *c4);

/*! \brief C++ porting of PCRSM0
 *
 * \param vk: `double` Wave number.
 * \param exri: `double` External medium refractive index.
 * \param inpol: `int` Incident field polarization type.
 * \param c1: `C1 *`
 * \param c1ao: `C1_AddOns *`
 * \param c4: `C4 *`
 */
void pcrsm0(double vk, double exri, int inpol, C1 *c1, C1_AddOns *c1ao, C4 *c4);

/*! \brief C++ porting of POLAR
 *
 * \param x: `double` X-axis Cartesian coordinate.
 * \param y: `double` Y-axis Cartesian coordinate.
 * \param z: `double` Z-axis Cartesian coordinate.
 * \param r: `double &` Reference to radial vector (output value).
 * \param cth: `double &` Reference to the cosine of the azimuth coordinate (output value).
 * \param sth: `double &` Reference to the sine of the azimuth coordinate (output value).
 * \param cph: `double &` Reference to the cosine of the elevation coordinate (output value).
 * \param sph: `double &` Reference to the sine of the elevation coordinate (output value).
 */
void polar(
	   double x, double y, double z, double &r, double &cth, double &sth,
	   double &cph, double &sph
);

/*! \brief C++ porting of R3J000
 *
 * \param j2: `int`
 * \param j3: `int`
 * \param c6: `C6 *` Pointer to a C6 instance.
 */
void r3j000(int j2, int j3, C6 *c6);

/*! \brief C++ porting of R3JJR
 *
 * \param j2: `int`
 * \param j3: `int`
 * \param m2: `int`
 * \param m3: `int`
 * \param c6: `C6 *`
 */
void r3jjr(int j2, int j3, int m2, int m3, C6 *c6);

/*! \brief C++ porting of R3JMR
 *
 * \param j1: `int`
 * \param j2: `int`
 * \param j3: `int`
 * \param m1: `int`
 * \param c6: `C6 *`
 */
void r3jmr(int j1, int j2, int j3, int m1, C6 *c6);

/*! \brief C++ porting of RABA
 *
 * \param le: `int`
 * \param am0m: Matrix of complex.
 * \param w: Matrix of complex.
 * \param tqce: `double **`
 * \param tqcpe: Matrix of complex.
 * \param tqcs: `double **`
 * \param tqcps: Matrix of complex.
 */
void raba(
	  int le, std::complex<double> **am0m, std::complex<double> **w, double **tqce,
	  std::complex<double> **tqcpe, double **tqcs, std::complex<double> **tqcps
);

/*! \brief C++ porting of RFTR
 *
 * \param u: `double *`
 * \param up: `double *`
 * \param un: `double *`
 * \param gapv: `double *`
 * \param extins: `double`
 * \param scatts: `double`
 * \param rapr: `double &`
 * \param cosav: `double &`
 * \param fp: `double &`
 * \param fn: `double &`
 * \param fk: `double &`
 * \param fx: `double &`
 * \param fy: `double &`
 * \param fz: `double &`
 */
void rftr(
	  double *u, double *up, double *un, double *gapv, double extins, double scatts,
	  double &rapr, double &cosav, double &fp, double &fn, double &fk, double &fx,
	  double &fy, double &fz
);

/*! \brief C++ porting of SCR0
 *
 * \param vk: `double` Wave number
 * \param exri: `double` External medium refractive index.
 * \param c1: `C1 *` Pointer to a C1 instance.
 * \param c1ao: `C1_AddOns *` Pointer to C1_AddOns instance.
 * \param c3: `C3 *` Pointer to a C3 instance.
 * \param c4: `C4 *` Pointer to a C4 structure.
 */
void scr0(double vk, double exri, C1 *c1, C1_AddOns *c1ao, C3 *c3, C4 * c4);

/*! \brief C++ porting of SCR2
 *
 * \param vk: `double` Wave number.
 * \param vkarg: `double` QUESTION: definition?
 * \param exri: `double` External medium refractive index.
 * \param duk: `double *` QUESTION: definition?
 * \param c1: `C1 *` Pointer to a C1 instance.
 * \param c1ao: `C1_AddOns *` Pointer to C1_AddOns instance.
 * \param c3: `C3 *` Pointer to a C3 instance.
 * \param c4: `C4 *` Pointer to a C4 structure.
 */
void scr2(
	  double vk, double vkarg, double exri, double *duk, C1 *c1, C1_AddOns *c1ao,
	  C3 *c3, C4 *c4
);

/*! \brief C++ porting of STR
 *
 * \param rcf: `double **` Matrix of double.
 * \param c1: `C1 *` Pointer to a C1 instance.
 * \param c1ao: `C1_AddOns *` Pointer to C1_AddOns instance.
 * \param c3: `C3 *` Pointer to a C3 instance.
 * \param c4: `C4 *` Pointer to a C4 structure.
 * \param c6: `C6 *` Pointer to a C6 instance.
 */
void str(double **rcf, C1 *c1, C1_AddOns *c1ao, C3 *c3, C4 *c4, C6 *c6);

/*! \brief C++ porting of TQR
 *
 * \param u: `double *`
 * \param up: `double *`
 * \param un: `double *`
 * \param tqev: `double *`
 * \param tqsv: `double *`
 * \param tep: `double &`
 * \param ten: `double &`
 * \param tek: `double &`
 * \param tsp: `double &`
 * \param tsn: `double &`
 * \param tsk: `double &`
 */
void tqr(
	 double *u, double *up, double *un, double *tqev, double *tqsv, double &tep,
	 double &ten, double &tek, double &tsp, double &tsn, double &tsk
);

/*! \brief C++ porting of ZTM
 *
 * \param am: Matrix of complex.
 * \param c1: `C1 *` Pointer to a C1 instance.
 * \param c1ao: `C1_AddOns *` Pointer to C1_AddOns instance.
 * \param c4: `C4 *` Pointer to a C4 structure.
 * \param c6: `C6 *` Pointer to a C6 instance.
 * \param c9: `C9 *` Pointer to a C9 instance.
 */
void ztm(std::complex<double> **am, C1 *c1, C1_AddOns *c1ao, C4 *c4, C6 *c6, C9 * c9);

#endif
