//
// Copyright (C) 2015 The Android Open Source Project
//
// 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.
//

#include "update_engine/client_library/client_dbus_nestlabs.h"

#include <base/message_loop/message_loop.h>

#include <dbus/bus.h>
#include <update_engine/dbus-constants-nestlabs.h>

#include "update_engine/update_status_utils.h"

using chromeos_update_engine::StringToUpdateStatus;
using dbus::Bus;
using com::nestlabs::UpdateEngineInterfaceProxy;
using std::string;

namespace update_engine {
namespace internal {

bool DBusUpdateEngineNestlabsClient::Init() {
  Bus::Options options;
  options.bus_type = Bus::SYSTEM;
  scoped_refptr<Bus> bus{new Bus{options}};

  if (!bus->Connect())
    return false;

  proxy_.reset(new UpdateEngineInterfaceProxy{bus, update_engine::kUpdateEngineServiceName});
  return true;
}

bool DBusUpdateEngineNestlabsClient::AttemptUpdate(const string& in_app_version,
                                           const string& in_url,
                                           bool at_user_request) {
  return proxy_->AttemptUpdate(
      in_app_version,
      in_url,
      nullptr);
}

bool DBusUpdateEngineNestlabsClient::GetStatus(int64_t* out_last_checked_time,
                                       double* out_progress,
                                       UpdateStatus* out_update_status,
                                       string* out_new_version,
                                       int64_t* out_new_size) const {
  string status_as_string;
  const bool success = proxy_->GetStatus(out_last_checked_time,
                                         out_progress,
                                         &status_as_string,
                                         out_new_version,
                                         out_new_size,
                                         nullptr);
  if (!success) {
    return false;
  }

  return StringToUpdateStatus(status_as_string, out_update_status);
}

bool DBusUpdateEngineNestlabsClient::Rollback(bool powerwash) {
  return proxy_->AttemptRollback(powerwash, nullptr);
}

bool DBusUpdateEngineNestlabsClient::GetRollbackPartition(
    string* rollback_partition) const {
  return proxy_->GetRollbackPartition(rollback_partition, nullptr);
}

bool DBusUpdateEngineNestlabsClient::GetPrevVersion(string* prev_version) const {
  return proxy_->GetPrevVersion(prev_version, nullptr);
}

void DBusUpdateEngineNestlabsClient::RebootIfNeeded() {
  bool ret = proxy_->RebootIfNeeded(nullptr);
  if (!ret) {
    // Reboot error code doesn't necessarily mean that a reboot
    // failed. For example, D-Bus may be shutdown before we receive the
    // result.
    LOG(INFO) << "RebootIfNeeded() failure ignored.";
  }
}

bool DBusUpdateEngineNestlabsClient::ResetStatus() {
  return proxy_->ResetStatus(nullptr);
}

void DBusUpdateEngineNestlabsClient::DBusStatusHandlersRegistered(
    const string& interface,
    const string& signal_name,
    bool success) const {
  if (!success) {
    for (auto handler : handlers_) {
      handler->IPCError("Could not connect to" + signal_name +
                        " on " + interface);
    }
  } else {
    StatusUpdateHandlersRegistered(nullptr);
  }
}

void DBusUpdateEngineNestlabsClient::StatusUpdateHandlersRegistered(
    StatusUpdateHandler* handler) const {
  int64_t last_checked_time;
  double progress;
  UpdateStatus update_status;
  string new_version;
  int64_t new_size;

  if (!GetStatus(&last_checked_time,
                 &progress,
                 &update_status,
                 &new_version,
                 &new_size)) {
    handler->IPCError("Could not query current status");
    return;
  }

  std::vector<update_engine::StatusUpdateHandler*> just_handler = {handler};
  for (auto h : handler ? just_handler : handlers_) {
    h->HandleStatusUpdate(
        last_checked_time, progress, update_status, new_version, new_size);
  }
}

void DBusUpdateEngineNestlabsClient::RunStatusUpdateHandlers(
    int64_t last_checked_time,
    double progress,
    const string& current_operation,
    const string& new_version,
    int64_t new_size) {
  UpdateStatus status;
  StringToUpdateStatus(current_operation, &status);

  for (auto handler : handlers_) {
    handler->HandleStatusUpdate(
        last_checked_time, progress, status, new_version, new_size);
  }
}

bool DBusUpdateEngineNestlabsClient::UnregisterStatusUpdateHandler(
    StatusUpdateHandler* handler) {
  auto it = std::find(handlers_.begin(), handlers_.end(), handler);
  if (it != handlers_.end()) {
    handlers_.erase(it);
    return true;
  }

  return false;
}

bool DBusUpdateEngineNestlabsClient::RegisterStatusUpdateHandler(
    StatusUpdateHandler* handler) {
  if (!base::MessageLoopForIO::current()) {
    LOG(FATAL) << "Cannot get UpdateEngineClient outside of message loop.";
    return false;
  }

  handlers_.push_back(handler);

  if (dbus_handler_registered_) {
    StatusUpdateHandlersRegistered(handler);
    return true;
  }

  proxy_->RegisterStatusUpdateSignalHandler(
      base::Bind(&DBusUpdateEngineNestlabsClient::RunStatusUpdateHandlers,
                 base::Unretained(this)),
      base::Bind(&DBusUpdateEngineNestlabsClient::DBusStatusHandlersRegistered,
                 base::Unretained(this)));

  dbus_handler_registered_ = true;

  return true;
}

bool DBusUpdateEngineNestlabsClient::GetLastAttemptError(
    int32_t* last_attempt_error) const {
  return proxy_->GetLastAttemptError(last_attempt_error, nullptr);
}

bool DBusUpdateEngineNestlabsClient::MarkBootSuccessful() const {
  return proxy_->MarkBootSuccessful(nullptr);
}

}  // namespace internal
}  // namespace update_engine
