#ifdef PETSC_RCS_HEADER
static char vcid[] = "$Id: gridreg.c,v 1.5 2000/01/10 03:54:25 knepley Exp $";
#endif

#include "src/grid/gridimpl.h"  /*I "grid.h"  I*/

PetscFList GridList                       = PETSC_NULL;
PetscTruth GridRegisterAllCalled          = PETSC_FALSE;
PetscFList GridSerializeList              = PETSC_NULL;
PetscTruth GridSerializeRegisterAllCalled = PETSC_FALSE;

#undef __FUNCT__  
#define __FUNCT__ "GridSetType"
/*@C
  GridSetType - Sets the creation method for the grid.

  Collective on Grid

  Input Parameters:
+ grid   - The Grid context
- method - A known method

  Options Database Command:
. -grid_type <method> - Sets the method; use -help for a list
                        of available methods (for instance, tri2d)

  Notes:
  See "petsc/include/grid.h" for available methods (for instance)
. GRID_TRIANGULAR_2D - Triangular 2D grid

  Normally, it is best to use the GridSetFromOptions() command and
  then set the Grid type from the options database rather than by using
  this routine.  Using the options database provides the user with
  maximum flexibility in evaluating the many different solvers.
  The GridSetType() routine is provided for those situations
  where it is necessary to set the application ordering independently of the
  command line or options database.  This might be the case, for example,
  when the choice of solver changes during the execution of the
  program, and the user's application is taking responsibility for
  choosing the appropriate method.  In other words, this routine is
  not for beginners.

  Level: intermediate

.keywords: grid, set, type
.seealso GridSetSerializeType()
@*/
int GridSetType(Grid grid, GridType method)
{
  int      (*r)(Grid);
  PetscTruth match;
  int        ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(grid, GRID_COOKIE);
  ierr = PetscTypeCompare((PetscObject) grid, method, &match);                                            CHKERRQ(ierr);
  if (match == PETSC_TRUE) PetscFunctionReturn(0);

  /* Get the function pointers for the method requested */
  if (GridRegisterAllCalled == PETSC_FALSE) {
    ierr = GridRegisterAll(PETSC_NULL);                                                                   CHKERRQ(ierr);
  }
  ierr = PetscFListFind(grid->comm, GridList, method, (void (**)(void)) &r);                              CHKERRQ(ierr);
  if (!r) SETERRQ1(PETSC_ERR_ARG_WRONG, "Unknown grid type: %s", method);

  if (grid->ops->destroy != PETSC_NULL) {
    ierr = (*grid->ops->destroy)(grid);                                                                   CHKERRQ(ierr);
  }
  ierr = (*r)(grid);                                                                                      CHKERRQ(ierr);

  ierr = PetscObjectChangeTypeName((PetscObject) grid, method);                                           CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef __FUNCT__
#define __FUNCT__ "GridGetType"
/*@C
  GridGetType - Gets the Grid method type name (as a string).

  Not collective

  Input Parameter:
. grid - The grid

  Output Parameter:
. type - The name of Grid method

  Level: intermediate

.keywords: grid, get, type, name
.seealso GridSetType()
@*/
int GridGetType(Grid grid, GridType *type)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(grid, GRID_COOKIE);
  PetscValidPointer(type);
  if (GridRegisterAllCalled == PETSC_FALSE) {
    ierr = GridRegisterAll(PETSC_NULL);                                                                   CHKERRQ(ierr);
  }
  *type = grid->type_name;
  PetscFunctionReturn(0);
}

