/*! \file Commons.h
 *
 * \brief C++ porting of common data structures.
 *
 * Many functions of the original FORTRAN code share complex data blocks in
 * form of COMMON blocks. This poses the limit of freezing the structure of
 * the data blocks in the code, therefore implying the necessity to modify
 * the code to adapt it to the input and to recompile before running. C++,
 * on the contrary, offers the possibility to represent the necessary data
 * structures as classes that can dynamically instantiate the shared information
 * in the most convenient format for the current configuration. This approach
 * adds an abstraction layer that lifts the need to modify and recompile the
 * code depending on the input.
 *
 */

#ifndef INCLUDE_COMMONS_H_
#define INCLUDE_COMMONS_H_

/*! \brief Representation of the FORTRAN C1 common blocks.
 *
 * C1 common blocks are used to store vector field expansions and geometric
 * properties, such as sphere sizes, positions and cross-sections. These are
 * used by functions such as `aps`, `diel`, `pwma`, `rabas`, `sscr0`, `sscr2`,
 * `wmamp`, `wmasp` and `dme`. QUESTION: correct?
 *
 * Due to the necessity to share the class contents with many functions that
 * need to read and update various fields, all shared members of C1 are declared
 * public (i.e., the class is just a structure with more advanced constructor
 * and destroyer). Further development may go in the direction of creating
 * a better encapsulation, either by unpacking the contents (recommended) or
 * by creating public methods to access protected fields (standard way, but not
 * recommended for HPC applications).
 */
class C1 {
protected:
	//! \brief Number of spheres.
	int nsph;
	//! \brief Maximum order of field expansion.
	int lm;
	//! \brief NLMMT. QUESTION: definition?
	int nlmmt;
public:
	//! \brief QUESTION: definition?
	std::complex<double> **rmi;
	//! \brief QUESTION: definition?
	std::complex<double> **rei;
	//! \brief QUESTION: definition?
	std::complex<double> **w;
	//! \brief QUESTION: definition?
	std::complex<double> *fsas;
	//! \brief QUESTION: definition?
	std::complex<double> **vints;
	//! \brief QUESTION: definition?
	double *sscs;
	//! \brief QUESTION: definition?
	double *sexs;
	//! \brief QUESTION: definition?
	double *sabs;
	//! \brief QUESTION: definition?
	double *sqscs;
	//! \brief QUESTION: definition?
	double *sqexs;
	//! \brief QUESTION: definition?
	double *sqabs;
	//! \brief QUESTION: definition?
	double *gcsv;
	//! \brief Vector of sphere X coordinates.
	double *rxx;
	//! \brief Vector of sphere X coordinates.
	double *ryy;
	//! \brief Vector of sphere X coordinates.
	double *rzz;
	//! \brief Vector of sphere radii.
	double *ros;
	//! \brief Matrix of spherical layer break radii. QUESTION: correct?
	double **rc;
	//! \brief Vector of spherical component identifiers.
	int *iog;
	//! \brief Vector of numbers of spherical layers.
	int *nshl;
	//! \brief QUESTION: definition?
	std::complex<double> ***sas;

	/*! \brief C1 instance constructor.
	 *
	 * \param ns: `int` Number of spheres.
	 * \param l_max: `int` Maximum order of field expansion.
	 * \param nshl: `int *` Array of number of layers in spheres.
	 * \param iog: `int *` Vector of spherical units ID numbers.
	 */
	C1(int ns, int l_max, int *nshl, int *iog);

	//! \brief C1 instance destroyer.
	~C1();
};

/*! \brief Representation of the FORTRAN C2 blocks.
 *
 */
class C2 {
	//! \brief Number of spheres.
	int nsph;
	//! \brief Number of required orders.
	int nhspo;
public:
	//! \brief QUESTION: definition?
	std::complex<double> *ris;
	//! \brief QUESTION: definition?
	std::complex<double> *dlri;
	//! \brief QUESTION: definition?
	std::complex<double> *dc0;
	//! \brief QUESTION: definition?
	std::complex<double> *vkt;
	//! Vector of scaled sizes. QUESTION: correct?
	double *vsz;

	/*! \brief C2 instance constructor.
	 *
	 * \param ns: `int` Number of spheres.
	 * \param nl: `int`
	 * \param npnt: `int`
	 * \param npntts: `int`
	 */
	C2(int ns, int nl, int npnt, int npntts);

	//! \brief C2 instance destroyer.
	~C2();
};

/*! \brief Representation of the FORTRAN C3 blocks.
 */
class C3 {
public:
	//! \brief QUESTION: definition?
	std::complex<double> tfsas;
	//! \brief QUESTION: definition?
	std::complex<double> **tsas;
	//! \brief QUESTION: definition?
	double gcs;
	//! \brief QUESTION: definition?
	double scs;
	//! \brief QUESTION: definition?
	double ecs;
	//! \brief QUESTION: definition?
	double acs;

	/*! \brief C3 instance constructor.
	 */
	C3();

	/*! \brief C3 instance destroyer.
	 */
	~C3();
};

