// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "garnet/bin/scpi/app.h"
#include <ddk/protocol/scpi.h>
#include <fuchsia/sysinfo/c/fidl.h>
#include <lib/fdio/util.h>
#include <lib/fdio/watcher.h>
#include <stdio.h>
#include <zircon/device/thermal.h>
#include <zircon/status.h>
#include <zircon/syscalls/object.h>
#include "lib/component/cpp/startup_context.h"

namespace scpi {

static const char kThermalDir[] = "/dev/class/thermal";

App::App() : App(component::StartupContext::CreateFromStartupInfo()) {}

App::App(std::unique_ptr<component::StartupContext> context)
    : context_(std::move(context)) {}

App::~App() {}

zx::handle App::GetRootResource() {
  const int fd = open("/dev/misc/sysinfo", O_RDWR);
  if (fd == 0)
    return {};

  zx::channel channel;
  zx_status_t status =
      fdio_get_service_handle(fd, channel.reset_and_get_address());
  if (status != ZX_OK) {
    return {};
  }

  zx_handle_t root_resource;
  zx_status_t fidl_status = fuchsia_sysinfo_DeviceGetRootResource(
      channel.get(), &status, &root_resource);

  if (fidl_status != ZX_OK || status != ZX_OK)
    return {};

  return zx::handle(root_resource);
}

size_t App::ReadCpuCount(const zx::handle& root_resource) {
  size_t actual, available;
  zx_status_t err = root_resource.get_info(ZX_INFO_CPU_STATS, nullptr, 0,
                                           &actual, &available);
  if (err != ZX_OK) {
    return 0;
  }
  return available;
}

bool App::ReadCpuStats() {
  size_t actual, available;
  zx_status_t err = root_resource_handle_.get_info(
      ZX_INFO_CPU_STATS, &cpu_stats_[0], num_cores_ * sizeof(zx_info_cpu_stats),
      &actual, &available);
  return (err == ZX_OK);
}

bool App::ReadMemStats() {
  zx_status_t err =
      root_resource_handle_.get_info(ZX_INFO_KMEM_STATS, &mem_stats_,
                                     sizeof(zx_info_kmem_stats_t), NULL, NULL);
  return (err == ZX_OK);
}

zx_status_t App::Start() {
  fxl::UniqueFD dirfd(open(kThermalDir, O_DIRECTORY | O_RDONLY));
  if (!dirfd.is_valid()) {
    return ZX_ERR_NOT_DIR;
  }

  auto DeviceAdded = [](int dirfd, int event, const char* name, void* cookie) {
    if (event != WATCH_EVENT_ADD_FILE) {
      return ZX_OK;
    }
    if (!strcmp("000", name)) {
      return ZX_ERR_STOP;
    } else {
      return ZX_OK;
    }
  };

  zx_status_t status =
      fdio_watch_directory(dirfd.get(), DeviceAdded, ZX_TIME_INFINITE, NULL);
  if (status != ZX_ERR_STOP) {
    return ZX_ERR_NOT_FOUND;
  }

  fd_.reset(open("/dev/class/thermal/000", O_RDWR));
  if (!fd_.is_valid()) {
    FXL_LOG(ERROR) << "Failed to open sensor " << errno;
    return ZX_ERR_UNAVAILABLE;
  }

  root_resource_handle_ = GetRootResource();
  num_cores_ = ReadCpuCount(root_resource_handle_);
  cpu_stats_.reserve(num_cores_);
  last_cpu_stats_.reserve(num_cores_);
  context_->outgoing().AddPublicService(bindings_.GetHandler(this));
  return ZX_OK;
}

void App::GetDvfsInfo(const uint32_t power_domain,
                      GetDvfsInfoCallback callback) {
  scpi_opp_t opps;
  auto result = fidl::VectorPtr<fuchsia::scpi::DvfsOpp>::New(0);
  size_t rc = ioctl_thermal_get_dvfs_info(fd_.get(), &power_domain, &opps);
  if (rc != sizeof(opps)) {
    fprintf(stderr, "ERROR: Failed to get thermal info: %zd\n", rc);
    callback(fuchsia::scpi::Status::ERR_DVFS_INFO, std::move(result));
    return;
  }
  for (uint32_t i = 0; i < opps.count; i++) {
    fuchsia::scpi::DvfsOpp opp;
    opp.freq_hz = opps.opp[i].freq_hz;
    opp.volt_mv = opps.opp[i].volt_mv;
    result.push_back(std::move(opp));
  }
  callback(fuchsia::scpi::Status::OK, std::move(result));
}

void App::GetSystemStatus(GetSystemStatusCallback callback) {
  fuchsia::scpi::SystemStatus info;
  uint32_t power_domain = BIG_CLUSTER_POWER_DOMAIN;
  size_t rc = ioctl_thermal_get_dvfs_opp(fd_.get(), &power_domain,
                                         &info.big_cluster_op_index);
  if (rc != sizeof(uint32_t)) {
    fprintf(stderr, "ERROR: Failed to get dvfs opp idx: %zd\n", rc);
    callback(fuchsia::scpi::Status::ERR_DVFS_OPP_IDX, std::move(info));
    return;
  }

  power_domain = LITTLE_CLUSTER_POWER_DOMAIN;
  rc = ioctl_thermal_get_dvfs_opp(fd_.get(), &power_domain,
                                  &info.small_cluster_op_index);
  if (rc != sizeof(uint32_t)) {
    fprintf(stderr, "ERROR: Failed to get dvfs opp idx: %zd\n", rc);
    callback(fuchsia::scpi::Status::ERR_DVFS_OPP_IDX, std::move(info));
    return;
  }

  rc = ioctl_thermal_get_temperature(fd_.get(), &info.temperature);
  if (rc != sizeof(uint32_t)) {
    fprintf(stderr, "ERROR: Failed to get current temperature: %zd\n", rc);
    callback(fuchsia::scpi::Status::ERR_TEMPERATURE, std::move(info));
    return;
  }

  rc = ioctl_thermal_get_fan_level(fd_.get(), &info.fan_level);
  if (rc != sizeof(uint32_t)) {
    fprintf(stderr, "ERROR: Failed to get fan level: %zd\n", rc);
    callback(fuchsia::scpi::Status::ERR_FAN_LEVEL, std::move(info));
    return;
  }

  zx_time_t delay = ZX_SEC(1);

  if (!ReadCpuStats()) {
    fprintf(stderr, "ERROR: Failed to get cpu_stats_ \n");
    callback(fuchsia::scpi::Status::ERR_CPU_STATS, std::move(info));
    return;
  }

  last_cpu_stats_.swap(cpu_stats_);
  sleep(1);

  if (!ReadCpuStats()) {
    fprintf(stderr, "ERROR: Failed to get cpu_stats_ \n");
    callback(fuchsia::scpi::Status::ERR_CPU_STATS, std::move(info));
    return;
  }

  zx_time_t idle_time, busy_time;
  double busypercent_sum = 0;
  for (size_t i = 0; i < num_cores_; i++) {
    idle_time = cpu_stats_[i].idle_time - last_cpu_stats_[i].idle_time;
    busy_time = delay - (idle_time > delay ? delay : idle_time);
    double busypercent = (busy_time * 100) / (double)delay;
    busypercent_sum += busypercent;
  }

  info.cpu_utilization = busypercent_sum / num_cores_;

  if (!ReadMemStats()) {
    fprintf(stderr, "ERROR: Failed to get mem_stats_ \n");
    callback(fuchsia::scpi::Status::ERR_MEM_STATS, std::move(info));
    return;
  }

  info.memory_utilization = ((mem_stats_.total_bytes - mem_stats_.free_bytes) *
                             100 / mem_stats_.total_bytes);

  callback(fuchsia::scpi::Status::OK, std::move(info));
}

}  // namespace scpi
