/*
 * Copyright (C) by Argonne National Laboratory
 *     See COPYRIGHT in top-level directory
 */

/*
 * This file contains a simple PMI-based implementation of the name server routines.
 */

#include "mpiimpl.h"
#include "namepub.h"

/* style: allow:fprintf:1 sig:0 */
/* For writing the name/service pair */

/* Define the name service handle */
#define MPID_MAX_NAMEPUB 64
struct MPID_NS_Handle {
    int dummy;
};                              /* unused for now */

int MPID_NS_Create(const MPIR_Info * info_ptr, MPID_NS_Handle * handle_ptr)
{
    static struct MPID_NS_Handle nsHandleWithNoData;

    MPL_UNREFERENCED_ARG(info_ptr);
    /* MPID_NS_Create() should always create a valid handle */
    *handle_ptr = &nsHandleWithNoData;  /* The name service needs no local data */
    return 0;
}

int MPID_NS_Publish(MPID_NS_Handle handle, const MPIR_Info * info_ptr,
                    const char service_name[], const char port[])
{
    int mpi_errno = MPI_SUCCESS;
    int rc;
    MPL_UNREFERENCED_ARG(info_ptr);
    MPL_UNREFERENCED_ARG(handle);

#ifdef USE_PMI2_API
    /* release the global CS for PMI calls */
    MPID_THREAD_CS_EXIT(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX);
    rc = PMI2_Nameserv_publish(service_name, info_ptr, port);
    MPID_THREAD_CS_ENTER(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX);
#elif defined(USE_PMIX_API)
    MPIR_Assert(0);
#else
    rc = PMI_Publish_name(service_name, port);
#endif
    MPIR_ERR_CHKANDJUMP1(rc, mpi_errno, MPI_ERR_NAME, "**namepubnotpub", "**namepubnotpub %s",
                         service_name);

  fn_fail:
    return mpi_errno;
}

int MPID_NS_Lookup(MPID_NS_Handle handle, const MPIR_Info * info_ptr,
                   const char service_name[], char port[])
{
    int mpi_errno = MPI_SUCCESS;
    int rc;
    MPL_UNREFERENCED_ARG(info_ptr);
    MPL_UNREFERENCED_ARG(handle);

#ifdef USE_PMI2_API
    /* release the global CS for PMI calls */
    MPID_THREAD_CS_EXIT(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX);
    rc = PMI2_Nameserv_lookup(service_name, info_ptr, port, MPI_MAX_PORT_NAME);
    MPID_THREAD_CS_ENTER(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX);
#elif defined(USE_PMIX_API)
    MPIR_Assert(0);
#else
    rc = PMI_Lookup_name(service_name, port);
#endif
    MPIR_ERR_CHKANDJUMP1(rc, mpi_errno, MPI_ERR_NAME, "**namepubnotfound", "**namepubnotfound %s",
                         service_name);

  fn_fail:
    return mpi_errno;
}

int MPID_NS_Unpublish(MPID_NS_Handle handle, const MPIR_Info * info_ptr, const char service_name[])
{
    int mpi_errno = MPI_SUCCESS;
    int rc;
    MPL_UNREFERENCED_ARG(info_ptr);
    MPL_UNREFERENCED_ARG(handle);

#ifdef USE_PMI2_API
    /* release the global CS for PMI calls */
    MPID_THREAD_CS_EXIT(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX);
    rc = PMI2_Nameserv_unpublish(service_name, info_ptr);
    MPID_THREAD_CS_ENTER(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX);
#elif defined(USE_PMIX_API)
    MPIR_Assert(0);
#else
    rc = PMI_Unpublish_name(service_name);
#endif
    MPIR_ERR_CHKANDJUMP1(rc, mpi_errno, MPI_ERR_SERVICE, "**namepubnotunpub",
                         "**namepubnotunpub %s", service_name);

  fn_fail:
    return mpi_errno;
}

int MPID_NS_Free(MPID_NS_Handle * handle_ptr)
{
    /* MPID_NS_Handle is Null */
    MPL_UNREFERENCED_ARG(handle_ptr);
    return 0;
}

#if 0
/* PMI_Put/Get version */

/*
 * This file contains a simple implementation of the name server routines,
 * using the PMI interface.
 */
#include "mpiimpl.h"
#include "namepub.h"
#include "pmi.h"

/* Define the name service handle */
struct MPID_NS_Handle {
    char *kvsname;
};

