/**
 * Copyright © 2019 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.
 */
#pragma once

#include "configuration.hpp"
#include "sensor_monitoring.hpp"
#include "services.hpp"

#include <memory>
#include <string>
#include <utility>

namespace phosphor::power::regulators
{

// Forward declarations to avoid circular dependencies
class Chassis;
class Device;
class System;

/**
 * @class Rail
 *
 * A voltage rail produced by a voltage regulator.
 *
 * Voltage regulators produce one or more rails.  Each rail typically provides a
 * different output voltage level, such as 1.1V.
 */
class Rail
{
  public:
    // Specify which compiler-generated methods we want
    Rail() = delete;
    Rail(const Rail&) = delete;
    Rail(Rail&&) = delete;
    Rail& operator=(const Rail&) = delete;
    Rail& operator=(Rail&&) = delete;
    ~Rail() = default;

    /**
     * Constructor.
     *
     * @param id unique rail ID
     * @param configuration configuration changes to apply to this rail, if any
     * @param sensorMonitoring sensor monitoring for this rail, if any
     */
    explicit Rail(
        const std::string& id,
        std::unique_ptr<Configuration> configuration = nullptr,
        std::unique_ptr<SensorMonitoring> sensorMonitoring = nullptr) :
        id{id},
        configuration{std::move(configuration)}, sensorMonitoring{std::move(
                                                     sensorMonitoring)}
    {
    }

    /**
     * Clears all error history.
     *
     * All data on previously logged errors will be deleted.  If errors occur
     * again in the future they will be logged again.
     *
     * This method is normally called when the system is being powered on.
     */
    void clearErrorHistory();

    /**
     * Configure this rail.
     *
     * Applies the configuration changes that are defined for this rail, if any.
     *
     * This method should be called during the boot before regulators are
     * enabled.
     *
     * @param services system services like error logging and the journal
     * @param system system that contains the chassis
     * @param chassis chassis that contains the device
     * @param device device that contains this rail
     */
    void configure(Services& services, System& system, Chassis& chassis,
                   Device& device);

    /**
     * Returns the configuration changes to apply to this rail, if any.
     *
     * @return Pointer to Configuration object.  Will equal nullptr if no
     *         configuration changes are defined for this rail.
     */
    const std::unique_ptr<Configuration>& getConfiguration() const
    {
        return configuration;
    }

    /**
     * Returns the unique ID of this rail.
     *
     * @return rail ID
     */
    const std::string& getID() const
    {
        return id;
    }

    /**
     * Monitor the sensors for this rail.
     *
     * Sensor monitoring is optional.  If sensor monitoring is defined for this
     * rail, the sensor values are read.
     *
     * This method should be called once per second.
     *
     * @param services system services like error logging and the journal
     * @param system system that contains the chassis
     * @param chassis chassis that contains the device
     * @param device device that contains this rail
     */
    void monitorSensors(Services& services, System& system, Chassis& chassis,
                        Device& device);

    /**
     * Returns the sensor monitoring for this rail, if any.
     *
     * @return Pointer to SensorMonitoring object.  Will equal nullptr if no
     *         sensor monitoring is defined for this rail.
     */
    const std::unique_ptr<SensorMonitoring>& getSensorMonitoring() const
    {
        return sensorMonitoring;
    }

  private:
    /**
     * Unique ID of this rail.
     */
    const std::string id{};

    /**
     * Configuration changes to apply to this rail, if any.  Set to nullptr if
     * no configuration changes are defined for this rail.
     */
    std::unique_ptr<Configuration> configuration{};

    /**
     * Sensor monitoring for this rail, if any.  Set to nullptr if no sensor
     * monitoring is defined for this rail.
     */
    std::unique_ptr<SensorMonitoring> sensorMonitoring{};
};

} // namespace phosphor::power::regulators