#ifdef __cplusplus
extern "C"
{
#endif
#include "lib/healpix/healpix.h"
#ifdef __cplusplus
}
#endif

#include "grid_healpix.h"
#include <cstring>

HpOrder
hp_get_order(const char *orderName)
{
  HpOrder order(HpOrder::Undef);
  // clang-format off
  if      (strcmp(orderName, "xy")   == 0) order = HpOrder::XY;
  else if (strcmp(orderName, "ring") == 0) order = HpOrder::Ring;
  else if (strcmp(orderName, "nest") == 0) order = HpOrder::Nest;
  // clang-format on
  return order;
}

static int64_t
hp_xy_to_xy(int64_t ipix, int nside)
{
  (void)nside;
  return ipix;
}

void
hp_generate_coords(HpOrder hpOrder, int nside, int64_t nvals, double *xvals, double *yvals, bool withBounds, double *xbounds, double *ybounds)
{
  int64_t (*convert_order)(int64_t ipix, int nside);
  // clang-format off
  convert_order = (hpOrder == HpOrder::Ring) ? &healpixl_ring_to_xy :
                  (hpOrder == HpOrder::Nest) ? &healpixl_nested_to_xy : &hp_xy_to_xy;
  // clang-format on

#ifdef _OPENMP
#pragma omp parallel for if (nvals > 99999) default(shared) schedule(static)
#endif
  for (int64_t ipix = 0; ipix < nvals; ipix++)
    {
      const auto order = convert_order(ipix, nside);

      healpixl_to_radec(order, nside, 0.5, 0.5, &xvals[ipix], &yvals[ipix]);

      if (withBounds)
        {
          healpixl_to_radec(order, nside, 0.0, 0.0, &xbounds[ipix * 4 + 0], &ybounds[ipix * 4 + 0]);
          healpixl_to_radec(order, nside, 1.0, 0.0, &xbounds[ipix * 4 + 1], &ybounds[ipix * 4 + 1]);
          healpixl_to_radec(order, nside, 1.0, 1.0, &xbounds[ipix * 4 + 2], &ybounds[ipix * 4 + 2]);
          healpixl_to_radec(order, nside, 0.0, 1.0, &xbounds[ipix * 4 + 3], &ybounds[ipix * 4 + 3]);
        }
    }
}
