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

#include "src/grid/discretization/discimpl.h"      /*I "discretization.h"  I*/

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

  Collective on MPI_Comm

  Input Parameter:
. comm - The communicator

  Output Parameter:
. disc - The disc

  Level: beginner

.keywords: Discretization, create
.seealso: DiscretizationSetType(), DiscretizationSetUp(), DiscretizationDestroy(), GridCreate()
@*/
int DiscretizationCreate(MPI_Comm comm, Discretization *disc) {
  Discretization d;
  int            ierr;

  PetscFunctionBegin;
  PetscValidPointer(disc);
  *disc = PETSC_NULL;
#ifndef PETSC_USE_DYNAMIC_LIBRARIES
  ierr = GridInitializePackage(PETSC_NULL);                                                               CHKERRQ(ierr);
#endif

  PetscHeaderCreate(d, _Discretization, struct _DiscretizationOps, DISCRETIZATION_COOKIE, -1, "Discretization", comm, DiscretizationDestroy, DiscretizationView);
  PetscLogObjectCreate(d);
  PetscLogObjectMemory(d, sizeof(struct _Discretization));
  ierr = PetscMemzero(d->ops, sizeof(struct _DiscretizationOps));                                         CHKERRQ(ierr);
  d->bops->publish    = PETSC_NULL /* DiscretizationPublish_Petsc */;
  d->type_name        = PETSC_NULL;
  d->serialize_name   = PETSC_NULL;

  /* General discretization description */
  d->data  = PETSC_NULL;
  d->dim   = -1;
  d->funcs = 0;
  d->comp  = 0;
  d->size  = 0;
  d->field = -1;

  /* Boundary integration */
  d->bdDisc = PETSC_NULL;

  /* Quadrature */
  d->numQuadPoints     = 0;
  d->quadPoints        = PETSC_NULL;
  d->quadWeights       = PETSC_NULL;
  d->quadShapeFuncs    = PETSC_NULL;
  d->quadShapeFuncDers = PETSC_NULL;

  /* Operators */
  d->numOps = 0;
  d->maxOps = 1;
  ierr = PetscMalloc(d->maxOps * sizeof(Operator), &d->operators);                                        CHKERRQ(ierr);

  /* Storage */
  d->funcVal  = PETSC_NULL;
  d->fieldVal = PETSC_NULL;

  *disc = d;
  PetscFunctionReturn(0);
}

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

  Collective on MPI_Comm

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

  Output Parameter:
. disc   - The discretization

  Level: beginner

.keywords: Discretization, serialize
.seealso: PartitionSerialize(), DiscretizationSerialize()
@*/
int DiscretizationSerialize(MPI_Comm comm, Discretization *disc, PetscViewer viewer, PetscTruth store)
{
  int      (*serialize)(MPI_Comm, Discretization *, PetscViewer, PetscTruth);
  int        fd, len;
  char      *name;
  PetscTruth match;
  int        ierr;

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

  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 (!DiscretizationSerializeRegisterAllCalled) {
    ierr = DiscretizationSerializeRegisterAll(PETSC_NULL);                                                CHKERRQ(ierr);
  }
  if (!DiscretizationSerializeList) SETERRQ(PETSC_ERR_ARG_CORRUPT, "Could not find table of methods");

  if (store) {
    PetscValidHeaderSpecific(*disc, DISCRETIZATION_COOKIE);
    ierr = PetscStrlen((*disc)->class_name, &len);                                                        CHKERRQ(ierr);
    ierr = PetscBinaryWrite(fd, &len,                     1,   PETSC_INT,  0);                            CHKERRQ(ierr);
    ierr = PetscBinaryWrite(fd,  (*disc)->class_name,     len, PETSC_CHAR, 0);                            CHKERRQ(ierr);
    ierr = PetscStrlen((*disc)->serialize_name, &len);                                                    CHKERRQ(ierr);
    ierr = PetscBinaryWrite(fd, &len,                     1,   PETSC_INT,  0);                            CHKERRQ(ierr);
    ierr = PetscBinaryWrite(fd,  (*disc)->serialize_name, len, PETSC_CHAR, 0);                            CHKERRQ(ierr);
    ierr = PetscFListFind(comm, DiscretizationSerializeList, (*disc)->serialize_name, (void (**)(void)) &serialize);CHKERRQ(ierr);
    if (!serialize) SETERRQ(PETSC_ERR_ARG_WRONG, "Type cannot be serialized");
    ierr = (*serialize)(comm, disc, 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, "Discretization", &match);                                                   CHKERRQ(ierr);
    ierr = PetscFree(name);                                                                               CHKERRQ(ierr);
    if (match == PETSC_FALSE) SETERRQ(PETSC_ERR_ARG_WRONG, "Non-disc 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, DiscretizationSerializeList, name, (void (**)(void)) &serialize);         CHKERRQ(ierr);
    if (!serialize) SETERRQ(PETSC_ERR_ARG_WRONG, "Type cannot be serialized");
    ierr = (*serialize)(comm, disc, viewer, store);                                                       CHKERRQ(ierr);
    ierr = PetscStrfree((*disc)->serialize_name);                                                         CHKERRQ(ierr);
    (*disc)->serialize_name = name;
  }

  PetscFunctionReturn(0);
}
