// Copyright (c) 2012 The Chromium OS 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 "power_manager/powerd/policy/suspend_delay_controller.h"

#include <algorithm>
#include <utility>
#include <vector>

#include <base/bind.h>
#include <base/logging.h>
#include <base/strings/string_number_conversions.h>
#include <chromeos/dbus/service_constants.h>

#include "power_manager/common/util.h"
#include "power_manager/powerd/policy/suspend_delay_observer.h"
#include "power_manager/proto_bindings/suspend.pb.h"

namespace power_manager {
namespace policy {

// static.
constexpr base::TimeDelta
    SuspendDelayController::kDefaultMaxSuspendDelayTimeout;

SuspendDelayController::SuspendDelayController(
    int initial_delay_id,
    const std::string& description,
    base::TimeDelta max_delay_timeout)
    : description_(description),
      next_delay_id_(initial_delay_id),
      current_suspend_id_(0),
      max_delay_timeout_(max_delay_timeout) {
  DCHECK_LT(dark_resume_min_delay_, max_delay_timeout_);
}

SuspendDelayController::~SuspendDelayController() {}

bool SuspendDelayController::ReadyForSuspend() const {
  return delay_ids_being_waited_on_.empty() &&
         !min_delay_expiration_timer_.IsRunning();
}

void SuspendDelayController::AddObserver(SuspendDelayObserver* observer) {
  DCHECK(observer);
  observers_.AddObserver(observer);
}

void SuspendDelayController::RemoveObserver(SuspendDelayObserver* observer) {
  DCHECK(observer);
  observers_.RemoveObserver(observer);
}

void SuspendDelayController::RegisterSuspendDelay(
    const RegisterSuspendDelayRequest& request,
    const std::string& dbus_client,
    RegisterSuspendDelayReply* reply) {
  DCHECK(reply);

  int delay_id = next_delay_id_++;

  DelayInfo info;
  // Timeout is sent as |ToInternalValue| from clients.
  base::TimeDelta timeout =
      base::TimeDelta::FromInternalValue(request.timeout());
  if ((timeout < base::TimeDelta()) || (timeout > max_delay_timeout_)) {
    info.timeout = max_delay_timeout_;
  } else {
    info.timeout = timeout;
  }
  info.dbus_client = dbus_client;
  info.description = request.description();

  LOG(INFO) << "Registering " << GetLogDescription() << " delay " << delay_id
            << " (" << info.description << ")"
            << " of " << info.timeout.InMilliseconds() << " ms on behalf of "
            << dbus_client;
  registered_delays_.insert(std::make_pair(delay_id, info));

  reply->Clear();
  reply->set_min_delay_timeout_ms(std::min(
      info.timeout.InMilliseconds(), max_delay_timeout_.InMilliseconds()));
  reply->set_delay_id(delay_id);
}

void SuspendDelayController::UnregisterSuspendDelay(
    const UnregisterSuspendDelayRequest& request,
    const std::string& dbus_client) {
  LOG(INFO) << "Unregistering " << GetLogDescription() << " delay "
            << request.delay_id() << " ("
            << GetDelayDescription(request.delay_id()) << ")"
            << " on behalf of " << dbus_client;
  UnregisterDelayInternal(request.delay_id());
}

void SuspendDelayController::HandleSuspendReadiness(
    const SuspendReadinessInfo& info, const std::string& dbus_client) {
  int delay_id = info.delay_id();
  int suspend_id = info.suspend_id();
  LOG(INFO) << "Got notification that delay " << delay_id << " ("
            << GetDelayDescription(delay_id) << ") is ready for "
            << GetLogDescription() << " request " << suspend_id << " from "
            << dbus_client;

  if (suspend_id != current_suspend_id_) {
    // This can legitimately happen if we cancel a suspend request, quickly
    // start a new request, and then receive a notification about the previous
    // request from a client.
    VLOG(1) << "Ignoring readiness notification for wrong "
            << GetLogDescription() << " request (got " << suspend_id
            << ", currently on " << current_suspend_id_ << ")";
    return;
  }

  if (!delay_ids_being_waited_on_.count(delay_id)) {
    LOG(WARNING) << "Ignoring readiness notification for "
                 << GetLogDescription() << " delay " << delay_id
                 << ", which we weren't waiting for";
    return;
  }
  RemoveDelayFromWaitList(delay_id);
}

void SuspendDelayController::HandleDBusClientDisconnected(
    const std::string& client) {
  std::vector<int> delay_ids_to_remove;
  for (DelayInfoMap::const_iterator it = registered_delays_.begin();
       it != registered_delays_.end(); ++it) {
    if (it->second.dbus_client == client)
      delay_ids_to_remove.push_back(it->first);
  }

  for (std::vector<int>::const_iterator it = delay_ids_to_remove.begin();
       it != delay_ids_to_remove.end(); ++it) {
    LOG(INFO) << "Unregistering " << GetLogDescription() << " delay " << *it
              << " (" << GetDelayDescription(*it) << ") due to D-Bus client "
              << client << " going away";
    UnregisterDelayInternal(*it);
  }
}

void SuspendDelayController::PrepareForSuspend(int suspend_id,
                                               bool in_dark_resume) {
  current_suspend_id_ = suspend_id;

  size_t old_count = delay_ids_being_waited_on_.size();
  delay_ids_being_waited_on_.clear();
  for (DelayInfoMap::const_iterator it = registered_delays_.begin();
       it != registered_delays_.end(); ++it)
    delay_ids_being_waited_on_.insert(it->first);

  LOG(INFO) << "Announcing " << GetLogDescription() << " request "
            << current_suspend_id_ << " with "
            << delay_ids_being_waited_on_.size() << " pending delay(s) and "
            << old_count << " outstanding delay(s) from previous request";

  const bool waiting = !delay_ids_being_waited_on_.empty();

  if (in_dark_resume) {
    min_delay_expiration_timer_.Start(
        FROM_HERE, dark_resume_min_delay_, this,
        &SuspendDelayController::OnMinDelayExpiration);
  } else if (!waiting) {
    PostNotifyObserversTask(current_suspend_id_);
  }

  if (waiting) {
    base::TimeDelta max_timeout;
    for (DelayInfoMap::const_iterator it = registered_delays_.begin();
         it != registered_delays_.end(); ++it) {
      max_timeout = std::max(max_timeout, it->second.timeout);
    }
    max_timeout = std::min(max_timeout, max_delay_timeout_);
    max_delay_expiration_timer_.Start(
        FROM_HERE, max_timeout, this,
        &SuspendDelayController::OnMaxDelayExpiration);
  }
}

void SuspendDelayController::FinishSuspend(int suspend_id) {
  if (suspend_id != current_suspend_id_)
    return;

  max_delay_expiration_timer_.Stop();
  min_delay_expiration_timer_.Stop();
  delay_ids_being_waited_on_.clear();
}

std::string SuspendDelayController::GetLogDescription() const {
  return (!description_.empty() ? description_ + " " : std::string()) +
         "suspend";
}

std::string SuspendDelayController::GetDelayDescription(int delay_id) const {
  DelayInfoMap::const_iterator it = registered_delays_.find(delay_id);
  return it != registered_delays_.end() ? it->second.description : "unknown";
}

void SuspendDelayController::UnregisterDelayInternal(int delay_id) {
  if (!registered_delays_.count(delay_id)) {
    LOG(WARNING) << "Ignoring request to remove unknown " << GetLogDescription()
                 << " delay " << delay_id;
    return;
  }
  RemoveDelayFromWaitList(delay_id);
  registered_delays_.erase(delay_id);
}

void SuspendDelayController::RemoveDelayFromWaitList(int delay_id) {
  if (!delay_ids_being_waited_on_.count(delay_id))
    return;

  delay_ids_being_waited_on_.erase(delay_id);
  if (delay_ids_being_waited_on_.empty() &&
      !min_delay_expiration_timer_.IsRunning()) {
    max_delay_expiration_timer_.Stop();
    PostNotifyObserversTask(current_suspend_id_);
  }
}

void SuspendDelayController::OnMaxDelayExpiration() {
  std::string tardy_delays;
  for (std::set<int>::const_iterator it = delay_ids_being_waited_on_.begin();
       it != delay_ids_being_waited_on_.end(); ++it) {
    const DelayInfo& delay = registered_delays_[*it];
    if (!tardy_delays.empty())
      tardy_delays += ", ";
    tardy_delays += base::NumberToString(*it) + " (" + delay.dbus_client +
                    ": " + delay.description + ")";
  }
  LOG(WARNING) << "Timed out while waiting for " << GetLogDescription()
               << " request " << current_suspend_id_
               << " readiness confirmation for "
               << delay_ids_being_waited_on_.size()
               << " delay(s): " << tardy_delays;

  delay_ids_being_waited_on_.clear();
  PostNotifyObserversTask(current_suspend_id_);
}

void SuspendDelayController::OnMinDelayExpiration() {
  if (delay_ids_being_waited_on_.empty()) {
    max_delay_expiration_timer_.Stop();
    PostNotifyObserversTask(current_suspend_id_);
  }
}

void SuspendDelayController::PostNotifyObserversTask(int suspend_id) {
  notify_observers_timer_.Start(
      FROM_HERE, base::TimeDelta(),
      base::Bind(&SuspendDelayController::NotifyObservers,
                 base::Unretained(this), suspend_id));
}

void SuspendDelayController::NotifyObservers(int suspend_id) {
  LOG(INFO) << "Notifying observers that " << GetLogDescription()
            << " is ready";
  for (SuspendDelayObserver& observer : observers_)
    observer.OnReadyForSuspend(this, suspend_id);
}

}  // namespace policy
}  // namespace power_manager
