#include <cstdlib>
#include <iostream>
#include <ostream>
#include <ios>
#include <iomanip>

#include "Header.hh"
#include "VectorGSLVectorConv.hh"

gsl_vector *initGSLVector(const size_t n) {
    gsl_vector *v=NULL;

    v=gsl_vector_alloc(n);
    for (size_t i=0; i<n; ++i) {
        gsl_vector_set(v, i, static_cast<Double>(i));
    }
    return v;
}

void vectorConversionTest(size_t n, VectorGSLVectorConv *conv) {

    gsl_vector     *v0=initGSLVector(n);
    vector<Double> *v1=conv->gslVectorToVector(v0);
    gsl_vector     *v2=conv->vectorToGSLVector(*v1);

    // column header
    std::cout << setw(5)  << setiosflags(std::ios::right) << "No.";
    std::cout << setw(1)  << " ";
    std::cout << setw(23) << setiosflags(std::ios::right) << "v0";
    std::cout << setw(1)  << " ";
    std::cout << setw(23) << setiosflags(std::ios::right) << "v1";
    std::cout << setw(1)  << " ";
    std::cout << setw(23) << setiosflags(std::ios::right) << "v2";
    std::cout << endl;

    for (size_t i=0; i<v0->size; ++i) {
        std::cout << setw(5)  << setiosflags(std::ios::right) << i;
        std::cout << setw(1)  << " ";
        std::cout << setw(23) << setprecision(15) << setiosflags(std::ios::right) << gsl_vector_get(v0, i);
        std::cout << setw(1)  << " ";
        std::cout << setw(23) << setprecision(15) << setiosflags(std::ios::right) << v1->at(i);
        std::cout << setw(1)  << " ";
        std::cout << setw(23) << setprecision(15) << setiosflags(std::ios::right) << gsl_vector_get(v2, i);
        std::cout << endl;
    }
    std::cout << endl;
}

gsl_matrix *initGSLMatrix(const size_t n) {
    gsl_matrix *m=gsl_matrix_alloc(n, n);

    for (size_t i=0; i<n; ++i) {
        for (size_t j=0; j<n; ++j) {
            gsl_matrix_set(m, i, j, static_cast<Double>(i+j));
        }
    }
    return m;
}

void matrixConversionTest(size_t n, VectorGSLVectorConv *conv) {
    gsl_matrix               *m0=initGSLMatrix(n);
    vector< vector<Double> > *m1=conv->gslMatrixToMatrix(m0);
    gsl_matrix               *m2=conv->matrixToGSLMatrix(*m1);

    // column header
    std::cout << setw(5)  << setiosflags(std::ios::right) << "No.";
    std::cout << setw(1)  << " ";
    std::cout << setw(5)  << setiosflags(std::ios::right) << "No.";
    std::cout << setw(1)  << " ";
    std::cout << setw(23) << setiosflags(std::ios::right) << "m0";
    std::cout << setw(1)  << " ";
    std::cout << setw(23) << setiosflags(std::ios::right) << "m1";
    std::cout << setw(1)  << " ";
    std::cout << setw(23) << setiosflags(std::ios::right) << "m2";
    std::cout << endl;

    for (size_t i=0; i<m0->size1; ++i) {
        for (size_t j=0; j<m0->size1; ++j) {
            std::cout << setw(5)  << setiosflags(std::ios::right) << i;
            std::cout << setw(1)  << " ";
            std::cout << setw(5)  << setiosflags(std::ios::right) << j;
            std::cout << setw(1)  << " ";
            std::cout << setw(23) << setprecision(15) << setiosflags(std::ios::right) << gsl_matrix_get(m0, i, j);
            std::cout << setw(1)  << " ";
            std::cout << setw(23) << setprecision(15) << setiosflags(std::ios::right) << m1->at(i).at(j);
            std::cout << setw(1)  << " ";
            std::cout << setw(23) << setprecision(15) << setiosflags(std::ios::right) << gsl_matrix_get(m2, i, j);
            std::cout << endl;
        }
    }
    std::cout << endl;
}

Int4 main (Int4 argc, Char *argv[]) {

    VectorGSLVectorConv *conv=new VectorGSLVectorConv();
    vectorConversionTest(5, conv);
    matrixConversionTest(5, conv);

    return EXIT_SUCCESS;
}
