#ifndef REMAP_METHOD_CONSERV_H
#define REMAP_METHOD_CONSERV_H

#include "grid_cellsearch.h"

extern "C"
{
#include "libyac/src/clipping.h"
#include "libyac/src/area.h"
#include "libyac/src/geometry.h"
}

struct CellSearch
{
  enum yac_edge_type *edgeType{ nullptr };
  size_t numCorners{ 0 };
  Varray<double> partialAreas;
  Varray<yac_grid_cell> gridCells;
  Varray<yac_grid_cell> overlapCells;
  Varray<std::array<double, 3>> overlapBarycenters;

  ~CellSearch()
  {
    for (size_t i = 0, n = gridCells.size(); i < n; ++i)
    {
      if (overlapCells[i].array_size > 0)
      {
        std::free(overlapCells[i].coordinates_xyz);
        std::free(overlapCells[i].edge_type);
      }

      delete[] gridCells[i].coordinates_xyz;
    }
  }

  void
  realloc(size_t numCells, bool allocBarycenters = false)
  {
    if (numCells > gridCells.size())
    {
      auto numCellsPrev = gridCells.size();
      constexpr size_t memInc = 32;
      numCells = (1 + numCells / memInc) * memInc;

      partialAreas.resize(numCells);
      overlapCells.resize(numCells);
      gridCells.resize(numCells);

      for (size_t i = numCellsPrev; i < numCells; ++i)
      {
        overlapCells[i].array_size = 0;
        overlapCells[i].num_corners = 0;
        overlapCells[i].edge_type = nullptr;
        overlapCells[i].coordinates_xyz = nullptr;

        gridCells[i].array_size = numCorners;
        gridCells[i].num_corners = numCorners;
        gridCells[i].edge_type = edgeType;
        gridCells[i].coordinates_xyz = new double[numCorners][3];
      }

      if (allocBarycenters) overlapBarycenters.resize(numCells);
    }
  }
};

inline double
gridcell_area(const yac_grid_cell &cell)
{
  return (cell.num_corners > 1) ? yac_grid_cell_area(cell) : 0.0;
}

void cdo_compute_overlap_info(size_t numCells, CellSearch &cellSearch, const GridCell &tgtGridCell);
void cdo_compute_concave_overlap_info(size_t numCells, CellSearch &cellSearch, const GridCell &tgtGridCell);

#endif
