// pch.cpp: 与预编译标头对应的源文件
#include "interface.h"


#define ROFFSETS 0
#define CINDICES 1
#define A_ROW 2
#define A_COL 3
#define A_REAL 4
#define A_IMAG 5
#define B_REAL 6
#define B_IMAG 7
#define OPT 8

void cootocsr_complex(int* coo_row, int* coo_col, double* coo_valr, double* coo_vali,
    int nnz, int rows, int cols, int* csr_rof, int* csr_cin, double* csr_valr, double* csr_vali);
void cootocsr(int* coo_row, int* coo_col, double* coo_val,
    int nnz, int rows, int cols, int* csr_rof, int* csr_cin, double* csr_val);

#define GET_ARRAY_LEN(array,len){len = _msize(array) / sizeof(*array);}

int WriteFile(double* data, int filetype, int numsize);
int WriteIntFile(int* data, int filetype, int numsize);
int ReadFile(double** data, char* name);
void DelFile(int filetype);
void DelNameFile(char* name);
// 当使用预编译的头时，需要使用此源文件，编译才能成功。

int solveRealLinearEqu(int* Roffsets, int* Cindices,
    double* A_real, double* b_real, double* x_real,
    int NbrDof, int Nzero ,double* para)
{
    /*opt:
        0：矩阵维度 1：预估数 2：对称性 3： 相对误差
        4：绝对误差 5：重启次数 6：预处理1 7：迭代1
        8：预处理2 9：迭代2 10：预处理3 11：迭代3
    */
    char model_name[40];
    int len;
    double opt[12];
    opt[0] = (double)NbrDof;
    opt[1] = para[0];   //预估数
    opt[2] = para[1];   //对称性
    opt[3] = para[2];   //相对误差
    opt[4] = para[3];   //绝对误差
    opt[5] = 30;

    if (para[5] == -1)  //  模型编号
    {
        opt[6] = -1;
        opt[7] = -1;
        opt[8] = -1;
        opt[9] = -1;
        opt[10] = -1;
        opt[11] = -1;
    }
    else
    {
        char model_name[50] = "./model_data/";
        char str[30];
        sprintf(str, "%d", (int)para[5]);
        strcat(model_name, str);
        strcat(model_name, ".txt");
        FILE* fp1 = fopen(model_name, "r"); //以data.txt文件为例
        int j = 0;

        fscanf(fp1, "%s\n", &model_name);

        while (!feof(fp1)) //feof（）检测一个文件是否结束，即到达文件尾，若结束，则返回非0值，否则返回0
        {
            fscanf(fp1, "%s\n", &str);
            opt[6 + j] = atoi(str);
            j++;
            if (j == 6)break;
        }
        fclose(fp1);
    }

    GET_ARRAY_LEN(Roffsets, len);
    WriteIntFile(Roffsets, ROFFSETS, len);
    WriteFile(b_real, B_REAL, len - 1);
    //printf("mat norf:%d\n", len);
    GET_ARRAY_LEN(Cindices, len);
    WriteIntFile(Cindices, CINDICES, len);
    WriteFile(A_real, A_REAL, len);
    WriteFile(opt, OPT, 12);
    //printf("mat nzero:%d\n", len);
    if (para[4] == 0)  //并行数量
        system(".\\real\\realsolver.exe");
    else if (para[4] == -1)
    {
        SYSTEM_INFO info;
        GetSystemInfo(&info);
        para[4] = (info.dwNumberOfProcessors / 2) - 2;

        char s_path[60] = ".\\mpi\\mpiexec.exe -n ";
        char str[3];
        sprintf(str, "%d", (int)para[4]);
        strcat(s_path, str);
        strcat(s_path, " .\\real\\realsolver.exe");
        system(s_path);
    }
    else
    {
        char s_path[60] = ".\\mpi\\mpiexec.exe -n ";
        char str[3];
        sprintf(str, "%d", (int)para[4]);
        strcat(s_path, str);
        strcat(s_path, " .\\real\\realsolver.exe");
        system(s_path);
    }

    double* x;
    int idex = 0, sum = 0;
    int mnum;
    if (para[4] == 0)mnum = 1;
    else mnum = para[4];
    for (int i = 0; i < mnum; i++)
    {
        char name[20] = "x_real_";
        char str[5] = { 0 };
        sprintf(str, "%d", i);
        strcat(name, str);
        strcat(name, ".dat");
        idex = ReadFile(&x, name);
        for (int j = 0; j < idex; j++)
        {
            x_real[sum++] = x[j];
        }
        DelNameFile(name);
    }
    DelFile(ROFFSETS);
    DelFile(CINDICES);
    DelFile(A_REAL);
    DelFile(B_REAL);
    DelFile(OPT);

    system("del res.dat");
    system("del log.dat");

    return 0;
}

