/**
 * Copyright © 2020 IBM 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 "manager.hpp"

#include "chassis.hpp"
#include "config_file_parser.hpp"
#include "exception_utils.hpp"
#include "rule.hpp"
#include "utility.hpp"

#include <xyz/openbmc_project/Common/error.hpp>
#include <xyz/openbmc_project/State/Chassis/server.hpp>

#include <algorithm>
#include <chrono>
#include <exception>
#include <functional>
#include <map>
#include <thread>
#include <tuple>
#include <utility>
#include <variant>

namespace phosphor::power::regulators
{

namespace fs = std::filesystem;

constexpr auto busName = "xyz.openbmc_project.Power.Regulators";
constexpr auto managerObjPath = "/xyz/openbmc_project/power/regulators/manager";
constexpr auto compatibleIntf =
    "xyz.openbmc_project.Configuration.IBMCompatibleSystem";
constexpr auto compatibleNamesProp = "Names";
constexpr auto chassisStatePath = "/xyz/openbmc_project/state/chassis0";
constexpr auto chassisStateIntf = "xyz.openbmc_project.State.Chassis";
constexpr auto chassisStateProp = "CurrentPowerState";
constexpr std::chrono::minutes maxTimeToWaitForCompatTypes{5};

using PowerState =
    sdbusplus::xyz::openbmc_project::State::server::Chassis::PowerState;

/**
 * Default configuration file name.  This is used when the system does not
 * implement the D-Bus compatible interface.
 */
constexpr auto defaultConfigFileName = "config.json";

/**
 * Standard configuration file directory.  This directory is part of the
 * firmware install image.  It contains the standard version of the config file.
 */
const fs::path standardConfigFileDir{"/usr/share/phosphor-regulators"};

/**
 * Test configuration file directory.  This directory can contain a test version
 * of the config file.  The test version will override the standard version.
 */
const fs::path testConfigFileDir{"/etc/phosphor-regulators"};

Manager::Manager(sdbusplus::bus_t& bus, const sdeventplus::Event& event) :
    ManagerObject{bus, managerObjPath}, bus{bus}, eventLoop{event},
    services{bus}, phaseFaultTimer{event,
                                   std::bind(&Manager::phaseFaultTimerExpired,
                                             this)},
    sensorTimer{event, std::bind(&Manager::sensorTimerExpired, this)}
{
    // Subscribe to D-Bus interfacesAdded signal from Entity Manager.  This
    // notifies us if the compatible interface becomes available later.
    std::string matchStr = sdbusplus::bus::match::rules::interfacesAdded() +
                           sdbusplus::bus::match::rules::sender(
                               "xyz.openbmc_project.EntityManager");
    std::unique_ptr<sdbusplus::bus::match_t> matchPtr =
        std::make_unique<sdbusplus::bus::match_t>(
            bus, matchStr,
            std::bind(&Manager::interfacesAddedHandler, this,
                      std::placeholders::_1));
    signals.emplace_back(std::move(matchPtr));

    // Try to find compatible system types using D-Bus compatible interface.
    // Note that it might not be supported on this system, or the service that
    // provides the interface might not be running yet.
    findCompatibleSystemTypes();

    // Try to find and load the JSON configuration file
    loadConfigFile();

    // Obtain D-Bus service name
    bus.request_name(busName);

    // If system is already powered on, enable monitoring
    if (isSystemPoweredOn())
    {
        monitor(true);
    }
}

void Manager::configure()
{
    // Clear any cached data or error history related to hardware devices
    clearHardwareData();

    // Wait until the config file has been loaded or hit max wait time
    waitUntilConfigFileLoaded();

    // Verify config file has been loaded and System object is valid
    if (isConfigFileLoaded())
    {
        // Configure the regulator devices in the system
        system->configure(services);
    }
    else
    {
        // Write error message to journal
        services.getJournal().logError("Unable to configure regulator devices: "
                                       "Configuration file not loaded");

        // Log critical error since regulators could not be configured.  Could
        // cause hardware damage if default regulator settings are very wrong.
        services.getErrorLogging().logConfigFileError(Entry::Level::Critical,
                                                      services.getJournal());

        // Throw InternalFailure to propogate error status to D-Bus client
        throw sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure{};
    }
}

