/**
 * @file usb_interface.hpp
 * @author Nawe Robotics
 * @brief File contains USB Interface class definitions
 */

#pragma once
#include "interface.hpp"
#include <atomic>
#include <future>
#include <map>
#include <mutex>

class USBInterface : public Interface {
  /**
   * @brief Class definition for USB interface implementations
   *
   */
  class USBInterfaceImpl;

  /**
   * @brief  Pointer to class object which stores USB interface implementation
   *
   */
  USBInterfaceImpl *impl = NULL;

  /**
   * @brief Parse can_frame from CAN Interface
   *
   */
  uint8_t recvData(struct can_frame_data *fra);

  /**
   * @brief Invokes lower level code to initialize USB Interface
   *
   * @param interface_name Name of USB Interface eg. /dev/ttyACMO, COM5...etc
   * @return uint8_t
   */
  uint8_t init(std::string interface_name);

  /**
   * @brief Method specific to closing CAN interface.
   *
   */
  void closeIface(void);

public:
  /**
   * @brief Construct a new USBInterface object
   *
   */
  USBInterface();
  /**
   * @brief Destroy the USBInterface object
   *
   */
  ~USBInterface();
  /**
   * @brief Send a CAN msg frame on the interface
   *
   * @param fra CAN Msg frame
   * @return uint8_t Success(0) or Failure(1)
   */
  uint8_t sendData(struct can_frame_data *fra);

  /**
   * @brief Set CAN Baud Rate for NLink
   * 
   * @param baud_rate
   * @return uint8_t Success(0) or Failure(1)
   */
  ret_interface_t setCANBaudRate(CANBaudRate baud_rate);

  /**
   * @brief Get CAN Baud Rate for NLink
   * 
   * @param baud_rate Pointer to CANBaudRate where current baud rate will be stored
   * @return ret_interface_t Success(0) or Failure(1)
   */
  ret_interface_t getCANBaudRate(CANBaudRate *baud_rate);
  /**
   * @brief Set NLink to DFU Mode
   * 
   * @return ret_interface_t Success(0) or Failure(1)
   */
  ret_interface_t enterDFUMode();

  /**
   * @brief Save the configuration to NLink
   *
   * @return ret_interface_t Success(0) or Failure(1)
   */
  ret_interface_t saveConfiguration();

  /**
   * @brief Erase the configuration from NLink
   *
   * @return ret_interface_t Success(0) or Failure(1)
   */
  ret_interface_t eraseConfiguration();

  /**
   * @brief Reboot the NLink device
   *
   * @return ret_interface_t Success(0) or Failure(1)
   */
  ret_interface_t rebootNLink();

  /**
   * @brief Get the firmware version of the device
   * 
   * @return ret_interface_t Success(0) or Failure(1)
   */
  ret_interface_t getFirmwareVersion(uint8_t * fw_version_major, uint8_t* fw_version_minor, uint8_t* fw_version_revision, std::string * fw_version_commit);
  
  /**
   * @brief Get the hardware version of the device
   * 
   * @return ret_interface_t Success(0) or Failure(1)
   */
  ret_interface_t getHardwareVersion(uint8_t* hw_version_major, uint8_t* hw_version_minor, uint8_t* hw_revision);
};