#ifndef VECTOR_COMPLEX_TOOL
#define VECTOR_COMPLEX_TOOL

#include <complex>

#include "gsl/gsl_complex.h"
#include "gsl/gsl_complex_math.h"
#include "gsl/gsl_vector.h"
#include "gsl/gsl_vector_double.h"
#include "gsl/gsl_vector_complex.h"
#include "gsl/gsl_vector_complex_double.h"

#include "Header.hh"

#include "AdvMessage.hh"

/** Tools for complex-type vectors.
 *  creation, initialzation, type conversion
 *
 *  @author TANIMORI Souichirou, AdvanceSoft Corp.
 *  @version 0.0
 *  @since   0.8
 */
class AdvVectorComplexTool : public AdvMessage {
    private:
        static const string className; // = string("AdvVectorComplexTool");

    public:
        enum Part {
            REAL, /** the symbol for real      part of complex */
            IMAG, /** the symbol for imagenary prat of complex */
        };

    private:
        /** check source.
         *  @param[in] src  the pointer to the source array
         *  @param[in] size the size of the source array
         *  @retval true  when src &ne; NULL and size &gt; 0
         *  @retval false otherwize
         */
        Bool checkSrc(const Double* src, const UInt4 size);

        /** check source.
         *  @param[in] src  the reference to a source vector
         *  @retval true  if src is not empty.
         *  @retval false otherwise
         */
        Bool checkSrc(const vector<Double>& src);

        /** check source.
         *  @param[in] src  the pointer to a gsl_vector.
         *  @retval true  if src &new; NULL and the size of src is lagerer than 0
         *  @retval false otherwize
         */
        Bool checkSrc(const gsl_vector* src);

        /** check source.
         *  @param[in] real the pointer to an array as the real      part
         *  @param[in] imag the pointer to an array as the imagenary part
         *  @retval true  if real &ne; NULL, imag &ne NULL, real&rarr;size > 0, imag&rarr;size and real&rarr;size &eq; imag&rarr;size
         *  @retval false otherwize
         */
        Bool checkSrc(const Double* real, const Double* imag, const UInt4 size);

        /** check source.
         *  @param[in] real the reference to an array as the real      part of complex numbers
         *  @param[in] imag the reference to an array as the imagenary part of complex numbers
         *  @retval true  when ! real.empty() and ! image.empty() and real.size() == image.size()
         *  @retval false otherwise
         */
        Bool checkSrc(const vector<Double>& real, const vector<Double>& imag);

        /** check source.
         *  @param[in] real  the pointer to a gs_vector as the real      part
         *  @param[in] imag  the pointer to a gs_vector as the imagenary part
         *  @retval true  when real &ne NULL and imag &ne;  and real&rarr;size == imag&rarr;size
         *  @retval false otherwise
         */
        Bool checkSrc(const gsl_vector* real, const gsl_vector* imag);

        /** check the destination.
         *  @param[in] dest    the pointer of a gsl_vector_complex
         *  @param[in] srcSize the size of the souce
         *  @retval true  if dest &ne; NULL and dest &rarr size &eq; srcSize
         *  @retval false otherwise
         */
        Bool checkDest(gsl_vector_complex* dest, const UInt4 srcSize);

        /** check the destirnation.
         *  @param[in] dest    the reference of a complex number type vector
         *  @param[in] srcSize the size of the souce
         *  @retval true  if the capacity of dest &eq; srcSize
         *  @retval false otherwise
         */
        Bool checkDest(vector< complex<Double> >& dest, const UInt4 srcSize);

        /** check the destirnation.
         *  @param[in] dest    the pointer to a comlex number type array
         *  @param[in] srcSize the size of the souce
         *  @retval true  if the capacity of dest &eq; srcSize
         *  @retval false otherwise
         */
        Bool checkDest(complex<Double>* dest, const UInt4 srcSize);

        Bool checkSrc(const gsl_vector_complex* src);
        Bool checkSrc(const complex<Double>* src, const UInt4 size);
        Bool checkSrc(const vector< complex<Double> >& src);

    public:
        /** constructor */
        AdvVectorComplexTool() {};

        /** constructor */
        virtual ~AdvVectorComplexTool() {};

        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        /** initialise a vector.
         *  @param[in] part part to be initialized, REAL or IMAG
         *  @param[in] src  the pointer to a source array
         *  @param[in] size the size of the array
         *  @param[in] dest destination vector
         */
        void initGslVectorComplex(const enum Part part, const Double *src, const UInt4 size, gsl_vector_complex* dest);