#undef __FUNCT__  
#define __FUNCT__ "GridSetSerializeType"
/*@C
  GridSetSerializeType - Sets the serialization method for the grid.

  Collective on Grid

  Input Parameters:
+ grid   - The Grid context
- method - A known method

  Options Database Command:
. -grid_serialize_type <method> - Sets the method; use -help for a list
                                  of available methods (for instance, tri2d_binary)

  Notes:
  See "petsc/include/grid.h" for available methods (for instance)
. GRID_SER_TRIANGULAR_2D_BINARY - Triangular 2D grid to binary file

  Normally, it is best to use the GridSetFromOptions() command and
  then set the Grid type from the options database rather than by using
  this routine.  Using the options database provides the user with
  maximum flexibility in evaluating the many different solvers.
  The GridSetSerializeType() routine is provided for those situations
  where it is necessary to set the application ordering independently of the
  command line or options database.  This might be the case, for example,
  when the choice of solver changes during the execution of the
  program, and the user's application is taking responsibility for
  choosing the appropriate method.  In other words, this routine is
  not for beginners.

  Level: intermediate

.keywords: grid, set, type, serialization
.seealso GridSetType()
@*/
int GridSetSerializeType(Grid grid, GridSerializeType method)
{
  int      (*r)(MPI_Comm, Grid *, PetscViewer, PetscTruth);
  PetscTruth match;
  int        ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(grid, GRID_COOKIE);
  ierr = PetscSerializeCompare((PetscObject) grid, method, &match);                                       CHKERRQ(ierr);
  if (match == PETSC_TRUE) PetscFunctionReturn(0);

  /* Get the function pointers for the method requested but do not call */
  if (GridSerializeRegisterAllCalled == PETSC_FALSE) {
    ierr = GridSerializeRegisterAll(PETSC_NULL);                                                          CHKERRQ(ierr);
  }
  ierr = PetscFListFind(grid->comm, GridSerializeList, method, (void (**)(void)) &r);                     CHKERRQ(ierr);
  if (!r) SETERRQ1(PETSC_ERR_ARG_WRONG, "Unknown grid serialization type: %s", method);

  ierr = PetscObjectChangeSerializeName((PetscObject) grid, method);                                      CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef __FUNCT__
#define __FUNCT__ "GridGetSerializeType"
/*@C
  GridGetSerializeType - Gets the Grid serialization method (as a string).

  Not collective

  Input Parameter:
. grid - The grid

  Output Parameter:
. type - The name of Grid serialization method

  Level: intermediate

.keywords: grid, get, serialize, type, name
.seealso GridSetType()
@*/
int GridGetSerializeType(Grid grid, GridSerializeType *type)
{
  int ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(grid, GRID_COOKIE);
  PetscValidPointer(type);
  if (GridSerializeRegisterAllCalled == PETSC_FALSE) {
    ierr = GridSerializeRegisterAll(PETSC_NULL);                                                          CHKERRQ(ierr);
  }
  *type = grid->serialize_name;
  PetscFunctionReturn(0);
}

/*--------------------------------------------------------------------------------------------------------------------*/
/*@C
  GridRegister - Adds a creation method to the grid package.

  Synopsis:

  GridRegister(char *name, char *path, char *func_name, int (*create_func)(Grid))

  Not Collective

  Input Parameters:
+ name        - The name of a new user-defined creation routine
. path        - The path (either absolute or relative) of the library containing this routine
. func_name   - The name of the creation routine
- create_func - The creation routine itself

  Notes:
  GridRegister() may be called multiple times to add several user-defined grides.

  If dynamic libraries are used, then the fourth input argument (create_func) is ignored.

  Sample usage:
.vb
  GridRegisterDynamic("my_grid", "/home/username/my_lib/lib/libO/solaris/libmy.a", "MyGridCreate", MyGridCreate);
.ve

  Then, your grid type can be chosen with the procedural interface via
.vb
    GridCreate(MPI_Comm, Grid *);
    GridSetType(vec, "my_grid")
.ve
  or at runtime via the option
.vb
    -grid_type my_grid
.ve

  Note: $PETSC_ARCH and $BOPT occuring in pathname will be replaced with appropriate values.

  Level: advanced

.keywords: Grid, register
.seealso: GridRegisterAll(), GridRegisterDestroy()
@*/
#undef __FUNCT__  
#define __FUNCT__ "GridRegister"
int GridRegister(const char sname[], const char path[], const char name[], int (*function)(Grid))
{
  char fullname[256];
  int  ierr;

  PetscFunctionBegin;
  ierr = PetscStrcpy(fullname, path);                                                                     CHKERRQ(ierr);
  ierr = PetscStrcat(fullname, ":");                                                                      CHKERRQ(ierr);
  ierr = PetscStrcat(fullname, name);                                                                     CHKERRQ(ierr);
  ierr = PetscFListAdd(&GridList, sname, fullname, (void (*)(void)) function);                            CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

/*@C
  GridSerializeRegister - Adds a serialization method to the grid package.

  Synopsis:

  GridSerializeRegister(char *name, char *path, char *func_name,
                        int (*serialize_func)(MPI_Comm, Grid *, PetscViewer, PetscTruth))

  Not Collective

  Input Parameters:
+ name           - The name of a new user-defined serialization routine
. path           - The path (either absolute or relative) of the library containing this routine
. func_name      - The name of the serialization routine
- serialize_func - The serialization routine itself

  Notes:
  GridSerializeRegister() may be called multiple times to add several user-defined serializers.

  If dynamic libraries are used, then the fourth input argument (serialize_func) is ignored.

  Sample usage:
.vb
  GridSerializeRegisterDynamic("my_store", "/home/username/my_lib/lib/libO/solaris/libmy.a", "MyStoreFunc", MyStoreFunc);
.ve

  Then, your serialization can be chosen with the procedural interface via
.vb
    GridSetSerializeType(grid, "my_store")
.ve
  or at runtime via the option
.vb
    -grid_serialize_type my_store
.ve

  Note: $PETSC_ARCH and $BOPT occuring in pathname will be replaced with appropriate values.

  Level: advanced

.keywords: grid, register
.seealso: GridSerializeRegisterAll(), GridSerializeRegisterDestroy()
M*/
#undef __FUNCT__  
#define __FUNCT__ "GridSerializeRegister"
int GridSerializeRegister(const char sname[], const char path[], const char name[],
                          int (*function)(MPI_Comm, Grid *, PetscViewer, PetscTruth))
{
  char fullname[256];
  int  ierr;

  PetscFunctionBegin;
  ierr = PetscStrcpy(fullname, path);                                                                     CHKERRQ(ierr);
  ierr = PetscStrcat(fullname, ":");                                                                      CHKERRQ(ierr);
  ierr = PetscStrcat(fullname, name);                                                                     CHKERRQ(ierr);
  ierr = PetscFListAdd(&GridSerializeList, sname, fullname, (void (*)(void)) function);                   CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

/*-------------------------------------------------------------------------------------------------------------------*/
#undef __FUNCT__  
#define __FUNCT__ "GridRegisterDestroy"
/*@C
  GridRegisterDestroy - Frees the list of creation routines for grids that were registered by GridRegister().

  Not collective

  Level: advanced

.keywords: grid, register, destroy
.seealso: GridRegister(), GridRegisterAll(), GridSerializeRegisterDestroy()
@*/
int GridRegisterDestroy(void)
{
  int ierr;

  PetscFunctionBegin;
  if (GridList != PETSC_NULL) {
    ierr = PetscFListDestroy(&GridList);                                                                  CHKERRQ(ierr);
    GridList = PETSC_NULL;
  }
  GridRegisterAllCalled = PETSC_FALSE;
  PetscFunctionReturn(0);
}

#undef __FUNCT__  
#define __FUNCT__ "GridSerializeRegisterDestroy"
/*@C
  GridSerializeRegisterDestroy - Frees the list of serialization routines for
  grids that were registered by GridSerializeRegister().

  Not collective

  Level: advanced

.keywords: grid, serialization, register, destroy
.seealso: GridSerializeRegisterAll(), GridRegisterDestroy()
@*/
int GridSerializeRegisterDestroy()
{
  int ierr;

  PetscFunctionBegin;
  if (GridSerializeList != PETSC_NULL) {
    ierr = PetscFListDestroy(&GridSerializeList);                                                         CHKERRQ(ierr);
    GridSerializeList = PETSC_NULL;
  }
  GridSerializeRegisterAllCalled = PETSC_FALSE;
  PetscFunctionReturn(0);
}
