#ifndef CUTOUT_HPP
#define CUTOUT_HPP

#include <string>
#include <vector>
#include <cstdint> // FIXME is for uintmax_t - find c++ equivalent


enum class area {CIRCLE, RECT, RANGE, POLYGON};
enum class skysystem  {NONE, GALACTIC, ICRS};
enum class specsystem {NONE, VELO_LSRK, WAVE_Barycentric};
enum class timesystem {NONE, MJD_UTC};


struct uint_bounds
{
   unsigned int pix1;
   unsigned int pix2;
   unsigned char type;
};


/* SODA */

struct circle
{
   double lon, lat, radius;
};

struct range
{
   double lon1, lon2, lat1, lat2;
};

struct polygon
{
   std::vector<double> lon;
   std::vector<double> lat;
};

struct position
{
   skysystem sys;
   area    shape;
   circle  circ;
   range   rng;
   polygon poly;
};

const position pos_none = {.sys = skysystem::NONE, .shape = area::CIRCLE, .circ = {0, 0, 0}, .rng = {0,0,0,0}, .poly = {{},{}}};

struct band
{
   specsystem sys;
   double band_value[2];
};

const band band_none = {.sys = specsystem::NONE, .band_value={0,0}};

struct time_axis
{
   timesystem sys;
   double time_value[2];
};

const time_axis time_none = {.sys = timesystem::NONE, .time_value={0,0}};

int min_pol_state(std::vector<std::string> pol);
int max_pol_state(std::vector<std::string> pol);



/* VLKB-legacy */

struct coordinates
{
   coordinates();

   skysystem skysys;               // mandatory: NONE GALACTIC ICRS
   double lon_deg, lat_deg;        // optional, check skysys == NONE
   area  shape;                    // optional: CIRCLE dlon=dlat=2xRadius, RECT dlon may differ dlat
   double dlon_deg, dlat_deg;      // optional
   std::vector<double> p_lon_deg;  // optional polygon arrry
   std::vector<double> p_lat_deg;  // optional polygon array

   specsystem specsys;             // mandatory NONE VELO_LSRK WAVE_Barycentric
   double vl_kmps, vu_kmps;        // optional, check specsystem == NONE

   timesystem timesys;
   double time_value[2];           // time interval (MJD in UTC)

   std::vector<std::string> pol;   // polarization states FIXME pol should be Set<enums>

   std::vector<uint_bounds> pixel_i;   // PIXEL_i for non-standard axes allow direct cut without WCS
};

 coordinates parse_coordinates(const std::string region_string);
 coordinates to_coordinates(const position pos, const band bnd, const time_axis time,
       const std::vector<std::string> pol, const std::vector<uint_bounds> pixel_i);

/* cutout */

struct nullvals_count_s
{
   double fill_ratio;
   unsigned long long null_count;
   unsigned long long total_count;
};

struct fits_card
{
   std::string key;
   std::string value;
   std::string comment;
};

struct cutout_res_s
{
   uintmax_t filesize;
   std::string filename;
   nullvals_count_s nullvals_count;
};


cutout_res_s do_cutout_file(
      const std::string fits_pathname, unsigned int hdunum,
      const position pos, const band bnd, const time_axis time, const std::vector<std::string> pol,
      const bool count_null_values,
      const std::vector<fits_card> extra_cards,
      const std::string conf_fits_path,
      const std::string conf_fits_cutpath);


// used in mcutout : deprecated to be removed from api when mcutout updated
uintmax_t cutout_file(
      const std::string abs_fits_pathname, unsigned int hdunum,
      const coordinates coord,
      const std::string vlkbcutout_pathname,
      const std::vector<fits_card> extra_cards);


// utils

std::string generate_cut_fitsname(std::string pubdid, unsigned int hdunum);
std::string create_timestamp();

#endif