void Manager::interfacesAddedHandler(sdbusplus::message_t& msg)
{
    // Verify message is valid
    if (!msg)
    {
        return;
    }

    try
    {
        // Read object path for object that was created or had interface added
        sdbusplus::message::object_path objPath;
        msg.read(objPath);

        // Read the dictionary whose keys are interface names and whose values
        // are dictionaries containing the interface property names and values
        std::map<std::string,
                 std::map<std::string, std::variant<std::vector<std::string>>>>
            intfProp;
        msg.read(intfProp);

        // Find the compatible interface, if present
        auto itIntf = intfProp.find(compatibleIntf);
        if (itIntf != intfProp.cend())
        {
            // Find the Names property of the compatible interface, if present
            auto itProp = itIntf->second.find(compatibleNamesProp);
            if (itProp != itIntf->second.cend())
            {
                // Get value of Names property
                auto propValue = std::get<0>(itProp->second);
                if (!propValue.empty())
                {
                    // Store list of compatible system types
                    compatibleSystemTypes = propValue;

                    // Find and load JSON config file based on system types
                    loadConfigFile();
                }
            }
        }
    }
    catch (const std::exception&)
    {
        // Error trying to read interfacesAdded message.  One possible cause
        // could be a property whose value is not a std::vector<std::string>.
    }
}

void Manager::monitor(bool enable)
{
    // Check whether already in the requested monitoring state
    if (enable == isMonitoringEnabled)
    {
        return;
    }

    isMonitoringEnabled = enable;
    if (isMonitoringEnabled)
    {
        services.getJournal().logDebug("Monitoring enabled");

        // Restart phase fault detection timer with repeating 15 second interval
        phaseFaultTimer.restart(std::chrono::seconds(15));

        // Restart sensor monitoring timer with repeating 1 second interval
        sensorTimer.restart(std::chrono::seconds(1));

        // Enable sensors service; put all sensors in an active state
        services.getSensors().enable();
    }
    else
    {
        services.getJournal().logDebug("Monitoring disabled");

        // Disable timers
        phaseFaultTimer.setEnabled(false);
        sensorTimer.setEnabled(false);

        // Disable sensors service; put all sensors in an inactive state
        services.getSensors().disable();

        // Verify config file has been loaded and System object is valid
        if (isConfigFileLoaded())
        {
            // Close the regulator devices in the system.  Monitoring is
            // normally disabled because the system is being powered off.  The
            // devices should be closed in case hardware is removed or replaced
            // while the system is powered off.
            system->closeDevices(services);
        }
    }
}

void Manager::phaseFaultTimerExpired()
{
    // Verify config file has been loaded and System object is valid
    if (isConfigFileLoaded())
    {
        // Detect redundant phase faults in regulator devices in the system
        system->detectPhaseFaults(services);
    }
}

void Manager::sensorTimerExpired()
{
    // Notify sensors service that a sensor monitoring cycle is starting
    services.getSensors().startCycle();

    // Verify config file has been loaded and System object is valid
    if (isConfigFileLoaded())
    {
        // Monitor sensors for the voltage rails in the system
        system->monitorSensors(services);
    }

    // Notify sensors service that current sensor monitoring cycle has ended
    services.getSensors().endCycle();
}

void Manager::sighupHandler(sdeventplus::source::Signal& /*sigSrc*/,
                            const struct signalfd_siginfo* /*sigInfo*/)
{
    // Reload the JSON configuration file
    loadConfigFile();
}

void Manager::clearHardwareData()
{
    // Clear any cached hardware presence data and VPD values
    services.getPresenceService().clearCache();
    services.getVPD().clearCache();

    // Verify config file has been loaded and System object is valid
    if (isConfigFileLoaded())
    {
        // Clear any cached hardware data in the System object
        system->clearCache();

        // Clear error history related to hardware devices in the System object
        system->clearErrorHistory();
    }
}

void Manager::findCompatibleSystemTypes()
{
    using namespace phosphor::power::util;

    try
    {
        // Query object mapper for object paths that implement the compatible
        // interface.  Returns a map of object paths to a map of services names
        // to their interfaces.
        DbusSubtree subTree = getSubTree(bus, "/xyz/openbmc_project/inventory",
                                         compatibleIntf, 0);

        // Get the first object path
        auto objectIt = subTree.cbegin();
        if (objectIt != subTree.cend())
        {
            std::string objPath = objectIt->first;

            // Get the first service name
            auto serviceIt = objectIt->second.cbegin();
            if (serviceIt != objectIt->second.cend())
            {
                std::string service = serviceIt->first;
                if (!service.empty())
                {
                    // Get compatible system types property value
                    getProperty(compatibleIntf, compatibleNamesProp, objPath,
                                service, bus, compatibleSystemTypes);
                }
            }
        }
    }
    catch (const std::exception&)
    {
        // Compatible system types information is not available.  The current
        // system might not support the interface, or the service that
        // implements the interface might not be running yet.
    }
}

