/*
// Copyright (c) 2019 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
*/

// #include <math.h>
#include <dimmSpdReader.hpp>

#include <chrono>
#include <functional>
#include <iostream>
#include <limits>
#include <memory>
#include <numeric>
#include <string>
#include <vector>
#include <unordered_map>

std::vector<std::string> dimm_table = {
    {"DIMM_CPU0_A"},
    {"DIMM_CPU0_B"},
    {"DIMM_CPU0_C"},
    {"DIMM_CPU0_D"},
    {"DIMM_CPU0_E"},
    {"DIMM_CPU0_F"},
    {"DIMM_CPU0_G"},
    {"DIMM_CPU0_H"},
    {"DIMM_CPU0_I"},
    {"DIMM_CPU0_J"},
    {"DIMM_CPU0_K"},
    {"DIMM_CPU0_L"},
    {"DIMM_CPU1_A"},
    {"DIMM_CPU1_B"},
    {"DIMM_CPU1_C"},
    {"DIMM_CPU1_D"},
    {"DIMM_CPU1_E"},
    {"DIMM_CPU1_F"},
    {"DIMM_CPU1_G"},
    {"DIMM_CPU1_H"},
    {"DIMM_CPU1_I"},
    {"DIMM_CPU1_J"},
    {"DIMM_CPU1_K"},
    {"DIMM_CPU1_L"}
};

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