int MPID_NS_Create(const MPIR_Info * info_ptr, MPID_NS_Handle * handle_ptr)
{
    int err;
    int length;
    char *pmi_namepub_kvs;

    *handle_ptr = (MPID_NS_Handle) MPL_malloc(sizeof(struct MPID_NS_Handle));
    /* --BEGIN ERROR HANDLING-- */
    if (!*handle_ptr) {
        err =
            MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, __func__, __LINE__,
                                 MPI_ERR_OTHER, "**nomem", 0);
        return err;
    }
    /* --END ERROR HANDLING-- */

    err = PMI_KVS_Get_name_length_max(&length);
    /* --BEGIN ERROR HANDLING-- */
    if (err != PMI_SUCCESS) {
        err =
            MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, __func__, __LINE__,
                                 MPI_ERR_OTHER, "**fail", 0);
    }
    /* --END ERROR HANDLING-- */

    (*handle_ptr)->kvsname = (char *) MPL_malloc(length);
    /* --BEGIN ERROR HANDLING-- */
    if (!(*handle_ptr)->kvsname) {
        err =
            MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, __func__, __LINE__,
                                 MPI_ERR_OTHER, "**nomem", 0);
        return err;
    }
    /* --END ERROR HANDLING-- */

    pmi_namepub_kvs = getenv("PMI_NAMEPUB_KVS");
    if (pmi_namepub_kvs) {
        MPL_strncpy((*handle_ptr)->kvsname, pmi_namepub_kvs, length);
    } else {
        err = PMI_KVS_Get_my_name((*handle_ptr)->kvsname, length);
        /* --BEGIN ERROR HANDLING-- */
        if (err != PMI_SUCCESS) {
            err =
                MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, __func__, __LINE__,
                                     MPI_ERR_OTHER, "**fail", 0);
        }
        /* --END ERROR HANDLING-- */
    }

    /*printf("namepub kvs: <%s>\n", (*handle_ptr)->kvsname);fflush(stdout); */
    return 0;
}

int MPID_NS_Publish(MPID_NS_Handle handle, const MPIR_Info * info_ptr,
                    const char service_name[], const char port[])
{
    int err;

    /*printf("publish kvs: <%s>\n", handle->kvsname);fflush(stdout); */
    err = PMI_KVS_Put(handle->kvsname, service_name, port);
    /* --BEGIN ERROR HANDLING-- */
    if (err != PMI_SUCCESS) {
        err =
            MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, __func__, __LINE__,
                                 MPI_ERR_OTHER, "**pmi_kvs_put", 0);
        return err;
    }
    /* --END ERROR HANDLING-- */
    err = PMI_KVS_Commit(handle->kvsname);
    /* --BEGIN ERROR HANDLING-- */
    if (err != PMI_SUCCESS) {
        err =
            MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, __func__, __LINE__,
                                 MPI_ERR_OTHER, "**pmi_kvs_commit", 0);
        return err;
    }
    /* --END ERROR HANDLING-- */

    return 0;
}

int MPID_NS_Lookup(MPID_NS_Handle handle, const MPIR_Info * info_ptr,
                   const char service_name[], char port[])
{
    int err;

    /*printf("lookup kvs: <%s>\n", handle->kvsname);fflush(stdout); */
    err = PMI_KVS_Get(handle->kvsname, service_name, port, MPI_MAX_PORT_NAME);
    /* --BEGIN ERROR HANDLING-- */
    if (err != PMI_SUCCESS) {
        err =
            MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, __func__, __LINE__,
                                 MPI_ERR_NAME, "**pmi_kvs_get", 0);
        return err;
    }
    /* --END ERROR HANDLING-- */

    if (port[0] == '\0') {
        return MPI_ERR_NAME;
    }
    return 0;
}

int MPID_NS_Unpublish(MPID_NS_Handle handle, const MPIR_Info * info_ptr, const char service_name[])
{
    int err;

    /*printf("unpublish kvs: <%s>\n", handle->kvsname);fflush(stdout); */
    /* This assumes you can put the same key more than once which breaks the PMI specification */
    err = PMI_KVS_Put(handle->kvsname, service_name, "");
    /* --BEGIN ERROR HANDLING-- */
    if (err != PMI_SUCCESS) {
        err =
            MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, __func__, __LINE__,
                                 MPI_ERR_OTHER, "**pmi_kvs_put", 0);
        return err;
    }
    /* --END ERROR HANDLING-- */
    err = PMI_KVS_Commit(handle->kvsname);
    /* --BEGIN ERROR HANDLING-- */
    if (err != PMI_SUCCESS) {
        err =
            MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, __func__, __LINE__,
                                 MPI_ERR_OTHER, "**pmi_kvs_commit", 0);
        return err;
    }
    /* --END ERROR HANDLING-- */

    return 0;
}

int MPID_NS_Free(MPID_NS_Handle * handle_ptr)
{
    int err;

    MPL_free((*handle_ptr)->kvsname);
    MPL_free(*handle_ptr);
    *handle_ptr = 0;

    return 0;
}
#endif
