// Copyright 2021 Google LLC
//
// 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 "main.hpp"
// This is the form a sensor assumes on DBus.
// Aggregates their view from all other daemons.
#include <bitset>
#include <map>
#include <optional>
#include <set>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

std::pair<std::string, std::string> ExtractFileName(std::string x);
// Where is this sensor seen?
constexpr int VISIBILITY_OBJECT_MAPPER = 0;
constexpr int VISIBILITY_HWMON = 1;
constexpr int VISIBILITY_IPMITOOL_SDR = 2;
class DBusConnection
{
  public:
    std::string service;    // example: "systemd-resolved"
    std::string connection; // example: ":1.1"
    std::string cmd;        // the comm line
    std::string unit;       // example: "systemd-resolved.service"
    int pid;
    // For actual DBus capture: service name, connection name, command line,
    //                          systmed unit and PID are all known
    DBusConnection(const std::string& _s, const std::string& _c,
                   const std::string& _cmd, const std::string& _u, int _pid)
    {
        service = _s;
        connection = _c;
        cmd = _cmd;
        unit = _u;
        pid = _pid;
    }

    // During PCap replay: only service name, connection name, and PID are known
    //                     cmd and unit are not known since they are not
    //                     stored in the PCap file
    DBusConnection(const std::string& _s, const std::string& _c, int _pid)
    {
        service = _s;
        connection = _c;
        pid = _pid;
    }
};

class DBusConnectionSnapshot
{
  public:
    std::vector<DBusConnection*> connections_;
    std::unordered_map<std::string, DBusConnection*> unique_name_to_cxn;
    DBusConnection* FindDBusConnectionByService(const std::string& service)
    {
        for (DBusConnection* cxn : connections_)
        {
            if (cxn->service == service)
                return cxn;
        }
        return nullptr;
    }

    void SetConnectionPID(const std::string& connection, int pid)
    {
        DBusConnection* cxn = FindDBusConnectionByService(connection);
        if (cxn != nullptr)
        {
            cxn->pid = pid;
            unique_name_to_cxn[connection] = cxn; // Just to make sure
        }
    }

    void SetConnectionUniqueName(const std::string& service,
                                 const std::string& unique_name)
    {
        DBusConnection* cxn = FindDBusConnectionByService(service);
        if (cxn != nullptr)
        {
            cxn->connection = unique_name;
            unique_name_to_cxn[unique_name] = cxn;
        }
    }

    DBusConnection* FindDBusConnectionByConnection(const std::string& conn)
    {
        for (DBusConnection* cxn : connections_)
        {
            if (cxn->connection == conn)
                return cxn;
        }
        return nullptr;
    }

    // Only when service is known (during playback)
    void AddConnection(const std::string& _s)
    {
        connections_.push_back(new DBusConnection(_s, "", "", "", INVALID));
    }

    // When all 5 pieces of details are known (during actual capture)
    void AddConnection(const std::string& _s, const std::string& _connection,
                       const std::string& _cmd, const std::string& _unit,
                       int _pid)
    {
        DBusConnection* cxn = new DBusConnection(_s, _connection, _cmd, _unit,
                                                 _pid);
        connections_.push_back(cxn);
        unique_name_to_cxn[_connection] = cxn;
    }

    int GetConnectionPIDFromNameOrUniqueName(const std::string& key)
    {
        if (unique_name_to_cxn.find(key) == unique_name_to_cxn.end())
        {
            return INVALID;
        }
        else
        {
            return unique_name_to_cxn[key]->pid;
        }
    }

    std::string GetConnectionCMDFromNameOrUniqueName(const std::string& key)
    {
        if (unique_name_to_cxn.find(key) == unique_name_to_cxn.end())
        {
            return "(unknown)";
        }
        else
        {
            return unique_name_to_cxn[key]->cmd;
        }
    }

    std::string GetUniqueNameIfExists(const std::string service)
    {
        for (DBusConnection* cxn : connections_)
        {
            if (cxn->service == service)
                return cxn->connection;
        }
        return service;
    }
};

// Each sensor might have different units, for example current and voltage
class Sensor
{
  public:
    DBusConnection* connection_;
    // Example: "/xyz/openbmc_project/sensors/temperature/powerseq_temp"
    std::string object_path_;
    std::string SensorID()
    {
        const size_t idx = object_path_.rfind('/');
        if (idx != std::string::npos)
        {
            return object_path_.substr(idx + 1);
        }
        else
            return ("unknown sensor");
    }

    std::string ServiceName()
    {
        if (connection_ == nullptr)
            return "";
        else
            return connection_->service;
    }

    std::string ConnectionName()
    {
        if (connection_ == nullptr)
            return "";
        else
            return connection_->connection;
    }

    std::string ObjectPath()
    {
        return object_path_;
    }

    // Should contain the following:
    // 1. "org.freedesktop.DBus.Introspectable"
    // 2. "org.freedesktop.DBus.Peer"
    // 3. "org.freedesktop.DBus.Properties"
    // 4. "xyz.openbmc_project.Sensor.Value"
    // 5. "xyz.openbmc_project.State.Decorator.OperationalStatus"
    std::set<std::string> interfaces_;
    std::bitset<4> visibility_flags_;
    std::set<std::string> associations_;
};