        /** initialise a vector.
         *  @param[in] part part to be initialized, REAL or IMAG
         *  @param[in] src  a source vector
         *  @param[in] dest destination vector
         */
        void initGslVectorComplex(const enum Part part, const vector<Double>& src, gsl_vector_complex* dest);

        /** initialise a vector.
         *  @param[in] part part to be initialized, REAL or IMAG
         *  @param[in] src  the pointer to a source array
         *  @param[in] dest destination vector
         */
        void initGslVectorComplex(const enum Part part, const gsl_vector* src, gsl_vector_complex* dest);


        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        /** create a complex-type vactor from a Double array .
         *  @param[in] part part to be initialized, REAL or IMAG
         *  @param[in] src  the pointer to an array
         *  @param[in] size the size of the array
         *  @retval the pointer to a new vector if src is not NULL and size is larger than 0
         *  @retval NULL, otherwise
         */
        gsl_vector_complex* createGslVectorComplex(const enum Part part, const Double* src, const UInt4 size);

        /** create a complex-type vector from a Double vector.
         *  @param[in] part the part of a complex vector to be initialized, REAL or IMAG
         *  @param[in] src  a real-type vector
         *  @retval the pointer to a new vector if src is not empty
         *  @retval NULL, otherwise
         */
        gsl_vector_complex* createGslVectorComplex(const enum Part part, const vector<Double>& src);

        /** create a complex-type vector from a Double vector.
         *  @param[in] part part to be initialized, REAL or IMAG
         *  @param[in] src  a real-type vector
         *  @retval the pointer to the created vector if src is not NULL and not empty
         *  @retval NULL, otherwise
         */
        gsl_vector_complex* createGslVectorComplex(const enum Part part, const gsl_vector* src);

        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        /** initialize a complex vector.
         *  @param[in]  real the pointer to an array as real part
         *  @param[in]  imag the pointer to an array as imagenary part
         *  @param[in]  size the size of the arrays
         *  @param[out] dest the pointer to a vector to be initializeed.
         */
        void initGslVectorComplex(const Double* real, const Double* imag, const UInt4 size, gsl_vector_complex* dest);

        /** initialize a complex vector.
         *  @param[in] real a vector as the real part
         *  @param[in] imag a vector as the imagenary part
         *  @param[out] dest the pointer to a vector to be initializeed.
         */
        void initGslVectorComplex(const vector<Double>& real, const vector<Double>& imag, gsl_vector_complex* dest);

        /** initiallze a complex vector.
         *  @param[in] real a vector as the real part
         *  @param[in] imag a vector as the imagenary part
         *  @param[out] dest the pointer to a vector to be initializeed.
         */
        void initGslVectorComplex(const gsl_vector* real, const gsl_vector* imag, gsl_vector_complex* dest);

        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        /** create complex-type vector from two Double array, one is the real part and another is the imagenary part.
         *  @param[in] real the pointer to an array as real part
         *  @param[in] imag the pointer to an array as imagenary part
         *  @param[in] size the size of the arrays
         *  @retval the pointer to a gsl_vector_complex type vector if the both of real and imag are not NULL and size is larger than 0
         *  @retval NULL, otherwise
         */
        gsl_vector_complex* createGslVectorComplex(const Double* real, const Double* imag, const UInt4 size);

        /** create a complex-type vector from two vector.
         *  @param[in] real a vector as the real part
         *  @param[in] imag a vector as the imagenary part
         *  @retval the pointer to a gsl_vector_complex type vector if the both of real and imag are not empty
         *  @retval NULL, otherwise
         */
        gsl_vector_complex* createGslVectorComplex(const vector<Double>& real, const vector<Double>& imag);

        /** create a compex-type vector from two vector.
         *  @param[in] real a vector as the real part
         *  @param[in] imag a vector as the imagenary part
         *  @retval the pointer to a complex vector if the both of real and imag are not NULL and not empty
         *  @retval NULL, otherwise
         */
        gsl_vector_complex* createGslVectorComplex(const gsl_vector* real, const gsl_vector* imag);

        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        /** initialize a complex vector.
         *  @param[in]  part part to be initialized, REAL or IMAG
         *  @param[in]  src  the pointer to an array
         *  @param[in]  size the size of the array
         *  @param[out] dest the pointer to a vector to be initiailzed
         */
        void initVectorComplex(const enum Part part, const Double* src, const UInt4 size, vector< complex<Double> >& dest);

