/**
 * Copyright © 2017 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 <algorithm>
#include <phosphor-logging/log.hpp>
#include "fan.hpp"
#include "types.hpp"
#include "utility.hpp"

namespace phosphor
{
namespace fan
{
namespace monitor
{

using namespace phosphor::logging;
using TimerType = phosphor::fan::util::Timer::TimerType;

constexpr auto INVENTORY_PATH = "/xyz/openbmc_project/inventory";
constexpr auto INVENTORY_INTF = "xyz.openbmc_project.Inventory.Manager";

constexpr auto FUNCTIONAL_PROPERTY = "Functional";
constexpr auto OPERATIONAL_STATUS_INTF  =
    "xyz.openbmc_project.State.Decorator.OperationalStatus";


Fan::Fan(sdbusplus::bus::bus& bus,
         phosphor::fan::event::EventPtr&  events,
         const FanDefinition& def) :
    _bus(bus),
    _name(std::get<fanNameField>(def)),
    _deviation(std::get<fanDeviationField>(def)),
    _numSensorFailsForNonFunc(std::get<numSensorFailsForNonfuncField>(def))
{
    auto& sensors = std::get<sensorListField>(def);

    for (auto& s : sensors)
    {
        _sensors.emplace_back(
            std::make_unique<TachSensor>(bus,
                                         *this,
                                         std::get<sensorNameField>(s),
                                         std::get<hasTargetField>(s),
                                         std::get<timeoutField>(def),
                                         events));
    }

    //Start from a known state of functional
    updateInventory(true);

    //The TachSensors will now have already read the input
    //and target values, so check them.
    tachChanged();
}


void Fan::tachChanged()
{
    for (auto& s : _sensors)
    {
        tachChanged(*s);
    }
}


void Fan::tachChanged(TachSensor& sensor)
{
    auto& timer = sensor.getTimer();
    auto running = timer.running();

    //If this sensor is out of range at this moment, start
    //its timer, at the end of which the inventory
    //for the fan may get updated to not functional.

    //If this sensor is OK, put everything back into a good state.

    if (outOfRange(sensor))
    {
        if (sensor.functional() && !running)
        {
            timer.start(sensor.getTimeout(), TimerType::oneshot);
        }
    }
    else
    {
        if (!sensor.functional())
        {
            sensor.setFunctional(true);
        }

        if (running)
        {
            timer.stop();
        }

        //If the fan was nonfunctional and enough sensors are now OK,
        //the fan can go back to functional
        if (!_functional && !tooManySensorsNonfunctional())
        {
            log<level::INFO>("Setting a fan back to functional",
                             entry("FAN=%s", _name.c_str()));

            updateInventory(true);
        }
    }
}


uint64_t Fan::getTargetSpeed(const TachSensor& sensor)
{
    uint64_t target = 0;

    if (sensor.hasTarget())
    {
        target = sensor.getTarget();
    }
    else
    {
        //The sensor doesn't support a target,
        //so get it from another sensor.
        auto s = std::find_if(_sensors.begin(), _sensors.end(),
                              [](const auto& s)
                              {
                                  return s->hasTarget();
                              });

        if (s != _sensors.end())
        {
            target = (*s)->getTarget();
        }
    }

    return target;
}


bool Fan::tooManySensorsNonfunctional()
{
    size_t numFailed =  std::count_if(_sensors.begin(), _sensors.end(),
                                      [](const auto& s)
                                      {
                                          return !s->functional();
                                      });

    return (numFailed >= _numSensorFailsForNonFunc);
}


bool Fan::outOfRange(const TachSensor& sensor)
{
    auto actual = static_cast<uint64_t>(sensor.getInput());
    auto target = getTargetSpeed(sensor);

    uint64_t min = target * (100 - _deviation) / 100;
    uint64_t max = target * (100 + _deviation) / 100;

    if ((actual < min) || (actual > max))
    {
        return true;
    }

    return false;
}


void Fan::timerExpired(TachSensor& sensor)
{
    sensor.setFunctional(false);

    //If the fan is currently functional, but too many
    //contained sensors are now nonfunctional, update
    //the whole fan nonfunctional.

    if (_functional && tooManySensorsNonfunctional())
    {
        log<level::ERR>("Setting a fan to nonfunctional",
                        entry("FAN=%s", _name.c_str()));

        updateInventory(false);
    }
}


void Fan::updateInventory(bool functional)
{
    ObjectMap objectMap = getObjectMap(functional);
    std::string service;

    service = phosphor::fan::util::getInvService(_bus);

    auto msg = _bus.new_method_call(service.c_str(),
                                   INVENTORY_PATH,
                                   INVENTORY_INTF,
                                   "Notify");

    msg.append(std::move(objectMap));
    auto response = _bus.call(msg);
    if (response.is_method_error())
    {
        log<level::ERR>("Error in Notify call to update inventory");
        return;
    }

    //This will always track the current state of the inventory.
    _functional = functional;
}


Fan::ObjectMap Fan::getObjectMap(bool functional)
{
    ObjectMap objectMap;
    InterfaceMap interfaceMap;
    PropertyMap propertyMap;

    propertyMap.emplace(FUNCTIONAL_PROPERTY, functional);
    interfaceMap.emplace(OPERATIONAL_STATUS_INTF, std::move(propertyMap));
    objectMap.emplace(_name, std::move(interfaceMap));

    return objectMap;
}


}
}
}