int solveRealLinearEqu_COO(int* A_i, int* A_j,
    double* A_real, double* b_real, double* x_real,
    int NbrDof, int Nzero, double* para)
{
    int len;
    GET_ARRAY_LEN(A_real, len);
    int* Roffsets = (int*)malloc(sizeof(int) * (NbrDof + 1));
    int* Cindices = (int*)malloc(sizeof(int) * (len));
    double* A_real_csr = (double*)malloc(sizeof(double) * (len));
    cootocsr(A_i, A_j, A_real, len, NbrDof, NbrDof, Roffsets, Cindices, A_real_csr);
    solveRealLinearEqu(Roffsets, Cindices, A_real_csr, b_real, x_real, NbrDof, Nzero, para);
    return 0;
}

int solveComplexLinearEqu(int* Roffsets, int* Cindices,
    std::complex<double>* A_complex, std::complex<double>* b_complex, std::complex<double>* x_complex,
    int NbrDof, int Nzero, double* para)
{
    /*opt:
        0：矩阵维度 1：预估数 2：对称性 3： 相对误差
        4：绝对误差 5：重启次数 6：预处理1 7：迭代1
        8：预处理2 9：迭代2 10：预处理3 11：迭代3
    */
    char model_name[40];
    int len;
    double opt[12];
    opt[0] = (double)NbrDof;
    opt[1] = para[0];   //预估数
    opt[2] = para[1];   //对称性
    opt[3] = para[2];   //相对误差
    opt[4] = para[3];   //绝对误差

    opt[5] = 30;
    if (para[5] == -1)  //  模型编号
    {
        opt[6] = -1;
        opt[7] = -1;
        opt[8] = -1;
        opt[9] = -1;
        opt[10] = -1;
        opt[11] = -1;
    }
    else
    {
        char model_name[50] = "./model_data/";
        char str[30];
        sprintf(str, "%d", (int)para[5]);
        strcat(model_name, str);
        strcat(model_name, ".txt");
        FILE* fp1 = fopen(model_name, "r"); //以data.txt文件为例
        int j = 0;
        fscanf(fp1, "%s\n", &model_name);

        while (!feof(fp1)) //feof（）检测一个文件是否结束，即到达文件尾，若结束，则返回非0值，否则返回0
        {
            fscanf(fp1, "%s\n", &str);
            opt[6+j] = atoi(str);
            j++;
            if (j == 6)break;
        }
        fclose(fp1);
    }

    // 将complex数据写入double中
    double* A_real = new double[Nzero];
    double* A_imag = new double[Nzero];

    for (int i = 0; i < Nzero; ++i) {
        A_real[i] = A_complex[i].real();
        A_imag[i] = A_complex[i].imag();
    }

    double* b_real = new double[NbrDof];
    double* b_imag = new double[NbrDof];

    for (size_t i = 0; i < NbrDof; ++i) {
        b_real[i] = b_complex[i].real();
        b_imag[i] = b_complex[i].imag();
    }
    double* x_real = new double[NbrDof];
    double* x_imag = new double[NbrDof];

    GET_ARRAY_LEN(Roffsets, len);
    WriteIntFile(Roffsets, ROFFSETS, len);
    WriteFile(b_real, B_REAL, len - 1);
    WriteFile(b_imag, B_IMAG, len - 1);
    //printf("mat norf:%d\n", len);
    GET_ARRAY_LEN(Cindices, len);
    WriteIntFile(Cindices, CINDICES, len);
    WriteFile(A_real, A_REAL, len);
    WriteFile(A_imag, A_IMAG, len);
    WriteFile(opt, OPT, 12);
    //printf("mat nzero:%d\n", len);
    if (para[4] == 0)
        system(".\\complex\\complexsolver.exe");
    else if (para[4] == -1)
    {
        SYSTEM_INFO info;
        GetSystemInfo(&info);
        para[4] = (info.dwNumberOfProcessors / 2) - 2;

        char s_path[60] = ".\\mpi\\mpiexec.exe -n ";
        char str[3];
        sprintf(str, "%d", (int)para[4]);
        strcat(s_path, str);
        strcat(s_path, " .\\complex\\complexsolver.exe");
        system(s_path);
    }
    else
    {
        char s_path[60] = ".\\mpi\\mpiexec.exe -n ";
        char str[3];
        sprintf(str, "%d", (int)para[4]);
        strcat(s_path, str);
        strcat(s_path, " .\\complex\\complexsolver.exe");
        system(s_path);
    }

    double* a_real;
    double* a_complex;
    int idex = 0, realsum = 0, imagsum = 0;
    int mnum;
    if (para[4] == 0)mnum = 1;
    else mnum = para[4];
    for (int i = 0; i < mnum; i++)
    {
        char realname[20] = "x_real_";
        char complexname[20] = "x_complex_";
        char str[5] = { 0 };
        sprintf(str, "%d", i);
        strcat(realname, str);
        strcat(complexname, str);
        strcat(realname, ".dat");
        strcat(complexname, ".dat");
        idex = ReadFile(&a_real, realname);
        for (int j = 0; j < idex; j++)
        {
            x_real[realsum++] = a_real[j];
        }
        idex = ReadFile(&a_complex, complexname);
        for (int j = 0; j < idex; j++)
        {
            x_imag[imagsum++] = a_complex[j];
        }
        DelNameFile(realname);
        DelNameFile(complexname);
    }

    for (int i = 0; i < NbrDof; i++)
    {
        x_complex[i].real(x_real[i]);
        x_complex[i].imag(x_imag[i]);
    }

    DelFile(ROFFSETS);
    DelFile(CINDICES);
    DelFile(A_REAL);
    DelFile(A_IMAG);
    DelFile(B_REAL);
    DelFile(B_IMAG);
    DelFile(OPT);

    system("del res.dat");
    system("del log.dat");

    return 0;
}

