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

#include "src/mesh/meshimpl.h"      /*I "mesh.h"  I*/

#undef  __FUNCT__
#define __FUNCT__ "MeshCreate"
/*@ 
  MeshCreate - This function creates an empty mesh. The type can then be set with MeshSetType().

  Collective on MPI_Comm

  Input Parameter:
. comm - The communicator for the mesh object

  Output Parameter:
. mesh - The mesh

  Options Database Keys:
. -mesh_reorder              - The flag to renumber the mesh nodes
. -mesh_ordering_type <type> - The type of node numbering, such as tri_2d_rcm, etc.

  Level: beginner

.keywords: mesh, create
.seealso: MeshSetType(), MeshSetUp(), MeshDestroy(), GridCreate()
@*/
int MeshCreate(MPI_Comm comm, Mesh *mesh)
{
  Mesh m;
  int  ierr;

  PetscFunctionBegin;
  PetscValidPointer(mesh);
  *mesh = PETSC_NULL;
#ifndef PETSC_USE_DYNAMIC_LIBRARIES
  ierr = MeshInitializePackage(PETSC_NULL);                                                               CHKERRQ(ierr);
#endif

  PetscHeaderCreate(m, _Mesh, struct _MeshOps, MESH_COOKIE, -1, "Mesh", comm, MeshDestroy, MeshView);
  PetscLogObjectCreate(m);
  PetscLogObjectMemory(m, sizeof(struct _Mesh));
  ierr = PetscMemzero(m->ops, sizeof(struct _MeshOps));                                                   CHKERRQ(ierr);
  m->bops->publish    = PETSC_NULL /* MeshPublish_Petsc */;
  m->type_name        = PETSC_NULL;
  m->serialize_name   = PETSC_NULL;

  m->dim              = -1;
  m->setupcalled      = PETSC_FALSE;
  m->data             = PETSC_NULL;
  m->usr              = PETSC_NULL;

  /* Domain information */
  m->startX    = m->startY    = m->startZ    = 0.0;
  m->endX      = m->endY      = m->endZ      = 0.0;
  m->sizeX     = m->sizeY     = m->sizeZ     = 0.0;
  m->locStartX = m->locStartY = m->locStartZ = 0.0;
  m->locEndX   = m->locEndY   = m->locEndZ   = 0.0;
  m->locSizeX  = m->locSizeY  = m->locSizeZ  = 0.0;
  m->isPeriodic       = PETSC_FALSE;
  m->isPeriodicDim[0] = PETSC_FALSE;
  m->isPeriodicDim[1] = PETSC_FALSE;
  m->isPeriodicDim[2] = PETSC_FALSE;

  /* Mesh boundary information */
  m->bdCtx    = PETSC_NULL;
  m->bdCtxNew = PETSC_NULL;

  /* Mesh generator information */
  m->nodeOrdering = PETSC_NULL;

  /* Mesh information */
  m->numBd          = 0;
  m->numVertices    = 0;
  m->numNodes       = 0;
  m->numBdNodes     = 0;
  m->numEdges       = 0;
  m->numBdEdges     = 0;
  m->numFaces       = 0;
  m->numBdFaces     = 0;
  m->numCells       = 0;
  m->numHoles       = 0;
  m->numCorners     = 0;
  m->numCellCorners = 0;
  m->maxDegree      = 0;
  m->holes          = 0;

  /* Iterator support */
  m->activeBd          = -1;
  m->activeBdOld       = -1;
  m->activeBdNode      = -1;
  m->activeBdNodeClass = -1;

  /* Quality limits */
  m->maxAspectRatio = 1.0;

  /* Partitioning support */
  m->part        = PETSC_NULL;
  m->partitioned = PETSC_FALSE;

  /* Coarsening support */
  m->coarseMap = PETSC_NULL;

  /* Graphics support */
  m->highlightElement = -1;

  /* Support calculations */
  m->support      = PETSC_NULL;
  m->supportTaken = PETSC_FALSE;

  /* Movement support */
  m->isMoving = PETSC_FALSE;

  *mesh = m;
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "MeshSerialize"
/*@ 
  MeshSerialize - This function stores or recreates a mesh using a viewer for a binary file.

  Collective on MPI_Comm

  Input Parameters:
+ comm   - The communicator for the mesh object
. viewer - The viewer context
- store  - This flag is PETSC_TRUE is data is being written, otherwise it will be read

  Output Parameter:
. mesh   - The mesh

  Level: beginner

.keywords: mesh, serialize
.seealso: PartitionSerialize(), GridSerialize()
@*/
int MeshSerialize(MPI_Comm comm, Mesh *mesh, PetscViewer viewer, PetscTruth store)
{
  int      (*serialize)(MPI_Comm, Mesh *, PetscViewer, PetscTruth);
  int        fd, len;
  char      *name;
  PetscTruth match;
  int        ierr;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(viewer, PETSC_VIEWER_COOKIE);
  PetscValidPointer(mesh);

  ierr = PetscTypeCompare((PetscObject) viewer, PETSC_VIEWER_BINARY, &match);                             CHKERRQ(ierr);
  if (match == PETSC_FALSE) SETERRQ(PETSC_ERR_ARG_WRONG, "Must be binary viewer");
  ierr = PetscViewerBinaryGetDescriptor(viewer, &fd);                                                     CHKERRQ(ierr);

  if (!MeshSerializeRegisterAllCalled) {
    ierr = MeshSerializeRegisterAll(PETSC_NULL);                                                          CHKERRQ(ierr);
  }
  if (!MeshSerializeList) SETERRQ(PETSC_ERR_ARG_CORRUPT, "Could not find table of methods");

  if (store) {
    PetscValidHeaderSpecific(*mesh, MESH_COOKIE);
    ierr = PetscStrlen((*mesh)->class_name, &len);                                                        CHKERRQ(ierr);
    ierr = PetscBinaryWrite(fd, &len,                     1,   PETSC_INT,  0);                            CHKERRQ(ierr);
    ierr = PetscBinaryWrite(fd,  (*mesh)->class_name,     len, PETSC_CHAR, 0);                            CHKERRQ(ierr);
    ierr = PetscStrlen((*mesh)->serialize_name, &len);                                                    CHKERRQ(ierr);
    ierr = PetscBinaryWrite(fd, &len,                     1,   PETSC_INT,  0);                            CHKERRQ(ierr);
    ierr = PetscBinaryWrite(fd,  (*mesh)->serialize_name, len, PETSC_CHAR, 0);                            CHKERRQ(ierr);
    ierr = PetscFListFind(comm, MeshSerializeList, (*mesh)->serialize_name, (void (**)(void)) &serialize); CHKERRQ(ierr);
    if (!serialize) SETERRQ(PETSC_ERR_ARG_WRONG, "Type cannot be serialized");
    ierr = (*serialize)(comm, mesh, viewer, store);                                                       CHKERRQ(ierr);
  } else {
    ierr = PetscBinaryRead(fd, &len,    1,   PETSC_INT);                                                  CHKERRQ(ierr);
    ierr = PetscMalloc((len+1) * sizeof(char), &name);                                                    CHKERRQ(ierr);
    name[len] = 0;
    ierr = PetscBinaryRead(fd,  name,   len, PETSC_CHAR);                                                 CHKERRQ(ierr);
    ierr = PetscStrcmp(name, "Mesh", &match);                                                             CHKERRQ(ierr);
    ierr = PetscFree(name);                                                                               CHKERRQ(ierr);
    if (match == PETSC_FALSE) SETERRQ(PETSC_ERR_ARG_WRONG, "Non-mesh object");
    /* Dispatch to the correct routine */
    ierr = PetscBinaryRead(fd, &len,    1,   PETSC_INT);                                                  CHKERRQ(ierr);
    ierr = PetscMalloc((len+1) * sizeof(char), &name);                                                    CHKERRQ(ierr);
    name[len] = 0;
    ierr = PetscBinaryRead(fd,  name,   len, PETSC_CHAR);                                                 CHKERRQ(ierr);
    ierr = PetscFListFind(comm, MeshSerializeList, name, (void (**)(void)) &serialize);                   CHKERRQ(ierr);
    if (!serialize) SETERRQ(PETSC_ERR_ARG_WRONG, "Type cannot be serialized");
    ierr = (*serialize)(comm, mesh, viewer, store);                                                       CHKERRQ(ierr);
    ierr = PetscStrfree((*mesh)->serialize_name);                                                         CHKERRQ(ierr);
    (*mesh)->serialize_name = name;
  }

  PetscFunctionReturn(0);
}
