/*
// 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 "NVMeSensor.hpp"

#include <boost/asio/deadline_timer.hpp>

#include <regex>

static constexpr const char* sensorType =
    "xyz.openbmc_project.Configuration.NVME1000";

static NVMEMap nvmeDeviceMap;

static constexpr bool DEBUG = false;

NVMEMap& getNVMEMap()
{
    return nvmeDeviceMap;
}

void createSensors(boost::asio::io_service& io,
                   sdbusplus::asio::object_server& objectServer,
                   std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
{

    auto getter = std::make_shared<GetSensorConfiguration>(
        dbusConnection,
        std::move([&io, &objectServer, &dbusConnection](
                      const ManagedObjectType& sensorConfigurations) {
            // todo: it'd be better to only update the ones we care about
            nvmeDeviceMap.clear();

            // iterate through all found configurations
            for (const std::pair<sdbusplus::message::object_path, SensorData>&
                     sensor : sensorConfigurations)
            {
                const SensorData& sensorData = sensor.second;
                const std::string& interfacePath = sensor.first.str;
                const std::pair<
                    std::string,
                    boost::container::flat_map<std::string, BasicVariantType>>*
                    baseConfiguration = nullptr;

                // find base configuration
                auto sensorBase = sensor.second.find(sensorType);
                if (sensorBase != sensor.second.end())
                {
                    baseConfiguration = &(*sensorBase);
                }

                if (baseConfiguration == nullptr)
                {
                    continue;
                }
                auto findBus = baseConfiguration->second.find("Bus");
                if (findBus == baseConfiguration->second.end())
                {
                    continue;
                }

                unsigned int busNumber =
                    std::visit(VariantToUnsignedIntVisitor(), findBus->second);

                auto findSensorName = baseConfiguration->second.find("Name");
                if (findSensorName == baseConfiguration->second.end())
                {
                    std::cerr << "could not determine configuration name for "
                              << interfacePath << "\n";
                    continue;
                }
                std::string sensorName =
                    std::get<std::string>(findSensorName->second);

                std::vector<thresholds::Threshold> sensorThresholds;

                if (!parseThresholdsFromConfig(sensorData, sensorThresholds))
                {
                    std::cerr << "error populating thresholds for "
                              << sensorName << "\n";
                }

                int rootBus = busNumber;

                std::string muxPath = "/sys/bus/i2c/devices/i2c-" +
                                      std::to_string(busNumber) + "/mux_device";

                if (std::filesystem::is_symlink(muxPath))
                {
                    std::string rootName =
                        std::filesystem::read_symlink(muxPath).filename();
                    size_t dash = rootName.find("-");
                    if (dash == std::string::npos)
                    {
                        std::cerr << "Error finding root bus for " << rootName
                                  << "\n";
                        continue;
                    }
                    rootBus = std::stoi(rootName.substr(0, dash));
                }

                std::shared_ptr<NVMeContext> context;
                auto findRoot = nvmeDeviceMap.find(rootBus);
                if (findRoot != nvmeDeviceMap.end())
                {
                    context = findRoot->second;
                }
                else
                {
                    context = std::make_shared<NVMeContext>(io, rootBus);
                    nvmeDeviceMap[rootBus] = context;
                }

                std::shared_ptr<NVMeSensor> sensorPtr =
                    std::make_shared<NVMeSensor>(
                        objectServer, io, dbusConnection, sensorName,
                        std::move(sensorThresholds), interfacePath, busNumber);

                context->sensors.emplace_back(sensorPtr);
            }
            for (const auto& [_, context] : nvmeDeviceMap)
            {
                context->pollNVMeDevices();
            }
        }));
    getter->getConfiguration(std::vector<std::string>{sensorType});
}

int main()
{
    boost::asio::io_service io;
    auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
    systemBus->request_name("xyz.openbmc_project.NVMeSensor");
    sdbusplus::asio::object_server objectServer(systemBus);
    nvmeMCTP::init();

    io.post([&]() { createSensors(io, objectServer, systemBus); });

    boost::asio::deadline_timer filterTimer(io);
    std::function<void(sdbusplus::message::message&)> eventHandler =
        [&filterTimer, &io, &objectServer,
         &systemBus](sdbusplus::message::message& message) {
            // this implicitly cancels the timer
            filterTimer.expires_from_now(boost::posix_time::seconds(1));

            filterTimer.async_wait([&](const boost::system::error_code& ec) {
                if (ec == boost::asio::error::operation_aborted)
                {
                    return; // we're being canceled
                }
                else if (ec)
                {
                    std::cerr << "Error: " << ec.message() << "\n";
                    return;
                }

                createSensors(io, objectServer, systemBus);
            });
        };

    sdbusplus::bus::match::match configMatch(
        static_cast<sdbusplus::bus::bus&>(*systemBus),
        "type='signal',member='PropertiesChanged',path_namespace='" +
            std::string(inventoryPath) + "',arg0namespace='" +
            std::string(sensorType) + "'",
        eventHandler);

    io.run();
}
