#pragma once
#include "std_msgs/Header.h"
#include <cstdint>
#include <string>
#include <vector>
#include <limits>

namespace sensor_msgs
{

struct BatteryState
{
  // ===== Power supply status constants =====
  static constexpr uint8_t POWER_SUPPLY_STATUS_UNKNOWN = 0;
  static constexpr uint8_t POWER_SUPPLY_STATUS_CHARGING = 1;
  static constexpr uint8_t POWER_SUPPLY_STATUS_DISCHARGING = 2;
  static constexpr uint8_t POWER_SUPPLY_STATUS_NOT_CHARGING = 3;
  static constexpr uint8_t POWER_SUPPLY_STATUS_FULL = 4;

  // ===== Power supply health constants =====
  static constexpr uint8_t POWER_SUPPLY_HEALTH_UNKNOWN = 0;
  static constexpr uint8_t POWER_SUPPLY_HEALTH_GOOD = 1;
  static constexpr uint8_t POWER_SUPPLY_HEALTH_OVERHEAT = 2;
  static constexpr uint8_t POWER_SUPPLY_HEALTH_DEAD = 3;
  static constexpr uint8_t POWER_SUPPLY_HEALTH_OVERVOLTAGE = 4;
  static constexpr uint8_t POWER_SUPPLY_HEALTH_UNSPEC_FAILURE = 5;
  static constexpr uint8_t POWER_SUPPLY_HEALTH_COLD = 6;
  static constexpr uint8_t POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE = 7;
  static constexpr uint8_t POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE = 8;

  // ===== Power supply technology (chemistry) constants =====
  static constexpr uint8_t POWER_SUPPLY_TECHNOLOGY_UNKNOWN = 0;
  static constexpr uint8_t POWER_SUPPLY_TECHNOLOGY_NIMH = 1;
  static constexpr uint8_t POWER_SUPPLY_TECHNOLOGY_LION = 2;
  static constexpr uint8_t POWER_SUPPLY_TECHNOLOGY_LIPO = 3;
  static constexpr uint8_t POWER_SUPPLY_TECHNOLOGY_LIFE = 4;
  static constexpr uint8_t POWER_SUPPLY_TECHNOLOGY_NICD = 5;
  static constexpr uint8_t POWER_SUPPLY_TECHNOLOGY_LIMN = 6;

  // ===== Data fields =====
  std_msgs::Header header;

  float voltage = std::numeric_limits<float>::quiet_NaN();           // [V]
  float temperature = std::numeric_limits<float>::quiet_NaN();       // [°C]
  float current = std::numeric_limits<float>::quiet_NaN();           // [A]
  float charge = std::numeric_limits<float>::quiet_NaN();            // [Ah]
  float capacity = std::numeric_limits<float>::quiet_NaN();          // [Ah]
  float design_capacity = std::numeric_limits<float>::quiet_NaN();   // [Ah]
  float percentage = std::numeric_limits<float>::quiet_NaN();        // 0..1

  uint8_t power_supply_status = POWER_SUPPLY_STATUS_UNKNOWN;
  uint8_t power_supply_health = POWER_SUPPLY_HEALTH_UNKNOWN;
  uint8_t power_supply_technology = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
  bool present = false;

  std::vector<float> cell_voltage;
  std::vector<float> cell_temperature;

  std::string location;
  std::string serial_number;
};

inline bool operator==(const sensor_msgs::BatteryState& lhs, const sensor_msgs::BatteryState& rhs)
{
  return lhs.header == rhs.header &&
    lhs.voltage == rhs.voltage &&
    lhs.temperature == rhs.temperature &&
    lhs.current == rhs.current &&
    lhs.charge == rhs.charge &&
    lhs.capacity == rhs.capacity &&
    lhs.design_capacity == rhs.design_capacity &&
    lhs.percentage == rhs.percentage &&
    lhs.power_supply_status == rhs.power_supply_status &&
    lhs.power_supply_health == rhs.power_supply_health &&
    lhs.power_supply_technology == rhs.power_supply_technology &&
    lhs.present == rhs.present &&
    lhs.cell_voltage == rhs.cell_voltage &&
    lhs.cell_temperature == rhs.cell_temperature &&
    lhs.location == rhs.location &&
    lhs.serial_number == rhs.serial_number;
}

inline bool operator!=(const sensor_msgs::BatteryState& lhs, const sensor_msgs::BatteryState& rhs)
{
  return !(lhs == rhs);
}

}  // namespace sensor_msgs