class SensorSnapshot
{
  public:
    std::vector<std::string> GetDistinctSensorNames()
    {
        std::unordered_set<std::string> seen;
        std::vector<std::string> ret;
        for (Sensor* s : sensors_)
        {
            std::string sn = s->SensorID();
            if (seen.find(sn) == seen.end())
            {
                ret.push_back(sn);
                seen.insert(sn);
            }
        }
        return ret;
    }

    explicit SensorSnapshot()
    {
        connection_snapshot_ = nullptr;
    }

    explicit SensorSnapshot(DBusConnectionSnapshot* cs)
    {
        connection_snapshot_ = cs;
    }

    ~SensorSnapshot()
    {
        for (Sensor* s : sensors_)
        {
            delete s;
        }
    }

    int SensorCount()
    {
        return int(sensors_.size());
    }

    Sensor* FindOrCreateSensorByServiceAndObject(const std::string& service,
                                                 const std::string& object)
    {
        Sensor* ret = nullptr;
        for (Sensor* s : sensors_)
        {
            if (s->ServiceName() == service && s->object_path_ == object)
            {
                ret = s;
                break;
            }
        }
        if (ret == nullptr)
        {
            DBusConnection* cxn =
                connection_snapshot_->FindDBusConnectionByService(service);
            ret = new Sensor();
            ret->connection_ = cxn;
            ret->object_path_ = object;
            sensors_.push_back(ret);
        }
        return ret;
    }

    // Note: one sensor_id might correspond to multiple sensors.
    // Example: "VDD" can have all 3 of power, current and voltage.
    std::vector<Sensor*> FindSensorsBySensorID(const std::string& sensor_id)
    {
        std::vector<Sensor*> ret;
        for (Sensor* s : sensors_)
        {
            const std::string& p = s->object_path_;
            if (p.find(sensor_id) == p.size() - sensor_id.size())
            {
                ret.push_back(s);
            }
        }
        return ret;
    }

    // This sensor is visible from Object Mapper
    void SetSensorVisibleFromObjectMapper(const std::string& service,
                                          const std::string& object)
    {
        Sensor* s = FindOrCreateSensorByServiceAndObject(service, object);
        s->visibility_flags_.set(VISIBILITY_OBJECT_MAPPER);
    }

    // This sensor is visible from Hwmon
    void SetSensorVisibleFromHwmon(const std::string& service,
                                   const std::string& object)
    {
        Sensor* s = FindOrCreateSensorByServiceAndObject(service, object);
        s->visibility_flags_.set(VISIBILITY_HWMON);
    }

    // This sensor is visible from `ipmitool sdr`
    // The first column is referred to as "sensorid".
    void SetSensorVisibleFromIpmitoolSdr(const std::string& sensor_id)
    {
        std::vector<Sensor*> sensors = FindSensorsBySensorID(sensor_id);
        for (Sensor* s : sensors)
            s->visibility_flags_.set(VISIBILITY_IPMITOOL_SDR);
    }

    void PrintSummary()
    {
        for (Sensor* s : sensors_)
        {
            printf("%50s %50s %9s\n", s->ServiceName().c_str(),
                   s->object_path_.c_str(),
                   s->visibility_flags_.to_string().c_str());
        }
    }

    Sensor* FindSensorByDBusUniqueNameOrServiceName(const std::string& key)
    {
        for (Sensor* s : sensors_)
        {
            if (s->ConnectionName() == key || s->ServiceName() == key)
                return s;
        }
        return nullptr;
    }

    void AddAssociationEndpoints(const std::string& path,
                                 const std::set<std::string>& entries)
    {
        associations_[path] = entries;
    }

    // Input: object path (regardless of what service name)
    // out_edges: what associations does `path` declare?
    // in_edges: what associations have `path` as endpoints?
    void FindAssociationEndpoints(
        const std::string& path,
        std::map<std::string, std::set<std::string>>* out_edges,
        std::map<std::string, std::set<std::string>>* in_edges)
    {
        std::map<std::string, std::set<std::string>> out, in;
        for (const auto& [k, v] : associations_)
        {
            if (k.find(path) == 0)
            {
                out[k.substr(path.size())] = v;
            }
            for (const std::string& entry : v)
            {
                if (entry.find(path) == 0)
                {
                    std::pair<std::string, std::string> p = ExtractFileName(k);
                    in[p.second].insert(k);
                }
            }
        }

        *out_edges = out;
        *in_edges = in;
    }

    void AddAssociationDefinition(const std::string& path,
                                  const std::string& forward,
                                  const std::string& reverse,
                                  const std::string& endpoint)
    {
        std::vector<std::string> d = {path, forward, reverse, endpoint};
        association_definitions_.push_back(d);
    }

  private:
    std::vector<Sensor*> sensors_;
    std::unordered_map<std::string, int> conn2pid_;
    DBusConnectionSnapshot* connection_snapshot_;

    // Associations seen from Inventory objects
    // Key: the path of the object that has the Association interface
    // Value: all the endpoints
    std::unordered_map<std::string, std::set<std::string>> associations_;

    // Association Definitions
    // Ideally, this should match associations_ above
    std::vector<std::vector<std::string>> association_definitions_;
};

bool IsSensorObjectPath(const std::string& s);
bool IsUniqueName(const std::string& x);
std::string Trim(const std::string& s);