int solveComplexLinearEqu_COO(int* A_i, int* A_j,
    double* A_real, double* A_imag, double* b_real, double* b_imag, double* x_real, double* x_imag,
    int NbrDof, double* para)
{
    int len;
    GET_ARRAY_LEN(A_real, len);
    int* Roffsets = (int*)malloc(sizeof(int)* (NbrDof+1));
    int* Cindices = (int*)malloc(sizeof(int) * (len));
    double* A_real_csr = (double*)malloc(sizeof(double) * (len));
    double* A_imag_csr = (double*)malloc(sizeof(double) * (len));
    cootocsr_complex(A_i, A_j, A_real, A_imag,len, NbrDof, NbrDof, Roffsets, Cindices, A_real_csr, A_imag_csr);
    //solveComplexLinearEqu(Roffsets, Cindices, A_real_csr, A_imag_csr, b_real, b_imag, x_real, x_imag, NbrDof, para);
    return 0;
}

int MumpsSolver_COO(int* A_i, int* A_j,
    double* A_real, double* A_imag, double* b_real, double* b_imag, double* x_real, double* x_imag,
    int NbrDof, int NNZ)
{
    int opt[2];
    opt[0] = NbrDof;
    opt[1] = NNZ;   //非零元总数

    WriteIntFile(A_i, A_ROW, NNZ);
    WriteIntFile(A_j, A_COL, NNZ);
    WriteFile(A_real, A_REAL, NNZ);
    WriteFile(A_imag, A_IMAG, NNZ);
    WriteFile(b_real, B_REAL, NbrDof);
    WriteFile(b_imag, B_IMAG, NbrDof);
    WriteIntFile(opt, OPT, 2);

    system(".\\mumps\\mumpssolver.exe");

    double* a_real;
    double* a_complex;
    int idex = 0, realsum = 0, imagsum = 0;
    int mnum = 1;
    for (int i = 0; i < mnum; i++)
    {
        char realname[20] = "x_real_";
        char complexname[20] = "x_complex_";
        char str[5] = { 0 };
        sprintf(str, "%d", i);
        strcat(realname, str);
        strcat(complexname, str);
        strcat(realname, ".dat");
        strcat(complexname, ".dat");
        idex = ReadFile(&a_real, realname);
        for (int j = 0; j < idex; j++)
        {
            x_real[realsum++] = a_real[j];
        }
        idex = ReadFile(&a_complex, complexname);
        for (int j = 0; j < idex; j++)
        {
            x_imag[imagsum++] = a_complex[j];
        }
        DelNameFile(realname);
        DelNameFile(complexname);
    }
    DelFile(A_ROW);
    DelFile(A_COL);
    DelFile(A_REAL);
    DelFile(A_IMAG);
    DelFile(B_REAL);
    DelFile(B_IMAG);
    DelFile(OPT);
    return 0;
}