        /** initialize a complex vector.
         *  @param[in]  part part to be initialized, REAL or IMAG
         *  @param[in]  src  a real-type vector
         *  @param[out] dest the pointer to a vector to be initiailzed
         */
        void initVectorComplex(const enum Part part, const vector<Double>& src, vector< complex<Double> >& dest);

        /** initialize a complex vector.
         *  @param[in]  part part to be initialized, REAL or IMAG
         *  @param[in]  src  a real-type vector
         *  @param[out] dest the pointer to a vector to be initiailzed
         */
        void initVectorComplex(const enum Part part, const gsl_vector* src, vector< complex<Double> >& dest);

        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        /** create a complex vector from a real-tyoe vector.
         *  @param[in] part part to be initialized, REAL or IMAG
         *  @param[in] src    the pointer to an array
         *  @param[in] size the size of the array
         *  @retval the pointer to a vector< complex<Double> > type vector if src is not NULL and the size of src is larger than 0
         *  @retval NULL, otherwise
         */
        vector< complex<Double> >* createVectorComplex(const enum Part part, const Double* src, const UInt4 size);

        /** create a complex vector from a real-type vector.
         *  @param[in] part part to be initialized, REAL or IMAG
         *  @param[in] src    a real-type vector
         *  @retval the pointer to a vector< complex<Double> > type vector if src is not empty
         *  @retval NULL, otherwise
         */
        vector< complex<Double> >* createVectorComplex(const enum Part part, const vector<Double>& src);

        /** create a complex vector from a real-type vector.
         *  @param[in] part part to be initialized, REAL or IMAG
         *  @param[in] src  a real-type vector
         *  @retval the pointer to a vector< complex<Double> > type vector if src is not NULL and not empty
         *  @retval NULL, otherwise
         */
        vector< complex<Double> >* createVectorComplex(const enum Part part, const gsl_vector* src);

        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        /** initialze a complex array.
         */
        void initVectorComplex(const Double* real, const Double* imag, const UInt4 size, vector< complex<Double> >& dest);
        void initVectorComplex(const vector<Double>& real, const vector<Double>& imag, vector< complex<Double> >& dest);
        void initVectorComplex(const gsl_vector* real, const gsl_vector* imag, vector< complex<Double> >& dest);

        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        /** create a complex vector from two real-type vector.
         *  @param[in] real the pointer to an array as real part
         *  @param[in] imag the pointer to an array as imagenary part
         *  @param[in] size the size of the arrays
         *  @retval the pointer to a vector< complex<Double> > type vector if the both of real and imag are not NULL and size is larger than 0
         *  @retval NULL, otherwize
         */
        vector< complex<Double> >* createVectorComplex(const Double* real, const Double* imag, const UInt4 size);

        /** create a complex vector from two real-type vector.
         *  @param[in] real a vector as the real part
         *  @param[in] imag a vector as the imagenary part
         *  @retval the pointer to a vector< complex<Double> > type vector if the both of real and imag are not empty
         *  @retval NULL, otherwize
         */
        vector< complex<Double> >* createVectorComplex(const vector<Double>& real, const vector<Double>& imag);

        /** create a complex vector from two real-type vector.
         *  @param[in] real a vector as the real part
         *  @param[in] imag a vector as the imagenary part
         *  @retval the pointer to a vector< complex<Double> > vector if real and imag are not NULL and not empty
         *  @retval NULL, otherwise
         */
        vector< complex<Double> >* createVectorComplex(const gsl_vector*     real, const gsl_vector*     imag);

        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        void initArrayComplex(const enum Part part, const Double* src, const UInt4 size, complex<Double>* dest);
        void initArrayComplex(const enum Part part, const vector<Double>& src, complex<Double>* dest);
        void initArrayComplex(const enum Part part, const gsl_vector* src, complex<Double>* dest);

        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        /** create a complex array from a real-type vector.
         *  @param[in] part part to be initialized, REAL or IMAG
         *  @param[in] src  the pointer to an array
         *  @param[in] size the size of the array
         *  @retval the pointer to complex<Double> array if src is not NULL and the size of src is larger than 0
         *  @retval NULL, otherwise
         */
        complex<Double>* createArrayComplex(const enum Part part, const Double* src, const UInt4 size);

        /** create a complex array from a real-type vector.
         *  @param[in] part part to be initialized, REAL or IMAG
         *  @param[in] src  a real-type vector
         *  @retval the pointer to a complex<Double> array if src is not empty
         *  @retval NULL, otherwise
         */
        complex<Double>* createArrayComplex(const enum Part part, const vector<Double>& src);

