#include <iostream>
#include <string>
#include <algorithm>
#include <phosphor-logging/log.hpp>
#include <xyz/openbmc_project/Led/Physical/server.hpp>
#include "manager.hpp"
namespace phosphor
{
namespace led
{

// Assert -or- De-assert
bool Manager::setGroupState(const std::string& path, bool assert,
                            group& ledsAssert, group& ledsDeAssert)
{
    if (assert)
    {
        assertedGroups.insert(&ledMap.at(path));
    }
    else
    {
        auto search = assertedGroups.find(&ledMap.at(path));
        if (search != assertedGroups.end())
        {
            assertedGroups.erase(&ledMap.at(path));
        }
    }

    // This will contain the union of what's already in the asserted group
    group desiredState {};
    for(const auto& grp : assertedGroups)
    {
        desiredState.insert(grp->cbegin(), grp->cend());
    }

    // Find difference between Combined and Desired to identify
    // which LEDs are getting altered
    group transient {};
    std::set_difference(combinedState.begin(), combinedState.end(),
                        desiredState.begin(), desiredState.end(),
                        std::inserter(transient, transient.begin()),
                        ledComp);
    if(transient.size())
    {
        // Find common LEDs between transient and Desired to know if some LEDs
        // are changing state and not really getting DeAsserted
        group ledsTransient {};
        std::set_intersection(transient.begin(),transient.end(),
                            desiredState.begin(), desiredState.end(),
                            std::inserter(ledsTransient, ledsTransient.begin()),
                            ledLess);

        // Find difference between above 2 to identify those LEDs which are
        // really getting DeAsserted
        std::set_difference(transient.begin(),transient.end(),
                            ledsTransient.begin(),ledsTransient.end(),
                            std::inserter(ledsDeAssert, ledsDeAssert.begin()),
                            ledLess);

        // Remove the elements from Current that are being DeAsserted.
        if(ledsDeAssert.size())
        {
            // Power off LEDs that are to be really DeAsserted
            for (auto& it:ledsDeAssert)
            {
                // Update LEDs in "physically asserted" set by removing those
                // LEDs which are De-Asserted
                auto found = currentState.find(it);
                if (found != currentState.end())
                {
                    currentState.erase(found);
                }
            }
        }
    }

    // Now LEDs that are to be Asserted. These could either be fresh asserts
    // -or- change between [On]<-->[Blink]
    group temp {};
    std::unique_copy(desiredState.begin(), desiredState.end(),
                     std::inserter(temp, temp.begin()),
                     ledEqual);
    if(temp.size())
    {
        // Find difference between [desired to be Asserted] and those LEDs
        // that are physically asserted currently.
        std::set_difference(temp.begin(), temp.end(),
                            currentState.begin(), currentState.end(),
                            std::inserter(ledsAssert, ledsAssert.begin()),
                            ledComp);
    }

    // Update the current actual and desired(the virtual actual)
    currentState = std::move(temp);
    combinedState = std::move(desiredState);

    // If we survive, then set the state accordingly.
    return assert;
}

/** @brief Run through the map and apply action on the LEDs */
void Manager::driveLEDs(group& ledsAssert, group& ledsDeAssert)
{
    // Map of physical LED dbus paths to their Service providers
    populateObjectMap();

    if (phyLeds.empty())
    {
        // Error message is inside the map construction logic.
        return;
    }

    // This order of LED operation is important.
    if (ledsDeAssert.size())
    {
        std::cout << "De-Asserting LEDs" << std::endl;
        for (const auto& it: ledsDeAssert)
        {
            std::string objPath = std::string(PHY_LED_PATH) + it.name;
            drivePhysicalLED(objPath, Layout::Action::Off, it.dutyOn);
        }
    }

    if(ledsAssert.size())
    {
        std::cout << "Asserting LEDs" << std::endl;
        for (const auto& it: ledsAssert)
        {
            std::string objPath = std::string(PHY_LED_PATH) + it.name;
            drivePhysicalLED(objPath, it.action, it.dutyOn);
        }
    }
    return;
}

// Calls into driving physical LED post choosing the action
void Manager::drivePhysicalLED(const std::string& objPath,
                               Layout::Action action,
                               uint8_t dutyOn)
{
    using namespace phosphor::logging;

    auto service = phyLeds.find(objPath);
    if (service == phyLeds.end() || service->second.empty())
    {
        log<level::ERR>("No service providers for physical LED",
                entry("PATH=%s",objPath.c_str()));
        return;
    }

   // If Blink, set its property
   if (action == Layout::Action::Blink)
   {
       drivePhysicalLED(service->second, objPath, "DutyOn", dutyOn);
   }
   drivePhysicalLED(service->second, objPath, "State",
           getPhysicalAction(action));
   return;
}

/** @brief Returns action string based on enum */
std::string Manager::getPhysicalAction(Layout::Action action)
{
    namespace server = sdbusplus::xyz::openbmc_project::Led::server;

    // TODO: openbmc/phosphor-led-manager#5
    //    Somehow need to use the generated Action enum than giving one
    //    in ledlayout.
    if(action == Layout::Action::On)
    {
        return server::convertForMessage(server::Physical::Action::On);
    }
    else if(action == Layout::Action::Blink)
    {
        return server::convertForMessage(server::Physical::Action::Blink);
    }
    else
    {
        return server::convertForMessage(server::Physical::Action::Off);
    }
}

/** Populates a map with physical LED paths to its service providers */
void Manager::populateObjectMap()
{
    using namespace phosphor::logging;

    // Mapper dbus constructs
    constexpr auto MAPPER_BUSNAME   = "xyz.openbmc_project.ObjectMapper";
    constexpr auto MAPPER_OBJ_PATH  = "/xyz/openbmc_project/object_mapper";
    constexpr auto MAPPER_IFACE     = "xyz.openbmc_project.ObjectMapper";

    // Needed to be passed to get the SubTree level
    auto depth = 0;

    // Clean start
    phyLeds.clear();

    // Make a mapper call
    auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
                                          MAPPER_IFACE, "GetSubTree");
    // Cook rest of the things.
    mapperCall.append(PHY_LED_PATH);
    mapperCall.append(depth);
    mapperCall.append(std::vector<std::string>({PHY_LED_IFACE}));

    auto reply = bus.call(mapperCall);
    if (reply.is_method_error())
    {
        // Its okay if we do not see a corresponding physical LED.
        log<level::INFO>("Error looking up Physical LED services",
                entry("PATH=%s",PHY_LED_PATH));
        return;
    }

    // Response by mapper in the case of success
    std::map<std::string, std::map<std::string,
             std::vector<std::string>>> objectTree;

    // This is the dict of object paths - service names - interfaces
    reply.read(objectTree);
    if (objectTree.empty())
    {
        log<level::INFO>("Physical LED lookup did not return any services",
                entry("PATH=%s",PHY_LED_PATH));
        return;
    }

    // Now construct our path -> Service name map.
    for (const auto& iter : objectTree)
    {
        phyLeds.emplace(iter.first, iter.second.begin()->first);
    }
    return;
}

} // namespace led
} // namespace phosphor
