// Copyright 2019 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 "suspend-task.h"

#include "coordinator.h"

namespace devmgr {

SuspendTask::SuspendTask(fbl::RefPtr<Device> device, uint32_t flags, Completion completion)
    : Task(device->coordinator->dispatcher(), std::move(completion)),
      device_(std::move(device)),
      flags_(flags) {}

SuspendTask::~SuspendTask() = default;

fbl::RefPtr<SuspendTask> SuspendTask::Create(fbl::RefPtr<Device> device, uint32_t flags,
                                             Completion completion) {
  return fbl::MakeRefCounted<SuspendTask>(std::move(device), flags, std::move(completion));
}

void SuspendTask::Run() {
  bool found_more_dependencies = false;
  for (auto& child : device_->children()) {
    // Use a switch statement here so that this gets reconsidered if we add
    // more states.
    switch (child.state()) {
      // If the device is dead, any existing suspend task would have been forcibly completed.
      case Device::State::kDead:
      case Device::State::kSuspended:
        continue;
      case Device::State::kUnbinding:
      case Device::State::kSuspending:
      case Device::State::kActive:
      case Device::State::kResuming:
      case Device::State::kResumed:
        break;
    }

    AddDependency(child.RequestSuspendTask(flags_));
    found_more_dependencies = true;
  }
  if (found_more_dependencies) {
    return;
  }

  // Handle the device proxy, if it exists, after children since they might
  // depend on it.
  if (device_->proxy() != nullptr) {
    switch (device_->proxy()->state()) {
      case Device::State::kDead:
      case Device::State::kSuspended:
      case Device::State::kResuming:
      case Device::State::kResumed:
        break;
      case Device::State::kUnbinding:
      case Device::State::kSuspending:
      case Device::State::kActive: {
        AddDependency(device_->proxy()->RequestSuspendTask(flags_));
        return;
      }
    }
  }

  // The device is about to be unbound, wait for it to complete.
  if (device_->state() == Device::State::kUnbinding) {
    // The remove task depends on the unbind task, so wait for that to complete.
    auto remove_task = device_->GetActiveRemove();
    ZX_ASSERT(remove_task != nullptr);
    AddDependency(remove_task);
    return;
  }

  // The device is about to be resumed, wait for it to complete.
  if (device_->state() == Device::State::kResuming) {
    auto resume_task = device_->GetActiveResume();
    AddDependency(resume_task);
    return;
  }

  // Check if this device is not in a devhost.  This happens for the
  // top-level devices like /sys provided by devcoordinator,
  // or the device is already dead.
  if (device_->host() == nullptr) {
    device_->set_state(Device::State::kSuspended);
    return Complete(ZX_OK);
  }

  auto completion = [this](zx_status_t status) {
    device_->set_state(Device::State::kSuspended);
    Complete(status);
  };
  zx_status_t status = device_->SendSuspend(flags_, std::move(completion));
  if (status != ZX_OK) {
    Complete(status);
  }
}

}  // namespace devmgr
