#ifdef PETSC_RCS_HEADER
static char vcid[] = "$Id: tri2d_GRUMMP.c,v 1.1 1999/12/08 14:45:09 knepley Exp $";
#endif

#include "src/mesh/impls/triangular/2d/2dimpl.h"         /*I "mesh.h" I*/
#include "GRUMMP.h"

#undef  __FUNCT__
#define __FUNCT__ "MeshInitInput_GRUMMP"
/*@C MeshInitInput_GRUMMP
  This function initializes the input structure for GRUMMP.

  Collective on Mesh

  Output Parameters:
. inputCtx - Structure for communicating with GRUMMP

  Level: developer

.keywords mesh, GRUMMP
.seealso MeshInitOutput_GRUMMP()
@*/
int MeshInitInput_GRUMMP(struct _GRUMMP_io *inputCtx)
{
  PetscFunctionBegin;
  /* Setup the input structure */
  inputCtx->numVertices      = 0;
  inputCtx->numCells         = 0;
  inputCtx->numHoles         = 0;
  inputCtx->vertices         = PETSC_NULL;
  inputCtx->perimeter.size   = 0;
  inputCtx->perimeter.numBC  = 0;
  inputCtx->perimeter.bc     = PETSC_NULL;
  inputCtx->perimeter.bcSize = PETSC_NULL;
  inputCtx->holes            = PETSC_NULL;
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "MeshParsePolygon_GRUMMP"
int MeshParsePolygon_GRUMMP(int *markers, struct _GRUMMP_polygon *poly)
{
#if 0
  int start; /* First node in the polygon */
  int first; /* First node on this edge */
  int next;  /* End   node on this edge */
  int size, bc;
#endif

  PetscFunctionBegin;
#if 0
  /* Walk around the polygon */
  poly->size  = 1;
  poly->numBC = 1;
  start = segments[0];
  first = start;
  next  = segments[in.perimeter.size*2];
  /* First get number of boundary conditions */
  while(next != start) {
    if (next != segments[poly->size*2+1]) SETERRQ(PETSC_ERR_LIB, "Boundary must be connected");
    if (markers[first] != markers[next])
      poly->numBC++;
    poly->size++;
    first = next;
    next  = segments[poly->size*2];
  }
  /* Handle multiple BC */
  ierr = PetscMalloc(poly->numBC * sizeof(int), &poly->bc);                                               CHKERRQ(ierr);
  ierr = PetscMalloc(poly->numBC * sizeof(int), &poly->bcSize);                                           CHKERRQ(ierr);
  poly->bc[0]  = markers[start];
  if (poly->numBC == 1) {
    poly->bcSize[0] = poly->size;
  } else {
    poly->bcSize[0] = 0;
    bc    = 0;
    size  = 1;
    start = segments[0];
    first = start;
    next  = segments[size*2];
    /* Get the number of nodes in each BC */
    while(next != start) {
      poly->bcSize[bc]++;
      if (next != segments[size*2+1]) SETERRQ(PETSC_ERR_LIB0, "Boundary must be connected");
      if (markers[first] != markers[next]) {
        bc++;
        poly->bcSize[bc] = 0;
      }
      size++;
      first = next;
      next  = segments[size*2];
    }
  }
#endif
  PetscFunctionReturn(0);
}

#undef  __FUNCT__
#define __FUNCT__ "MeshCreate_GRUMMP"
/*@C MeshCreate_GRUMMP
  This function creates a 2D unstructured mesh using GRUMMP.

  Collective on Mesh

  Input Parameters:
+ b           - The number of closed boundaries in the geometry, or different markers
. n           - Number of boundary points
. points      - (x,y) coordinates of the boundary points
. markers     - Boundary markers for nodes, 0 indicates an interior point, each boundary must have a different marker
. m           - Number of boundary segments
. segments    - Endpoints of boundary segments or PETSC_NULL
. segmarkers  - Boundary markers for each segment
. h           - Number of holes
. holes       - (x,y) coordinates of holes or PETSC_NULL
- numLocNodes - Number of nodes in an element

  Output Parameter:
. mesh        - The new mesh created by Triangle

  Level: developer

.keywords mesh, GRUMMP
.seealso MeshInitInput_GRUMMP
@*/
int MeshCreate_GRUMMP(int b, int n, double *points, int *markers, int m, int *segments, int *segmarkers, int h,
                      double *holes, int numLocNodes, Mesh mesh)
{
  struct _GRUMMP_io in;  /* Input  for GRUMMP mesh generator */
  int               hole;
  int               rank;
  int               ierr;

  PetscFunctionBegin;
  /* Initialize communication structures for GRUMMP */
  ierr = MeshInitInput_GRUMMP(&in);                                                                       CHKERRQ(ierr);
  /*ierr = MeshInitOutput_GRUMMP(&out);                                                                   CHKERRQ(ierr);*/

  mesh->numBd      = b;
  mesh->holes      = PETSC_NULL;
  mesh->numCorners = numLocNodes;
  mesh->numHoles   = h;

  ierr = MPI_Comm_rank(mesh->comm, &rank);                                                                CHKERRQ(ierr);
  if (rank == 0) {
    /* Setup boundaries and holes */
    in.numVertices = n;
    if (n > 0) {
      PetscValidScalarPointer(points);
      in.vertices  = points;
    }
    in.numCells    = h + 1;
    if (m > 0) {
      PetscValidIntPointer(segments);
      PetscValidIntPointer(segmarkers);
      PetscValidIntPointer(markers);
      ierr = MeshParsePolygon_GRUMMP(markers, &in.perimeter);                                             CHKERRQ(ierr);
    }
    in.numHoles    = h;
    if (h > 0) {
      /* We keep these */
      PetscValidScalarPointer(holes);
      ierr = PetscMalloc(in.numHoles * sizeof(struct _GRUMMP_polygon), &in.holes);                        CHKERRQ(ierr);
      for(hole = 0; hole < in.numHoles; hole++) {
        ierr = MeshParsePolygon_GRUMMP(markers, &in.holes[hole]);                                         CHKERRQ(ierr);
      }
    }

    /* Generate the inital coarse mesh and check whether we should create midnodes */
    if (numLocNodes != 3) SETERRQ(PETSC_ERR_SUP, "Number of local nodes not supported");
    /*ierr = Mesh2DToPetsc(&in, tri);                                                                      CHKERRQ(ierr);*/

    /* Get rid of extra information */
  }

  /* Communicate values */
  /*ierr = MeshDistribute_GRUMMP(mesh);                                                                    CHKERRQ(ierr);*/

  PetscFunctionReturn(0);
}
