#ifdef WITH_FEAST
#include "feast_wrapper.h"

// Must be treated as C to avoid name mangling
extern "C" {

#include <stdio.h>
#include <stdlib.h>

#include <feast.h>
#include <feast_dense.h>
#include <feast_sparse.h>

void feast_init_wrapper(int* fpm)
{
    feastinit(fpm);
}

void zfeast_heev_wrapper(FeastDenseArgs* args)
{
    // local variables
    char up_lo = 'F';
    int loop = 0;
    int info = 0;

    // call feast
    zfeast_heev(
        &up_lo,
        &(args->num_orb), // N
        args->hk, // matrix A
        &(args->num_orb), // LDA
        args->fpm,
        &(args->eps_out),
        &loop,
        &(args->e_min),
        &(args->e_max),
        &(args->subspace_size), // m0
        args->eig_val, // lambda
        args->eig_vec, // q
        &(args->num_states), // mode
        args->residual,
        &info);

    // Check status
    if (1 <= info && info <= 7) {
        printf("WARNING: zfeast_heev returned with info = %d\n", info);
    } else if (info != 0) {
        printf("ERROR: zfeast_heev exited with info = %d\n", info);
        exit(-1);
    }
}

void zfeast_hegv_wrapper(FeastDenseArgs* args)
{
    // local variables
    char up_lo = 'F';
    int loop = 0;
    int info = 0;

    // call feast
    zfeast_hegv(
        &up_lo,
        &(args->num_orb), // N
        args->hk, // matrix A
        &(args->num_orb), // LDA
        args->sk, // matrix B
        &(args->num_orb), // LDB
        args->fpm,
        &(args->eps_out),
        &loop,
        &(args->e_min),
        &(args->e_max),
        &(args->subspace_size), // m0
        args->eig_val, // lambda
        args->eig_vec, // q
        &(args->num_states), // mode
        args->residual,
        &info);

    // Check status
    if (1 <= info && info <= 7) {
        printf("WARNING: zfeast_hegv returned with info = %d\n", info);
    } else if (info != 0) {
        printf("ERROR: zfeast_hegv exited with info = %d\n", info);
        exit(-1);
    }
}

void zfeast_hcsrev_wrapper(FeastCsrArgs* args)
{
    // local variables
    char up_lo = 'F';
    int loop = 0;
    int info = 0;

    // call feast
    zfeast_hcsrev(
        &up_lo,
        &(args->num_orb), // N
        args->values_h, // sa
        args->indptr_h, // isa
        args->indices_h, // jsa
        args->fpm,
        &(args->eps_out),
        &loop,
        &(args->e_min),
        &(args->e_max),
        &(args->subspace_size), // m0
        args->eig_val, // lambda
        args->eig_vec, // q
        &(args->num_states), // mode
        args->residual,
        &info);

    // Check status
    if (1 <= info && info <= 7) {
        printf("WARNING: zfeast_hcsrev returned with info = %d\n", info);
    } else if (info != 0) {
        printf("ERROR: zfeast_hcsrev exited with info = %d\n", info);
        exit(-1);
    }
}

void zfeast_hcsrgv_wrapper(FeastCsrArgs* args)
{
    // local variables
    char up_lo = 'F';
    int loop = 0;
    int info = 0;

    // call feast
    zfeast_hcsrgv(
        &up_lo,
        &(args->num_orb), // N
        args->values_h, // sa
        args->indptr_h, // isa
        args->indices_h, // jsa
        args->values_s, // sb
        args->indptr_s, // isb
        args->indices_s, // jsb
        args->fpm,
        &(args->eps_out),
        &loop,
        &(args->e_min),
        &(args->e_max),
        &(args->subspace_size), // m0
        args->eig_val, // lambda
        args->eig_vec, // q
        &(args->num_states), // mode
        args->residual,
        &info);

    // Check status
    if (1 <= info && info <= 7) {
        printf("WARNING: zfeast_hcsrgv returned with info = %d\n", info);
    } else if (info != 0) {
        printf("ERROR: zfeast_hcsrgv exited with info = %d\n", info);
        exit(-1);
    }
}

} // extern "C"
#endif // WITH_FEAST