const char* Interfacefilename[11] = { "Roffsets.dat", "Cindices.dat","A_row.dat", "A_col.dat", "A_real.dat","A_imag.dat", "B_real.dat", "B_imag.dat" ,"opt.dat","x_real_","x_complex_"};
int WriteFile(double* data, int filetype, int numsize)
{
    /*写出数据*/
    FILE* fid;
    fid = fopen(Interfacefilename[filetype], "wb");
    if (fid == NULL)
    {
        printf("写出文件出错");
        return 0;
    }

    fwrite(data, sizeof(double), numsize, fid);
    fclose(fid);
    return 0;

}

int WriteIntFile(int* data, int filetype, int numsize)
{
    /*写出数据*/
    FILE* fid;
    fid = fopen(Interfacefilename[filetype], "wb");
    if (fid == NULL)
    {
        printf("写出文件出错");
        return 0;
    }

    fwrite(data, sizeof(int), numsize, fid);
    fclose(fid);
    return 0;

}

int ReadFile(double** data, char* name)
{
    FILE* fid;
    fid = fopen(name, "rb");
    if (fid == NULL)
    {
        printf("读取文件出错");
        return -1;
    }
    //获取文件大小
    fseek(fid, 0, SEEK_END);
    long lSize = ftell(fid);
    rewind(fid);
    //开辟存储空间
    int num = lSize / sizeof(double);
    *data = (double*)malloc(sizeof(double) * num);
    if (*data == NULL)
    {
        printf("开辟空间出错");
        return -1;
    }
    fread(*data, sizeof(double), num, fid);

    //printf("%d\n", num);

    fclose(fid);
    return num;
}

void DelFile(int filetype)
{
    struct stat buffer;
    if (stat(Interfacefilename[filetype], &buffer) == 0)
    {
        char path1[40] = "del ";
        strcat(path1, Interfacefilename[filetype]);
        system(path1);
    }
}

void DelNameFile(char* name)
{
    struct stat buffer;
    if (stat(name, &buffer) == 0)
    {
        char path1[40] = "del ";
        strcat(path1, name);
        system(path1);
    }
}

void cootocsr_complex(int* coo_row, int* coo_col, double* coo_valr, double* coo_vali, 
    int nnz, int rows, int cols, int* csr_rof, int* csr_cin, double* csr_valr, double* csr_vali)
{
    memset(csr_rof, 0, (rows) * sizeof(int));

    for (int i = 0; i < nnz; i++)
    {
        csr_rof[coo_row[i]]++;
    }

    for (int i = 0, cumsum = 0; i < rows; i++) {
        int temp = csr_rof[i];
        csr_rof[i] = cumsum;
        cumsum += temp;
    }
    csr_rof[rows] = nnz;

    for (int n = 0; n < nnz; n++) {
        int row = coo_row[n];
        int dest = csr_rof[row];

        csr_cin[dest] = coo_col[n];
        csr_valr[dest] = coo_valr[n];
        csr_vali[dest] = coo_vali[n];

        csr_rof[row]++;
    }

    for (int i = 0, last = 0; i <= rows; i++) {
        int temp = csr_rof[i];
        csr_rof[i] = last;
        last = temp;
    }
}

void cootocsr(int* coo_row, int* coo_col, double* coo_val,
    int nnz, int rows, int cols, int* csr_rof, int* csr_cin, double* csr_val)
{
    memset(csr_rof, 0, (rows) * sizeof(int));

    for (int i = 0; i < nnz; i++)
    {
        csr_rof[coo_row[i]]++;
    }

    for (int i = 0, cumsum = 0; i < rows; i++) {
        int temp = csr_rof[i];
        csr_rof[i] = cumsum;
        cumsum += temp;
    }
    csr_rof[rows] = nnz;

    for (int n = 0; n < nnz; n++) {
        int row = coo_row[n];
        int dest = csr_rof[row];

        csr_cin[dest] = coo_col[n];
        csr_val[dest] = coo_val[n];

        csr_rof[row]++;
    }

    for (int i = 0, last = 0; i <= rows; i++) {
        int temp = csr_rof[i];
        csr_rof[i] = last;
        last = temp;
    }
}