#ifndef FITS_HEADER_HPP
#define FITS_HEADER_HPP

#include "io.hpp"
#include "my_assert.hpp"
#include "cutout.hpp" // fits_card
#include "fitsfiles.hpp"
#include <fitsio.h>

#include <iostream>
#include <vector>
#include <string>
#include <map>

namespace fits
{

class header
{
   public:

      header() : hdunum{1}, fptr{nullptr}
      {
         LOG_trace(std::string{__func__} + " (explicit default constructor)");
      }

      header(std::string pathname, unsigned long hdunum, int iomode = READONLY)
         : hdunum{hdunum}, fptr{nullptr}
      {
         LOG_trace(__func__);
         open_fitsfile(pathname, hdunum, iomode);
      };

      ~header()
      {
         LOG_trace(__func__);

         if(fptr != nullptr)
         {
            LOG_STREAM << "closing disk-file" << std::endl;
            int status = 0;
            fits_close_file(fptr,&status);
            if(status) LOG_STREAM << "fits_close_file: " << cfitsio_errmsg(__FILE__,__LINE__,status) << std::endl;
         }
      };

      int read_record(int keynum, char *card, int *status);
      int get_nkeys();
      void update(const std::vector<fits_card> additional_cards);
      void update(const std::string card);
      std::string get_header(bool apply_fixes = false);
      std::string read_card(std::string keyname);
      bool contains_card(std::string keyname);

      // FIXME unify card-interface: above uses fits_card vs below map<string-key, fits-type>

      // support ObsCoreKeys
      void parseStrCards(std::map<std::string, std::string>& strCards);
      void parseUIntCards(std::map<std::string, unsigned long>& uintCards);
      void parseDoubleCards(std::map<std::string, double>& doubleCards);

      std::map<std::string, std::string>   parse_string_cards(std::set<std::string> str_keys);
      std::map<std::string, unsigned long> parse_uint_cards(std::set<std::string> str_keys);
      std::map<std::string, double>        parse_double_cards(std::set<std::string> str_keys);
      fitsfiles::key_values_by_type parse_cards(fitsfiles::keys_by_type keys);

      double calc_nullvals(unsigned long long & null_cnt, unsigned long long & tot_cnt);

   protected:

      std::string cfitsio_errmsg(const char * filename, int line_num, int status);
      std::string cfitsio_errmsg(int status);
      void open_fitsfile(std::string pathname_template, unsigned long hdunum, int iomode);
      void update_card(const struct fits_card new_card);

      unsigned long hdunum;
      fitsfile * fptr;
};

}

#endif

