#ifndef BSP_Q7S_DEVICES_STARTRACKER_ARCSECJSONPARAMBASE_H_
#define BSP_Q7S_DEVICES_STARTRACKER_ARCSECJSONPARAMBASE_H_

#include <filesystem>
#include <fstream>
#include <nlohmann/json.hpp>

#include "fsfw/returnvalues/HasReturnvaluesIF.h"
#include "linux/devices/devicedefinitions/StarTrackerDefinitions.h"

extern "C" {
#include "thirdparty/arcsec_star_tracker/common/generated/tmtcstructs.h"
#include "thirdparty/arcsec_star_tracker/common/genericstructs.h"
}

using json = nlohmann::json;

/**
 * @brief   Base class for creation of parameter configuration commands. Reads parameter set
 *          from a json file located on the filesystem and generates the appropriate command
 *          to apply the parameters to the star tracker software.
 *
 * @author  J. Meier
 */
class ArcsecJsonParamBase : public HasReturnvaluesIF {
 public:
  static const uint8_t INTERFACE_ID = CLASS_ID::ARCSEC_JSON_BASE;
  //! [EXPORT] : [COMMENT] Specified json file does not exist
  static const ReturnValue_t JSON_FILE_NOT_EXISTS = MAKE_RETURN_CODE(1);
  //! [EXPORT] : [COMMENT] Requested set does not exist in json file
  static const ReturnValue_t SET_NOT_EXISTS = MAKE_RETURN_CODE(2);
  //! [EXPORT] : [COMMENT] Requested parameter does not exist in json file
  static const ReturnValue_t PARAM_NOT_EXISTS = MAKE_RETURN_CODE(3);

  /**
   * @brief Constructor
   *
   * @param fullname  Name with absolute path of json file containing the parameters to set.
   */
  ArcsecJsonParamBase(std::string setName);

  /**
   * @brief   Fills a buffer with a parameter set
   *
   * @param fullname  The name including the absolute path of the json file containing the
   *                  parameter set.
   * @param buffer    Pointer to the buffer the command will be written to
   */
  ReturnValue_t create(std::string fullname, uint8_t* buffer);

  /**
   * @brief   Returns the size of the parameter command.
   */
  virtual size_t getSize() = 0;

 protected:
  /**
   * @brief   Reads the value of a parameter from a json set
   *
   * @param name  The name of the parameter
   * @param value The string representation of the read value
   *
   * @return  RETURN_OK if successful, otherwise PARAM_NOT_EXISTS
   */
  ReturnValue_t getParam(const std::string name, std::string& value);

  /**
   * @brief   Converts empty string which is equal to define a value as zero.
   */
  void convertEmpty(std::string& value);

  /**
   * @brief   This function adds a float represented as string to a buffer
   *
   * @param value     The float in string representation to add
   * @param buffer    Pointer to the buffer the float will be written to
   */
  void addfloat(const std::string value, uint8_t* buffer);

  /**
   * @brief   This function adds a uint8_t represented as string to a buffer
   *
   * @param value     The uint8_t in string representation to add
   * @param buffer    Pointer to the buffer the uint8_t will be written to
   */
  void adduint8(const std::string value, uint8_t* buffer);

  /**
   * @brief   This function adds a int16_t represented as string to a buffer
   *
   * @param value     The int16_t in string representation to add
   * @param buffer    Pointer to the buffer the int16_t will be written to
   */
  void addint16(const std::string value, uint8_t* buffer);

  /**
   * @brief   This function adds a uint16_t represented as string to a buffer
   *
   * @param value     The uint16_t in string representation to add
   * @param buffer    Pointer to the buffer the uint16_t will be written to
   */
  void adduint16(const std::string value, uint8_t* buffer);

  /**
   * @brief   This function adds a uint32_t represented as string to a buffer
   *
   * @param value     The uint32_t in string representation to add
   * @param buffer    Pointer to the buffer the uint32_t will be written to
   */
  void adduint32(const std::string value, uint8_t* buffer);

  void addSetParamHeader(uint8_t* buffer, uint8_t setId);

 private:
  json properties;
  json set;
  std::string setName;

  /**
   * @brief   This function must be implemented by the derived class to define creation of a
   *          parameter command.
   */
  virtual ReturnValue_t createCommand(uint8_t* buffer) = 0;

  /**
   * @brief   Initializes the properties json object and the set json object
   *
   * @param fullname  Name including absolute path to json file
   * @param setName   The name of the set to work on
   *
   * @param return    JSON_FILE_NOT_EXISTS if specified file does not exist, otherwise
   *                  RETURN_OK
   */
  ReturnValue_t init(const std::string filename);

  void createJsonObject(const std::string fullname);

  /**
   * @brief   Extracts the json set object form the json file
   *
   * @param setName   The name of the set to create the json object from
   */
  ReturnValue_t initSet();
};

#endif /* BSP_Q7S_DEVICES_STARTRACKER_ARCSECJSONPARAMBASE_H_ */