// Copyright (c) 2014 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 "update_engine/update_manager/real_shill_provider.h"

#include <string>

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

#include "update_engine/glib_utils.h"

using std::string;

namespace {

// Looks up a |key| in a GLib |hash_table| and returns the unboxed string from
// the corresponding GValue, if found.
const char* GetStrProperty(GHashTable* hash_table, const char* key) {
  auto gval = reinterpret_cast<GValue*>(g_hash_table_lookup(hash_table, key));
  return (gval ? g_value_get_string(gval) : nullptr);
}

};  // namespace


namespace chromeos_update_manager {

RealShillProvider::~RealShillProvider() {
  // Detach signal handler, free manager proxy.
  dbus_->ProxyDisconnectSignal(manager_proxy_, shill::kMonitorPropertyChanged,
                               G_CALLBACK(HandlePropertyChangedStatic),
                               this);
  dbus_->ProxyUnref(manager_proxy_);
}

ConnectionType RealShillProvider::ParseConnectionType(const char* type_str) {
  if (!strcmp(type_str, shill::kTypeEthernet))
    return ConnectionType::kEthernet;
  if (!strcmp(type_str, shill::kTypeWifi))
    return ConnectionType::kWifi;
  if (!strcmp(type_str, shill::kTypeWimax))
    return ConnectionType::kWimax;
  if (!strcmp(type_str, shill::kTypeBluetooth))
    return ConnectionType::kBluetooth;
  if (!strcmp(type_str, shill::kTypeCellular))
    return ConnectionType::kCellular;

  return ConnectionType::kUnknown;
}

ConnectionTethering RealShillProvider::ParseConnectionTethering(
    const char* tethering_str) {
  if (!strcmp(tethering_str, shill::kTetheringNotDetectedState))
    return ConnectionTethering::kNotDetected;
  if (!strcmp(tethering_str, shill::kTetheringSuspectedState))
    return ConnectionTethering::kSuspected;
  if (!strcmp(tethering_str, shill::kTetheringConfirmedState))
    return ConnectionTethering::kConfirmed;

  return ConnectionTethering::kUnknown;
}

bool RealShillProvider::Init() {
  // Obtain a DBus connection.
  GError* error = nullptr;
  connection_ = dbus_->BusGet(DBUS_BUS_SYSTEM, &error);
  if (!connection_) {
    LOG(ERROR) << "Failed to initialize DBus connection: "
               << chromeos_update_engine::utils::GetAndFreeGError(&error);
    return false;
  }

  // Allocate a shill manager proxy.
  manager_proxy_ = GetProxy(shill::kFlimflamServicePath,
                            shill::kFlimflamManagerInterface);

  // Subscribe to the manager's PropertyChanged signal.
  dbus_->ProxyAddSignal_2(manager_proxy_, shill::kMonitorPropertyChanged,
                          G_TYPE_STRING, G_TYPE_VALUE);
  dbus_->ProxyConnectSignal(manager_proxy_, shill::kMonitorPropertyChanged,
                            G_CALLBACK(HandlePropertyChangedStatic),
                            this, nullptr);

  // Attempt to read initial connection status. Even if this fails because shill
  // is not responding (e.g. it is down) we'll be notified via "PropertyChanged"
  // signal as soon as it comes up, so this is not a critical step.
  GHashTable* hash_table = nullptr;
  if (GetProperties(manager_proxy_, &hash_table)) {
    GValue* value = reinterpret_cast<GValue*>(
        g_hash_table_lookup(hash_table, shill::kDefaultServiceProperty));
    ProcessDefaultService(value);
    g_hash_table_unref(hash_table);
  }

  return true;
}

DBusGProxy* RealShillProvider::GetProxy(const char* path,
                                        const char* interface) {
  return dbus_->ProxyNewForName(connection_, shill::kFlimflamServiceName,
                                path, interface);
}

bool RealShillProvider::GetProperties(DBusGProxy* proxy,
                                      GHashTable** result_p) {
  GError* error = nullptr;
  if (!dbus_->ProxyCall_0_1(proxy, shill::kGetPropertiesFunction, &error,
                            result_p)) {
    LOG(ERROR) << "Calling shill via DBus proxy failed: "
               << chromeos_update_engine::utils::GetAndFreeGError(&error);
    return false;
  }
  return true;
}

bool RealShillProvider::ProcessDefaultService(GValue* value) {
  // Decode the string from the boxed value.
  const char* default_service_path_str = nullptr;
  if (!(value && (default_service_path_str = g_value_get_string(value))))
    return false;

  // Anything changed?
  if (default_service_path_ == default_service_path_str)
    return true;

  // Update the connection status.
  default_service_path_ = default_service_path_str;
  bool is_connected = (default_service_path_ != "/");
  var_is_connected_.SetValue(is_connected);
  var_conn_last_changed_.SetValue(clock_->GetWallclockTime());

  // Update the connection attributes.
  if (is_connected) {
    DBusGProxy* service_proxy = GetProxy(default_service_path_.c_str(),
                                         shill::kFlimflamServiceInterface);
    GHashTable* hash_table = nullptr;
    if (GetProperties(service_proxy, &hash_table)) {
      // Get the connection type.
      const char* type_str = GetStrProperty(hash_table, shill::kTypeProperty);
      if (type_str && !strcmp(type_str, shill::kTypeVPN)) {
        type_str = GetStrProperty(hash_table,
                                  shill::kPhysicalTechnologyProperty);
      }
      if (type_str) {
        var_conn_type_.SetValue(ParseConnectionType(type_str));
      } else {
        var_conn_type_.UnsetValue();
        LOG(ERROR) << "Could not find connection type ("
                   << default_service_path_ << ")";
      }

      // Get the connection tethering mode.
      const char* tethering_str = GetStrProperty(hash_table,
                                                 shill::kTetheringProperty);
      if (tethering_str) {
        var_conn_tethering_.SetValue(ParseConnectionTethering(tethering_str));
      } else {
        var_conn_tethering_.UnsetValue();
        LOG(ERROR) << "Could not find connection tethering mode ("
                   << default_service_path_ << ")";
      }

      g_hash_table_unref(hash_table);
    }
    dbus_->ProxyUnref(service_proxy);
  } else {
    var_conn_type_.UnsetValue();
    var_conn_tethering_.UnsetValue();
  }

  return true;
}

void RealShillProvider::HandlePropertyChanged(DBusGProxy* proxy,
                                              const char* name, GValue* value) {
  if (!strcmp(name, shill::kDefaultServiceProperty))
    ProcessDefaultService(value);
}

void RealShillProvider::HandlePropertyChangedStatic(DBusGProxy* proxy,
                                                    const char* name,
                                                    GValue* value,
                                                    void* data) {
  auto obj = reinterpret_cast<RealShillProvider*>(data);
  obj->HandlePropertyChanged(proxy, name, value);
}

}  // namespace chromeos_update_manager
