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

#include <fmt/format.h>

#include <phosphor-logging/log.hpp>

#include <bitset>

namespace openpower::pels::service_indicators
{

using namespace phosphor::logging;

static constexpr auto platformSaiLedGroup =
    "/xyz/openbmc_project/led/groups/platform_system_attention_indicator";

std::unique_ptr<Policy> getPolicy(const DataInterfaceBase& dataIface)
{
    // At the moment there is just one type of policy.
    return std::make_unique<LightPath>(dataIface);
}

bool LightPath::ignore(const PEL& pel) const
{
    auto creator = pel.privateHeader().creatorID();

    // Don't ignore serviceable BMC or hostboot errors
    if ((static_cast<CreatorID>(creator) == CreatorID::openBMC) ||
        (static_cast<CreatorID>(creator) == CreatorID::hostboot))
    {
        std::bitset<16> actionFlags{pel.userHeader().actionFlags()};
        if (actionFlags.test(serviceActionFlagBit))
        {
            return false;
        }
    }

    return true;
}

void LightPath::activate(const PEL& pel)
{
    if (ignore(pel))
    {
        return;
    }

    // Now that we've gotten this far, we'll need to turn on
    // the system attention indicator if we don't find other
    // indicators to turn on.
    bool sai = true;
    auto src = pel.primarySRC();
    const auto& calloutsObj = (*src)->callouts();

    if (calloutsObj && !calloutsObj->callouts().empty())
    {
        const auto& callouts = calloutsObj->callouts();

        // From the callouts, find the location codes whose
        // LEDs need to be turned on.
        auto locCodes = getLocationCodes(callouts);
        if (!locCodes.empty())
        {
            // Find the inventory paths for those location codes.
            auto paths = getInventoryPaths(locCodes);
            if (!paths.empty())
            {
                setNotFunctional(paths);
                createCriticalAssociation(paths);
                sai = false;
            }
        }
    }

    if (sai)
    {
        try
        {
            _dataIface.assertLEDGroup(platformSaiLedGroup, true);
        }
        catch (const std::exception& e)
        {
            log<level::ERR>(
                fmt::format("Failed to assert platform SAI LED group: {}",
                            e.what())
                    .c_str());
        }
    }
}

std::vector<std::string> LightPath::getLocationCodes(
    const std::vector<std::unique_ptr<src::Callout>>& callouts) const
{
    std::vector<std::string> locCodes;
    bool firstCallout = true;
    uint8_t firstCalloutPriority;

    // Collect location codes for the first group of callouts,
    // where a group can be:
    //  * a single medium priority callout
    //  * one or more high priority callouts
    //  * one or more medium group a priority callouts
    //
    // All callouts in the group must be hardware callouts.

    for (const auto& callout : callouts)
    {
        if (firstCallout)
        {
            firstCallout = false;

            firstCalloutPriority = callout->priority();

            // If the first callout is High, Medium, or Medium
            // group A, and is a hardware callout, then we
            // want it.
            if (isRequiredPriority(firstCalloutPriority) &&
                isHardwareCallout(*callout))
            {
                locCodes.push_back(callout->locationCode());
            }
            else
            {
                break;
            }

            // By definition a medium priority callout can't be part
            // of a group, so no need to look for more.
            if (static_cast<CalloutPriority>(firstCalloutPriority) ==
                CalloutPriority::medium)
            {
                break;
            }
        }
        else
        {
            // Only continue while the callouts are the same
            // priority as the first callout.
            if (callout->priority() != firstCalloutPriority)
            {
                break;
            }

            // If any callout in the group isn't a hardware callout,
            // then don't light up any LEDs at all.
            if (!isHardwareCallout(*callout))
            {
                locCodes.clear();
                break;
            }

            locCodes.push_back(callout->locationCode());
        }
    }

    return locCodes;
}

bool LightPath::isRequiredPriority(uint8_t priority) const
{
    auto calloutPriority = static_cast<CalloutPriority>(priority);
    return (calloutPriority == CalloutPriority::high) ||
           (calloutPriority == CalloutPriority::medium) ||
           (calloutPriority == CalloutPriority::mediumGroupA);
}

bool LightPath::isHardwareCallout(const src::Callout& callout) const
{
    const auto& fruIdentity = callout.fruIdentity();
    if (fruIdentity)
    {
        return (callout.locationCodeSize() != 0) &&
               ((fruIdentity->failingComponentType() ==
                 src::FRUIdentity::hardwareFRU) ||
                (fruIdentity->failingComponentType() ==
                 src::FRUIdentity::symbolicFRUTrustedLocCode));
    }

    return false;
}

std::vector<std::string> LightPath::getInventoryPaths(
    const std::vector<std::string>& locationCodes) const
{
    std::vector<std::string> paths;

    for (const auto& locCode : locationCodes)
    {
        try
        {
            auto inventoryPath = _dataIface.getInventoryFromLocCode(locCode, 0,
                                                                    true);
            paths.push_back(std::move(inventoryPath));
        }
        catch (const std::exception& e)
        {
            log<level::ERR>(fmt::format("Could not get inventory path for "
                                        "location code {} ({}).",
                                        locCode, e.what())
                                .c_str());

            // Unless we can set the LEDs for all FRUs, we can't turn
            // on any of them, so clear the list and quit.
            paths.clear();
            break;
        }
    }

    return paths;
}

void LightPath::setNotFunctional(
    const std::vector<std::string>& inventoryPaths) const
{
    for (const auto& path : inventoryPaths)
    {
        try
        {
            _dataIface.setFunctional(path, false);
        }
        catch (const std::exception& e)
        {
            log<level::INFO>(
                fmt::format("Could not write Functional property on {} ({})",
                            path, e.what())
                    .c_str());
        }
    }
}

void LightPath::createCriticalAssociation(
    const std::vector<std::string>& inventoryPaths) const
{
    for (const auto& path : inventoryPaths)
    {
        try
        {
            _dataIface.setCriticalAssociation(path);
        }
        catch (const std::exception& e)
        {
            log<level::INFO>(
                fmt::format(
                    "Could not set critical association on object path {} ({})",
                    path, e.what())
                    .c_str());
        }
    }
}

} // namespace openpower::pels::service_indicators