fs::path Manager::findConfigFile()
{
    // Build list of possible base file names
    std::vector<std::string> fileNames{};

    // Add possible file names based on compatible system types (if any)
    for (const std::string& systemType : compatibleSystemTypes)
    {
        // Replace all spaces and commas in system type name with underscores
        std::string fileName{systemType};
        std::replace(fileName.begin(), fileName.end(), ' ', '_');
        std::replace(fileName.begin(), fileName.end(), ',', '_');

        // Append .json suffix and add to list
        fileName.append(".json");
        fileNames.emplace_back(fileName);
    }

    // Add default file name for systems that don't use compatible interface
    fileNames.emplace_back(defaultConfigFileName);

    // Look for a config file with one of the possible base names
    for (const std::string& fileName : fileNames)
    {
        // Check if file exists in test directory
        fs::path pathName{testConfigFileDir / fileName};
        if (fs::exists(pathName))
        {
            return pathName;
        }

        // Check if file exists in standard directory
        pathName = standardConfigFileDir / fileName;
        if (fs::exists(pathName))
        {
            return pathName;
        }
    }

    // No config file found; return empty path
    return fs::path{};
}

bool Manager::isSystemPoweredOn()
{
    bool isOn{false};

    try
    {
        // Get D-Bus property that contains the current power state for
        // chassis0, which represents the entire system (all chassis)
        using namespace phosphor::power::util;
        auto service = getService(chassisStatePath, chassisStateIntf, bus);
        if (!service.empty())
        {
            PowerState currentPowerState;
            getProperty(chassisStateIntf, chassisStateProp, chassisStatePath,
                        service, bus, currentPowerState);
            if (currentPowerState == PowerState::On)
            {
                isOn = true;
            }
        }
    }
    catch (const std::exception& e)
    {
        // Current power state might not be available yet.  The regulators
        // application can start before the power state is published on D-Bus.
    }

    return isOn;
}

void Manager::loadConfigFile()
{
    try
    {
        // Find the absolute path to the config file
        fs::path pathName = findConfigFile();
        if (!pathName.empty())
        {
            // Log info message in journal; config file path is important
            services.getJournal().logInfo("Loading configuration file " +
                                          pathName.string());

            // Parse the config file
            std::vector<std::unique_ptr<Rule>> rules{};
            std::vector<std::unique_ptr<Chassis>> chassis{};
            std::tie(rules, chassis) = config_file_parser::parse(pathName);

            // Store config file information in a new System object.  The old
            // System object, if any, is automatically deleted.
            system =
                std::make_unique<System>(std::move(rules), std::move(chassis));
        }
    }
    catch (const std::exception& e)
    {
        // Log error messages in journal
        services.getJournal().logError(exception_utils::getMessages(e));
        services.getJournal().logError("Unable to load configuration file");

        // Log error
        services.getErrorLogging().logConfigFileError(Entry::Level::Error,
                                                      services.getJournal());
    }
}

void Manager::waitUntilConfigFileLoaded()
{
    // If config file not loaded and list of compatible system types is empty
    if (!isConfigFileLoaded() && compatibleSystemTypes.empty())
    {
        // Loop until compatible system types found or waited max amount of time
        auto start = std::chrono::system_clock::now();
        std::chrono::system_clock::duration timeWaited{0};
        while (compatibleSystemTypes.empty() &&
               (timeWaited <= maxTimeToWaitForCompatTypes))
        {
            // Try to find list of compatible system types
            findCompatibleSystemTypes();
            if (!compatibleSystemTypes.empty())
            {
                // Compatible system types found; try to load config file
                loadConfigFile();
            }
            else
            {
                // Sleep 5 seconds
                using namespace std::chrono_literals;
                std::this_thread::sleep_for(5s);
            }
            timeWaited = std::chrono::system_clock::now() - start;
        }
    }
}

} // namespace phosphor::power::regulators