int main()
{
    boost::asio::io_context io;
    auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
    sdbusplus::asio::object_server objectServer(systemBus, true);
    std::string unit;
    objectServer.add_manager("/xyz/openbmc_project/dimm");
    systemBus->request_name("xyz.openbmc_project.DimmSpdReader");

    for(auto& dimm : dimm_table) {
        std::string interfacePath = "/xyz/openbmc_project/dimm/" + dimm;
        dimm_temp_inf[dimm] = objectServer.add_interface(interfacePath,
                                        "xyz.openbmc_project.Dimm.Temperature");
        dimm_temp_inf[dimm]->register_property(
                "TS0", std::numeric_limits<double>::quiet_NaN(),
                sdbusplus::asio::PropertyPermission::readWrite);
        dimm_temp_inf[dimm]->register_property(
                "TS1", std::numeric_limits<double>::quiet_NaN(),
                sdbusplus::asio::PropertyPermission::readWrite);
        dimm_temp_inf[dimm]->register_property(
                "SPD_TS", std::numeric_limits<double>::quiet_NaN(),
                sdbusplus::asio::PropertyPermission::readWrite);
        unit = "DegreesC";
        dimm_temp_inf[dimm]->register_property("Unit", unit);
        dimm_temp_inf[dimm]->initialize();

        dimm_voltage_inf[dimm] = objectServer.add_interface(interfacePath,
                                        "xyz.openbmc_project.Dimm.Voltage");
        dimm_voltage_inf[dimm]->register_property(
                "SWA", std::numeric_limits<double>::quiet_NaN(),
                sdbusplus::asio::PropertyPermission::readWrite);
        dimm_voltage_inf[dimm]->register_property(
                "SWB", std::numeric_limits<double>::quiet_NaN(),
                sdbusplus::asio::PropertyPermission::readWrite);
        dimm_voltage_inf[dimm]->register_property(
                "SWC", std::numeric_limits<double>::quiet_NaN(),
                sdbusplus::asio::PropertyPermission::readWrite);
        dimm_voltage_inf[dimm]->register_property(
                "SWD", std::numeric_limits<double>::quiet_NaN(),
                sdbusplus::asio::PropertyPermission::readWrite);
        dimm_voltage_inf[dimm]->register_property(
                "SWE", std::numeric_limits<double>::quiet_NaN(),
                sdbusplus::asio::PropertyPermission::readWrite);
        dimm_voltage_inf[dimm]->register_property(
                "SWF", std::numeric_limits<double>::quiet_NaN(),
                sdbusplus::asio::PropertyPermission::readWrite);
        unit = "Volts";
        dimm_voltage_inf[dimm]->register_property("Unit", unit);
        dimm_voltage_inf[dimm]->initialize();

        dimm_current_inf[dimm] = objectServer.add_interface(interfacePath,
                                        "xyz.openbmc_project.Dimm.Current");
        dimm_current_inf[dimm]->register_property(
                "SWA", std::numeric_limits<double>::quiet_NaN(),
                sdbusplus::asio::PropertyPermission::readWrite);
        dimm_current_inf[dimm]->register_property(
                "SWB", std::numeric_limits<double>::quiet_NaN(),
                sdbusplus::asio::PropertyPermission::readWrite);
        dimm_current_inf[dimm]->register_property(
                "SWC", std::numeric_limits<double>::quiet_NaN(),
                sdbusplus::asio::PropertyPermission::readWrite);
        dimm_current_inf[dimm]->register_property(
                "SWD", std::numeric_limits<double>::quiet_NaN(),
                sdbusplus::asio::PropertyPermission::readWrite);
        dimm_current_inf[dimm]->register_property(
                "SWE", std::numeric_limits<double>::quiet_NaN(),
                sdbusplus::asio::PropertyPermission::readWrite);
        dimm_current_inf[dimm]->register_property(
                "SWF", std::numeric_limits<double>::quiet_NaN(),
                sdbusplus::asio::PropertyPermission::readWrite);
        unit = "Amperes";
        dimm_current_inf[dimm]->register_property("Unit", unit);
        dimm_current_inf[dimm]->initialize();

        dimm_power_inf[dimm] = objectServer.add_interface(interfacePath,
                                        "xyz.openbmc_project.Dimm.Power");
        dimm_power_inf[dimm]->register_property(
                "SWA", std::numeric_limits<double>::quiet_NaN(),
                sdbusplus::asio::PropertyPermission::readWrite);
        dimm_power_inf[dimm]->register_property(
                "SWB", std::numeric_limits<double>::quiet_NaN(),
                sdbusplus::asio::PropertyPermission::readWrite);
        dimm_power_inf[dimm]->register_property(
                "SWC", std::numeric_limits<double>::quiet_NaN(),
                sdbusplus::asio::PropertyPermission::readWrite);
        dimm_power_inf[dimm]->register_property(
                "SWD", std::numeric_limits<double>::quiet_NaN(),
                sdbusplus::asio::PropertyPermission::readWrite);
        dimm_power_inf[dimm]->register_property(
                "SWE", std::numeric_limits<double>::quiet_NaN(),
                sdbusplus::asio::PropertyPermission::readWrite);
        dimm_power_inf[dimm]->register_property(
                "SWF", std::numeric_limits<double>::quiet_NaN(),
                sdbusplus::asio::PropertyPermission::readWrite);
        unit = "Watts";
        dimm_power_inf[dimm]->register_property("Unit", unit);
        dimm_power_inf[dimm]->initialize();

        dimm_statusReg_inf[dimm] = objectServer.add_interface(interfacePath,
                                        "xyz.openbmc_project.Dimm.StatusReg");
        dimm_statusReg_inf[dimm]->register_property(
                "0x04", uint8_t(0), sdbusplus::asio::PropertyPermission::readWrite);
        dimm_statusReg_inf[dimm]->register_property(
                "0x05", uint8_t(0), sdbusplus::asio::PropertyPermission::readWrite);
        dimm_statusReg_inf[dimm]->register_property(
                "0x06", uint8_t(0), sdbusplus::asio::PropertyPermission::readWrite);
        dimm_statusReg_inf[dimm]->register_property(
                "0x07", uint8_t(0), sdbusplus::asio::PropertyPermission::readWrite);
        dimm_statusReg_inf[dimm]->register_property(
                "0x08", uint8_t(0), sdbusplus::asio::PropertyPermission::readWrite);
        dimm_statusReg_inf[dimm]->register_property(
                "0x09", uint8_t(0), sdbusplus::asio::PropertyPermission::readWrite);
        dimm_statusReg_inf[dimm]->register_property(
                "0x0a", uint8_t(0), sdbusplus::asio::PropertyPermission::readWrite);
        dimm_statusReg_inf[dimm]->register_property(
                "0x0b", uint8_t(0), sdbusplus::asio::PropertyPermission::readWrite);
        dimm_statusReg_inf[dimm]->initialize();

        dimm_errCode_inf[dimm] = objectServer.add_interface(interfacePath,
                                        "xyz.openbmc_project.Dimm.ErrCode");
        dimm_errCode_inf[dimm]->register_property(
                "0x32", uint8_t(0), sdbusplus::asio::PropertyPermission::readWrite);
        dimm_errCode_inf[dimm]->initialize();

    }

    double pollRate = 0.1;
    auto reader = std::make_shared<DIMMSpdReader>(io, objectServer, pollRate);

    reader->init();
    reader->getdimmI3cSwitchState(systemBus);
    reader->setupMatches(static_cast<sdbusplus::bus_t&>(*systemBus));

    io.run();
}
