#ifndef GRID_HEALPIX_H
#define GRID_HEALPIX_H

#include <string>
#include <vector>

enum class HpOrder
{
  Undef,
  XY,
  Ring,
  Nested
};

class HpParams
{
public:
  HpParams(){};
  HpParams(int nside, HpOrder order) : m_nside(nside), m_order(order){};

  // clang-format off
  int get_nside() const { return m_nside; };
  HpOrder get_order() const { return m_order; };
  // clang-format on

private:
  int m_nside{ 0 };
  HpOrder m_order{ HpOrder::Undef };
};

HpOrder hp_get_order(const std::string &orderName);
int64_t hp_lonlat_to_index(HpParams hpParams, double xval, double yval);
void hp_index_to_lonlat(HpParams hpParams, int64_t index, double *xval, double *yval);
void hp_get_neighbours(HpParams hpParams, int64_t index, int64_t *neighbours);
void hp_bilinear_interpolate_weights(HpParams hpParams, double lon, double lat, size_t *indices, double *weights);
void hp_generate_coords(HpOrder order, int nside, int64_t nvals, double *xvals, double *yvals, bool withBounds, double *xbounds,
                        double *ybounds);
void hp_generate_latitudes(int nside, std::vector<double> &latitudes);
void hp_generate_ring_indices(HpParams hpParams, size_t gridsize, std::vector<int> &ringIndices, std::vector<int> &ringRows);

template <typename T>
void hp_ring_to_nested(int nside, size_t gridsize, T *arrayIn, T *arrayOut);

template <typename T>
void hp_nested_to_ring(int nside, size_t gridsize, T *arrayIn, T *arrayOut);

#endif
