#include <petsc/private/sfimpl.h> /*I  "petscsf.h"  I*/

PETSC_INTERN PetscErrorCode PetscSFCreate_Basic(PetscSF);
#if defined(PETSC_HAVE_MPI_WIN_CREATE)
PETSC_INTERN PetscErrorCode PetscSFCreate_Window(PetscSF);
#endif
PETSC_INTERN PetscErrorCode PetscSFCreate_Allgatherv(PetscSF);
PETSC_INTERN PetscErrorCode PetscSFCreate_Allgather(PetscSF);
PETSC_INTERN PetscErrorCode PetscSFCreate_Gatherv(PetscSF);
PETSC_INTERN PetscErrorCode PetscSFCreate_Gather(PetscSF);
PETSC_INTERN PetscErrorCode PetscSFCreate_Alltoall(PetscSF);
#if defined(PETSC_HAVE_MPI_NEIGHBORHOOD_COLLECTIVES)
PETSC_INTERN PetscErrorCode PetscSFCreate_Neighbor(PetscSF);
#endif

PetscFunctionList PetscSFList;
PetscBool         PetscSFRegisterAllCalled;

/*@C
  PetscSFRegisterAll - Registers all the `PetscSF` communication implementations

  Not Collective

  Level: advanced

.seealso: `PetscSF`, `PetscSFRegister()`, `PetscSFRegisterDestroy()`
@*/
PetscErrorCode PetscSFRegisterAll(void)
{
  PetscFunctionBegin;
  if (PetscSFRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS);
  PetscSFRegisterAllCalled = PETSC_TRUE;
  PetscCall(PetscSFRegister(PETSCSFBASIC, PetscSFCreate_Basic));
#if defined(PETSC_HAVE_MPI_WIN_CREATE)
  PetscCall(PetscSFRegister(PETSCSFWINDOW, PetscSFCreate_Window));
#endif
  PetscCall(PetscSFRegister(PETSCSFALLGATHERV, PetscSFCreate_Allgatherv));
  PetscCall(PetscSFRegister(PETSCSFALLGATHER, PetscSFCreate_Allgather));
  PetscCall(PetscSFRegister(PETSCSFGATHERV, PetscSFCreate_Gatherv));
  PetscCall(PetscSFRegister(PETSCSFGATHER, PetscSFCreate_Gather));
  PetscCall(PetscSFRegister(PETSCSFALLTOALL, PetscSFCreate_Alltoall));
#if defined(PETSC_HAVE_MPI_NEIGHBORHOOD_COLLECTIVES)
  PetscCall(PetscSFRegister(PETSCSFNEIGHBOR, PetscSFCreate_Neighbor));
#endif
  PetscFunctionReturn(PETSC_SUCCESS);
}

/*@C
  PetscSFRegister  - Adds an implementation of the `PetscSF` communication protocol.

  Not Collective

  Input Parameters:
+ name   - name of a new user-defined implementation
- create - routine to create method context

  Example Usage:
.vb
   PetscSFRegister("my_impl", MyImplCreate);
.ve

  Then, this implementation can be chosen with the procedural interface via
$     PetscSFSetType(sf, "my_impl")
  or at runtime via the option
$     -sf_type my_impl

  Level: advanced

  Note:
  `PetscSFRegister()` may be called multiple times to add several user-defined implementations.

.seealso: `PetscSF`, `PetscSFType`, `PetscSFRegisterAll()`, `PetscSFInitializePackage()`
@*/
PetscErrorCode PetscSFRegister(const char name[], PetscErrorCode (*create)(PetscSF))
{
  PetscFunctionBegin;
  PetscCall(PetscSFInitializePackage());
  PetscCall(PetscFunctionListAdd(&PetscSFList, name, create));
  PetscFunctionReturn(PETSC_SUCCESS);
}