/*! \brief Representation of the FORTRAN C4 blocks.
 */
struct C4 {
	//! \brief QUESTION: definition?
	int litpo;
	//! \brief QUESTION: definition?
	int litpos;
	//! \brief Maximum field expansion order plus one. QUESTION: correct?
	int lmpo;
	//! \brief Twice maximum field expansion order plus one. QUESTION: correct?
	int lmtpo;
	//! \brief Square of `lmtpo`.
	int lmtpos;
	//! \brief QUESTION: definition?
	int li;
	//! \brief QUESTION: definition?
	int nlim;
	//! \brief QUESTION: definition?
	int le;
	//! \brief QUESTION: definition?
	int nlem;
	//! \brief Maximum field expansion order. QUESTION: correct?
	int lm;
	//! \brief Number of spheres.
	int nsph;
	//! \brief QUESTION: definition?
	int nv3j;
};

/*! \brief Vectors and matrices that are specific to cluster C1 blocks.
 *
 */
class C1_AddOns {
protected:
	//! \brief Number of spheres.
	int nsph;
	//! \brief QUESTION: definition?
	int nlemt;
	//! \brief Maximum expansion order plus one. QUESTION: correct?
	int lmpo;

	/*! \brief Allocate the necessary common vectors depending on configuration.
	 *
	 * The size of the vectors and matrices defined in various common
	 * blocks, and particularly in C1, depends on many settings of the
	 * problem configuration, such as the number of spheres, the number
	 * of layers the spheres are made of, the field expansion order and
	 * others. This function collects the calculations needed to infer
	 * the necessary amount of memory for these configurable elements,
	 * thus making the class constructor more compact and easier to handle.
	 *
	 * \param c4: `C4 *` Pointer to a C4 structure.
	 */
	void allocate_vectors(C4 *c4);
public:
	//! \brief QUESTION: definition?
	std::complex<double> *vh;
	//! \brief QUESTION: definition?
	std::complex<double> *vj0;
	//! \brief QUESTION: definition?
	std::complex<double> *vj;
	//! \brief QUESTION: definition?
	std::complex<double> *vyhj;
	//! \brief QUESTION: definition?
	std::complex<double> *vyj0;
	//! \brief QUESTION: definition?
	std::complex<double> **am0m;
	//! \brief QUESTION: definition?
	std::complex<double> *vint;
	//! \brief QUESTION: definition?
	std::complex<double> *vintm;
	//! \brief QUESTION: definition?
	std::complex<double> **vints;
	//! \brief QUESTION: definition?
	std::complex<double> *vintt;
	//! \brief QUESTION: definition?
	std::complex<double> **fsac;
	//! \brief QUESTION: definition?
	std::complex<double> **sac;
	//! \brief QUESTION: definition?
	std::complex<double> **fsacm;
	//! \brief QUESTION: definition?
	double *scsc;
	//! \brief QUESTION: definition?
	std::complex<double> *scscp;
	//! \brief QUESTION: definition?
	double *ecsc;
	//! \brief QUESTION: definition?
	double *ecscm;
	//! \brief QUESTION: definition?
	double *scscm;
	//! \brief QUESTION: definition?
	std::complex<double> *ecscp;
	//! \brief QUESTION: definition?
	std::complex<double> *scscpm;
	//! \brief QUESTION: definition?
	std::complex<double> *ecscpm;
	//! \brief QUESTION: definition?
	double *v3j0;
	//! \brief QUESTION: definition?
	double *sscs;
	//! \brief QUESTION: definition?
	int **ind3j;

	/*! \brief C1_AddOns instance constructor.
	 *
	 * \param c4: `C4 *` Pointer to a C4 structure.
	 */
	C1_AddOns(C4 *c4);

	//! \brief C1_AddOns instance destroyer.
	~C1_AddOns();
};

/*! \brief Representation of the FORTRAN C6 blocks.
 */
class C6 {
public:
	//! \brief QUESTION: definition?
	double *rac3j;

	/*! \brief C6 instance constructor.
	 *
	 * \param lmtpo: `int` QUESTION: definition?
	 */
	C6(int lmtpo);

	/*! \brief C6 instance destroyer.
	 */
	~C6();
};

/*! \brief Representation of the FORTRAN C9 blocks.
 */
class C9 {
protected:
	//! \brief Number of rows in the GIS and GLS matrices
	int gis_size_0;
	//! \brief Number of rows in the SAM matrix
	int sam_size_0;
public:
	//! \brief QUESTION: definition?
	std::complex<double> **gis;
	//! \brief QUESTION: definition?
	std::complex<double> **gls;
	//! \brief QUESTION: definition?
	std::complex<double> **sam;

	/*! \brief C9 instance constructor.
	 *
	 * \param ndi: `int` QUESTION: definition?
	 * \param nlem: `int` QUESTION: definition?
	 * \param ndit: `int` QUESTION: definition?
	 * \param nlemt: `int` QUESTION: definition?
	 */
	C9(int ndi, int nlem, int ndit, int nlemt);

	/*! \brief C9 instance destroyer.
	 */
	~C9();
};
#endif
