#pragma once
#include <boost/asio/steady_timer.hpp>
#include <boost/container/flat_map.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/container/flat_map.hpp>
#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/asio/object_server.hpp>
#include <sdbusplus/bus/match.hpp>
#include <string>
#include <iostream>

#define MAX_CPU_ID 2
#define MAX_DIMM_RANK 12
#define STATUS_TEMP_NUM 3
#define STATUS_PMIC_RAIL_NUM 6
#define STATUS_REG_NUM 8
#define STATUS_ERROR_NUM 1

extern std::unordered_map<std::string, std::shared_ptr<sdbusplus::asio::dbus_interface>> dimm_temp_inf;
extern std::unordered_map<std::string, std::shared_ptr<sdbusplus::asio::dbus_interface>> dimm_voltage_inf;
extern std::unordered_map<std::string, std::shared_ptr<sdbusplus::asio::dbus_interface>> dimm_current_inf;
extern std::unordered_map<std::string, std::shared_ptr<sdbusplus::asio::dbus_interface>> dimm_power_inf;
extern std::unordered_map<std::string, std::shared_ptr<sdbusplus::asio::dbus_interface>> dimm_statusReg_inf;
extern std::unordered_map<std::string, std::shared_ptr<sdbusplus::asio::dbus_interface>> dimm_errCode_inf;

enum FieldType {
    VOLTAGE,
    CURRENT,
    POWER,
    TEMP,
    STATUS,
    ERROR
};

 struct DimmData
 {
  uint8_t reg[STATUS_REG_NUM];
  uint8_t error[STATUS_ERROR_NUM];  
  double voltage[STATUS_PMIC_RAIL_NUM];
  double current[STATUS_PMIC_RAIL_NUM];
  double power[STATUS_PMIC_RAIL_NUM];
  double temp[STATUS_TEMP_NUM];

 };

struct DimmI3CAddr
{
  std::string spdAddr;
  std::string pmicAddr;
};

enum PMICType {
  PMIC5000 = 0,
  PMIC5010,
  PMIC5100,
  PMIC5020,
  PMIC5120,
  PMIC5200,
  PMIC5030,
  Unknown = 0xFF
};

struct DIMMSpdReader : std::enable_shared_from_this<DIMMSpdReader>
{
    DIMMSpdReader(boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
    const float pollRate) : sensorPollMs(static_cast<unsigned int>(pollRate * 1000)),
    objectServer(objectServer), waitTimer(io) {};

    ~DIMMSpdReader()
    {
        waitTimer.cancel();
    };

    void init();
    void startRead();
    void readDimmInfo();
    int getDIMMRegsTemp(uint8_t cpuid, uint8_t rank, DimmData& dimmData);
    int getDIMMRegsVol(uint8_t cpuid, uint8_t rank, DimmData& dimmData);
    int getDIMMRegsCurAndPow(uint8_t cpuid, uint8_t rank, DimmData& dimmData);
    void updateDbus();
    void updateToDimmInfoFile();
    void setupMatches(sdbusplus::bus_t&);
    void dimmI3cSwitchMatcher( std::vector<sdbusplus::bus::match_t>& matches,
    sdbusplus::bus_t& connection, std::function<void(bool)>&& onMatch);
    void getdimmI3cSwitchState(const std::shared_ptr<sdbusplus::asio::connection>& conn, size_t retries = 2);
    int getPmicType(uint8_t cpuid, uint8_t rank);
    int getPmicStatusRegs(uint8_t cpuid, uint8_t rank, DimmData& dimmData);
    int setADCAccuracyStepSize(uint8_t cpuid, uint8_t rank, DimmData& dimmData, uint8_t R32);
    int checkADCAccuracyStepSize(uint8_t cpuid, uint8_t rank, DimmData& dimmData, const uint8_t* ThresholdData);	

  private:
    std::vector<sdbusplus::bus::match_t> matches;
    unsigned int sensorPollMs;
    sdbusplus::asio::object_server& objectServer;
    boost::asio::steady_timer waitTimer;
    PMICType pmicType[MAX_CPU_ID][MAX_DIMM_RANK];
    bool gotType[MAX_CPU_ID][MAX_DIMM_RANK];
    bool twoByteMode[MAX_CPU_ID][MAX_DIMM_RANK];
    int adcDelay[MAX_CPU_ID][MAX_DIMM_RANK];
    uint16_t regCounter;
    uint16_t pmicCounter;
};