        /** create a complex array from a real-type vector.
         *  @param[in] part part to be initialized, REAL or IMAG
         *  @param[in] src  a real-type vector
         *  @retval the pointer to a complex<Double> array if src is not NULL and not empty
         *  @retval NULL, otherwise
         */
        complex<Double>* createArrayComplex(const enum Part part, const gsl_vector* src);

        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        void initArrayComplex(const Double* real, const Double* imag, const UInt4 size, complex<Double>* dest);
        void initArrayComplex(const vector<Double>& real, const vector<Double>& imag, complex<Double>* dest);
        void initArrayComplex(const gsl_vector* real, const gsl_vector* imag, complex<Double>* dest);

        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        /** create a complex array from two real-type vector.
         *  @param[in] real the pointer to an array as real part
         *  @param[in] imag the pointer to an array as imagenary part
         *  @param[in] size the size of the arrays
         *  @retval the pointer to a complex<Double> array if the both of real and imag are not NULL and the size is larger than 0
         */
        complex<Double>* createArrayComplex(const Double* real, const Double* imag, const UInt4 size);

        /** create a complex array from two real-tyoe vector.
         *  @param[in] real a vector as the real part
         *  @param[in] imag a vector as the imagenary part
         *  @retval the pointer to a complex<Double> array if the both of real and imag are not empty
         *  @retval NULL, otherwize
         */
        complex<Double>* createArrayComplex(const vector<Double>& real, const vector<Double>& imag);

        /** create a complex array from two real-type array.
         *  @param[in] real a vector as the real part
         *  @param[in] imag a vector as the imagenary part
         *  @retval the pointer to a complex<Double> array if the both of real and imag are not NULL and not empty
         *  @retval NULL, otherwise
         */
        complex<Double>* createArrayComplex(const gsl_vector* real, const gsl_vector* imag);

        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        /** transform a vector to another type vector.
         *  @param[in] src a complex vector
         *  @retval the pointer to a gsl_vector_complex type vector if src is not empty
         *  @retval NULL, otherwise
         */
        gsl_vector_complex* VectorComplexToGslVectorComplex(const vector< complex<Double> >& src);

        /** transfotm a vector to other type vector.
         *  @param[in] src a gsl_vector_complex
         *  @retval the pointer to a complex vector if src is not NULL and not empty
         *  @retval NULL, otherwise
         */
        vector< complex<Double> >* GslVectorComplexToVectorComplex(const gsl_vector_complex* src);

        /** transform an array to a vector.
         *  @param[in] src    a pointer to an array
         *  @param[in] size the size of v
         *  @retval a pointer to a vector if src is not NULL and the size of src is larger than 0
         *  @param  NULL, otherwise
         */
        gsl_vector_complex* ArrayComplexToGslVectorComplex(const complex<Double>* src, UInt4 size);

        /** transform a vector to an arry.
         *  @param[in] src  the pointer to a vector
         *  @retval a pointer to an array if src is not NULL and not empty
         *  @retval NULL, otherwise
         */
        complex<Double>* GslVectorComplexToArrayComplex(const gsl_vector_complex* src);

        /** transform an array to vector.
         *  @param[in] src    the pointer to an array
         *  @param[in] size the size of v
         *  @retval the pointer to a vector if src is not NULL and the size of src is larger than 0
         *  @retval NULL, otherwize
         */
        vector< complex<Double> >* ArrayComplexToVectorComplex(const complex<Double>* src, UInt4 size);

        /** transform a vector to an array.
         *  @param[in] src a vector
         *  @retval the pointer to an array if src is not empty
         *  @retval NULL, otherwise
         */
        complex<Double>* VectorComplexToArrayComplex(const vector< complex<Double> >& src);

        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        gsl_vector* getPartAsGslVector(const enum Part part, const gsl_vector_complex* src);
        gsl_vector* getPartAsGslVector(const enum Part part, complex<Double>* src, const UInt4 size);
        gsl_vector* getPartAsGslVector(const enum Part part, vector< complex<Double> >& src);
        
        Double* getPartAsArray(const enum Part part, const gsl_vector_complex* src);
        Double* getPartAsArray(const enum Part part, complex<Double>* src, const UInt4 size);
        Double* getPartAsArray(const enum Part part, vector< complex<Double> >& src);

        vector<Double>* getPartAsVector(const enum Part part, const gsl_vector_complex* src);
        vector<Double>* getPartAsVector(const enum Part part, complex<Double>* src, const UInt4 size);
        vector<Double>* getPartAsVector(const enum Part part, vector< complex<Double> >& src);
};
#endif // VECTOR_COMPLEX_TOOL
