// Copyright 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 "buffet/shill_client.h"

#include <memory>
#include <set>
#include <utility>

#include <base/stl_util.h>
#include <base/threading/thread_task_runner_handle.h>
#include <brillo/any.h>
#include <brillo/errors/error.h>
#include <chromeos/dbus/service_constants.h>
#include <weave/enum_to_string.h>

#include "buffet/socket_stream.h"
#include "buffet/weave_error_conversion.h"

using brillo::Any;
using brillo::VariantDictionary;
using dbus::ObjectPath;
using org::chromium::flimflam::DeviceProxy;
using org::chromium::flimflam::DeviceProxyInterface;
using org::chromium::flimflam::IPConfigProxy;
using org::chromium::flimflam::ServiceProxy;
using org::chromium::flimflam::ServiceProxyInterface;
using std::map;
using std::set;
using std::string;
using std::vector;
using weave::EnumToString;
using weave::provider::Network;

namespace buffet {

namespace {

const char kErrorDomain[] = "buffet";

void IgnoreDetachEvent() {}

bool GetStateForService(ServiceProxyInterface* service, string* state) {
  CHECK(service) << "|service| was nullptr in GetStateForService()";
  VariantDictionary properties;
  if (!service->GetProperties(&properties, nullptr)) {
    LOG(WARNING) << "Failed to read properties from service.";
    return false;
  }
  auto property_it = properties.find(shill::kStateProperty);
  if (property_it == properties.end()) {
    LOG(WARNING) << "No state found in service properties.";
    return false;
  }
  string new_state = property_it->second.TryGet<string>();
  if (new_state.empty()) {
    LOG(WARNING) << "Invalid state value.";
    return false;
  }
  *state = new_state;
  return true;
}

Network::State ShillServiceStateToNetworkState(const string& state) {
  // TODO(wiley) What does "unconfigured" mean in a world with multiple sets
  //             of WiFi credentials?
  // TODO(wiley) Detect disabled devices, update state appropriately.
  if (state.compare(shill::kStateOnline) == 0) {
    return Network::State::kOnline;
  }
  if ((state.compare(shill::kStateReady) == 0) ||
      (state.compare(shill::kStateAssociation) == 0) ||
      (state.compare(shill::kStateConfiguration) == 0) ||
      (state.compare(shill::kStateRedirectFound) == 0) ||
      (state.compare(shill::kStatePortalSuspected) == 0)) {
    return Network::State::kConnecting;
  }
  if (state.compare(shill::kStateFailure) == 0) {
    // TODO(wiley) Get error information off the service object.
    return Network::State::kError;
  }
  if ((state.compare(shill::kStateIdle) == 0) ||
      (state.compare(shill::kStateNoConnectivity) == 0) ||
      (state.compare(shill::kStateDisconnect) == 0)) {
    return Network::State::kOffline;
  }
  LOG(WARNING) << "Unknown state found: '" << state << "'";
  return Network::State::kOffline;
}

}  // namespace

ShillClient::ShillClient(const scoped_refptr<dbus::Bus>& bus,
                         const set<string>& device_whitelist,
                         bool disable_xmpp)
    : bus_{bus},
      manager_proxy_{bus_},
      device_whitelist_{device_whitelist},
      disable_xmpp_{disable_xmpp} {
  manager_proxy_.RegisterPropertyChangedSignalHandler(
      base::Bind(&ShillClient::OnManagerPropertyChange,
                 weak_factory_.GetWeakPtr()),
      base::Bind(&ShillClient::OnManagerPropertyChangeRegistration,
                 weak_factory_.GetWeakPtr()));
  auto owner_changed_cb = base::Bind(&ShillClient::OnShillServiceOwnerChange,
                                     weak_factory_.GetWeakPtr());
  bus_->GetObjectProxy(shill::kFlimflamServiceName, ObjectPath{"/"})
      ->SetNameOwnerChangedCallback(owner_changed_cb);
}

ShillClient::~ShillClient() {}

void ShillClient::Init() {
  VLOG(2) << "ShillClient::Init();";
  CleanupConnectingService();
  devices_.clear();
  connectivity_state_ = Network::State::kOffline;
  VariantDictionary properties;
  if (!manager_proxy_.GetProperties(&properties, nullptr)) {
    LOG(ERROR) << "Unable to get properties from Manager, waiting for "
                  "Manager to come back online.";
    return;
  }
  auto it = properties.find(shill::kDevicesProperty);
  CHECK(it != properties.end()) << "shill should always publish a device list.";
  OnManagerPropertyChange(shill::kDevicesProperty, it->second);
}

void ShillClient::Connect(const string& ssid,
                          const string& passphrase,
                          const weave::DoneCallback& callback) {
  if (connecting_service_) {
    weave::ErrorPtr error;
    weave::Error::AddTo(&error, FROM_HERE, kErrorDomain, "busy",
                        "Already connecting to WiFi network");
    base::ThreadTaskRunnerHandle::Get()->PostTask(
        FROM_HERE, base::Bind(callback, base::Passed(&error)));
    return;
  }
  CleanupConnectingService();
  VariantDictionary service_properties;
  service_properties[shill::kTypeProperty] = Any{string{shill::kTypeWifi}};
  service_properties[shill::kSSIDProperty] = Any{ssid};
  if (passphrase.empty()) {
    service_properties[shill::kSecurityProperty] = Any{shill::kSecurityNone};
  } else {
    service_properties[shill::kPassphraseProperty] = Any{passphrase};
    service_properties[shill::kSecurityProperty] = Any{shill::kSecurityPsk};
  }
  service_properties[shill::kSaveCredentialsProperty] = Any{true};
  service_properties[shill::kAutoConnectProperty] = Any{true};
  ObjectPath service_path;
  brillo::ErrorPtr brillo_error;
  if (!manager_proxy_.ConfigureService(service_properties, &service_path,
                                       &brillo_error) ||
      !manager_proxy_.RequestScan(shill::kTypeWifi, &brillo_error)) {
    weave::ErrorPtr weave_error;
    ConvertError(*brillo_error, &weave_error);
    base::ThreadTaskRunnerHandle::Get()->PostTask(
        FROM_HERE, base::Bind(callback, base::Passed(&weave_error)));
    return;
  }
  connecting_service_.reset(new ServiceProxy{bus_, service_path});
  connecting_service_->Connect(nullptr);
  connect_done_callback_ = callback;
  connecting_service_->RegisterPropertyChangedSignalHandler(
      base::Bind(&ShillClient::OnServicePropertyChange,
                 weak_factory_.GetWeakPtr(), service_path),
      base::Bind(&ShillClient::OnServicePropertyChangeRegistration,
                 weak_factory_.GetWeakPtr(), service_path));
  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
      FROM_HERE,
      base::Bind(&ShillClient::ConnectToServiceError,
                 weak_factory_.GetWeakPtr(), connecting_service_),
      base::TimeDelta::FromMinutes(1));
}

void ShillClient::ConnectToServiceError(
    std::shared_ptr<org::chromium::flimflam::ServiceProxy> connecting_service) {
  if (connecting_service != connecting_service_ ||
      connect_done_callback_.is_null()) {
    return;
  }
  std::string error = have_called_connect_ ? connecting_service_error_
                                           : shill::kErrorOutOfRange;
  if (error.empty())
    error = shill::kErrorInternal;
  OnErrorChangeForConnectingService(error);
}

Network::State ShillClient::GetConnectionState() const {
  return connectivity_state_;
}

void ShillClient::StartAccessPoint(const std::string& ssid) {}

void ShillClient::StopAccessPoint() {}

std::string ShillClient::GetIpAddress() {
  return ip_address_;
}

void ShillClient::AddConnectionChangedCallback(
    const ConnectionChangedCallback& listener) {
  connectivity_listeners_.push_back(listener);
}

bool ShillClient::IsMonitoredDevice(DeviceProxyInterface* device) {
  if (device_whitelist_.empty()) {
    return true;
  }
  VariantDictionary device_properties;
  if (!device->GetProperties(&device_properties, nullptr)) {
    LOG(ERROR) << "Devices without properties aren't whitelisted.";
    return false;
  }
  auto it = device_properties.find(shill::kInterfaceProperty);
  if (it == device_properties.end()) {
    LOG(ERROR) << "Failed to find interface property in device properties.";
    return false;
  }
  return base::Contains(device_whitelist_, it->second.TryGet<string>());
}

void ShillClient::OnShillServiceOwnerChange(const string& old_owner,
                                            const string& new_owner) {
  VLOG(1) << "Shill service owner name changed to '" << new_owner << "'";
  if (new_owner.empty()) {
    CleanupConnectingService();
    devices_.clear();
    connectivity_state_ = Network::State::kOffline;
  } else {
    Init();  // New service owner means shill reset!
  }
}

void ShillClient::OnManagerPropertyChangeRegistration(const string& interface,
                                                      const string& signal_name,
                                                      bool success) {
  VLOG(3) << "Registered ManagerPropertyChange handler.";
  CHECK(success) << "privetd requires Manager signals.";
  VariantDictionary properties;
  if (!manager_proxy_.GetProperties(&properties, nullptr)) {
    LOG(ERROR) << "Unable to get properties from Manager, waiting for "
                  "Manager to come back online.";
    return;
  }
  auto it = properties.find(shill::kDevicesProperty);
  CHECK(it != properties.end()) << "Shill should always publish a device list.";
  OnManagerPropertyChange(shill::kDevicesProperty, it->second);
}

void ShillClient::OnManagerPropertyChange(const string& property_name,
                                          const Any& property_value) {
  if (property_name != shill::kDevicesProperty) {
    return;
  }
  VLOG(3) << "Manager's device list has changed.";
  // We're going to remove every device we haven't seen in the update.
  set<ObjectPath> device_paths_to_remove;
  for (const auto& kv : devices_) {
    device_paths_to_remove.insert(kv.first);
  }
  for (const auto& device_path : property_value.TryGet<vector<ObjectPath>>()) {
    if (!device_path.IsValid()) {
      LOG(ERROR) << "Ignoring invalid device path in Manager's device list.";
      return;
    }
    auto it = devices_.find(device_path);
    if (it != devices_.end()) {
      // Found an existing proxy.  Since the whitelist never changes,
      // this still a valid device.
      device_paths_to_remove.erase(device_path);
      continue;
    }
    std::unique_ptr<DeviceProxy> device{new DeviceProxy{bus_, device_path}};
    if (!IsMonitoredDevice(device.get())) {
      continue;
    }
    VLOG(3) << "Creating device proxy at " << device_path.value();
    devices_[device_path].device = std::move(device);
    // Register after adding to devices list as registration callback will be
    // invoked directly.
    devices_[device_path].device->RegisterPropertyChangedSignalHandler(
        base::Bind(&ShillClient::OnDevicePropertyChange,
                   weak_factory_.GetWeakPtr(), device_path),
        base::Bind(&ShillClient::OnDevicePropertyChangeRegistration,
                   weak_factory_.GetWeakPtr(), device_path));
  }

  // Clean up devices/services related to removed devices.
  if (!device_paths_to_remove.empty()) {
    for (const ObjectPath& device_path : device_paths_to_remove) {
      devices_.erase(device_path);
    }
    UpdateConnectivityState();
  }
}

void ShillClient::OnDevicePropertyChangeRegistration(
    const ObjectPath& device_path,
    const string& interface,
    const string& signal_name,
    bool success) {
  VLOG(3) << "Registered DevicePropertyChange handler.";
  auto it = devices_.find(device_path);
  if (it == devices_.end()) {
    return;
  }
  CHECK(success) << "Failed to subscribe to Device property changes.";
  DeviceProxyInterface* device = it->second.device.get();
  VariantDictionary properties;
  if (!device->GetProperties(&properties, nullptr)) {
    LOG(WARNING) << "Failed to get device properties?";
    return;
  }
  auto prop_it = properties.find(shill::kSelectedServiceProperty);
  if (prop_it == properties.end()) {
    LOG(WARNING) << "Failed to get device's selected service?";
    return;
  }
  OnDevicePropertyChange(device_path, shill::kSelectedServiceProperty,
                         prop_it->second);
}

void ShillClient::OnDevicePropertyChange(const ObjectPath& device_path,
                                         const string& property_name,
                                         const Any& property_value) {
  // We only care about selected services anyway.
  if (property_name != shill::kSelectedServiceProperty) {
    return;
  }
  // If the device isn't our list of whitelisted devices, ignore it.
  auto it = devices_.find(device_path);
  if (it == devices_.end()) {
    return;
  }
  DeviceState& device_state = it->second;
  ObjectPath service_path{property_value.TryGet<ObjectPath>()};
  if (!service_path.IsValid()) {
    LOG(ERROR) << "Device at " << device_path.value()
               << " selected invalid service path.";
    return;
  }
  VLOG(3) << "Device at " << it->first.value() << " has selected service at "
          << service_path.value();
  bool removed_old_service{false};
  if (device_state.selected_service) {
    if (device_state.selected_service->GetObjectPath() == service_path) {
      return;  // Spurious update?
    }
    device_state.selected_service.reset();
    device_state.service_state = Network::State::kOffline;
    removed_old_service = true;
  }
  std::shared_ptr<ServiceProxy> new_service;
  const bool reuse_connecting_service =
      service_path.value() != "/" && connecting_service_ &&
      connecting_service_->GetObjectPath() == service_path;
  bool register_service = false;
  if (reuse_connecting_service) {
    new_service = connecting_service_;
    // When we reuse the connecting service, we need to make sure that our
    // cached state is correct.  Normally, we do this by relying reading the
    // state when our signal handlers finish registering, but this may have
    // happened long in the past for the connecting service.
    string state;
    if (GetStateForService(new_service.get(), &state)) {
      device_state.service_state = ShillServiceStateToNetworkState(state);
    } else {
      LOG(WARNING) << "Failed to read properties from existing service "
                      "on selection.";
    }
  } else if (service_path.value() != "/") {
    // The device has selected a new service we haven't see before.
    new_service.reset(new ServiceProxy{bus_, service_path});
    register_service = true;
  }
  device_state.selected_service = new_service;
  if (reuse_connecting_service || removed_old_service) {
    UpdateConnectivityState();
  }
  if (register_service) {
    // Register after setting selected_service as registration callback will be
    // invoked directly.
    new_service->RegisterPropertyChangedSignalHandler(
        base::Bind(&ShillClient::OnServicePropertyChange,
                   weak_factory_.GetWeakPtr(), service_path),
        base::Bind(&ShillClient::OnServicePropertyChangeRegistration,
                   weak_factory_.GetWeakPtr(), service_path));
  }
}

void ShillClient::OnServicePropertyChangeRegistration(const ObjectPath& path,
                                                      const string& interface,
                                                      const string& signal_name,
                                                      bool success) {
  VLOG(3) << "OnServicePropertyChangeRegistration(" << path.value() << ");";
  ServiceProxy* service{nullptr};
  if (connecting_service_ && connecting_service_->GetObjectPath() == path) {
    // Note that the connecting service might also be a selected service.
    service = connecting_service_.get();
    if (!success)
      CleanupConnectingService();
  } else {
    for (const auto& kv : devices_) {
      if (kv.second.selected_service &&
          kv.second.selected_service->GetObjectPath() == path) {
        service = kv.second.selected_service.get();
        break;
      }
    }
  }
  if (service == nullptr || !success) {
    return;  // A failure or success for a proxy we no longer care about.
  }
  VariantDictionary properties;
  if (!service->GetProperties(&properties, nullptr)) {
    return;
  }
  // Give ourselves property changed signals for the initial property
  // values.
  for (auto name : {shill::kStateProperty, shill::kSignalStrengthProperty,
                    shill::kErrorProperty, shill::kIPConfigProperty}) {
    auto it = properties.find(name);
    if (it != properties.end())
      OnServicePropertyChange(path, name, it->second);
  }
}

void ShillClient::OnServicePropertyChange(const ObjectPath& service_path,
                                          const string& property_name,
                                          const Any& property_value) {
  VLOG(3) << "ServicePropertyChange(" << service_path.value() << ", "
          << property_name << ", ...);";

  bool is_connecting_service =
      connecting_service_ &&
      connecting_service_->GetObjectPath() == service_path;
  if (property_name == shill::kStateProperty) {
    const string state{property_value.TryGet<string>()};
    if (state.empty()) {
      VLOG(3) << "Invalid service state update.";
      return;
    }
    VLOG(3) << "New service state=" << state;
    OnStateChangeForSelectedService(service_path, state);
    if (is_connecting_service)
      OnStateChangeForConnectingService(state);
  } else if (property_name == shill::kSignalStrengthProperty) {
    VLOG(3) << "Signal strength=" << property_value.TryGet<uint8_t>();
    if (is_connecting_service)
      OnStrengthChangeForConnectingService(property_value.TryGet<uint8_t>());
  } else if (property_name == shill::kErrorProperty) {
    VLOG(3) << "Error=" << property_value.TryGet<std::string>();
    if (is_connecting_service)
      connecting_service_error_ = property_value.TryGet<std::string>();
  } else if (property_name == shill::kIPConfigProperty) {
    string device_path;
    for (const auto& kv : devices_) {
      if (kv.second.selected_service &&
          kv.second.selected_service->GetObjectPath() == service_path) {
        device_path = kv.first.value();
        break;
      }
    }
    OnIpConfigChange(property_value.TryGet<ObjectPath>(), device_path);
  }
}

void ShillClient::OnIpConfigChange(const ObjectPath& ip_config_path,
                                   const string& device_path) {
  IPConfigProxy ip_config(bus_.get(), ip_config_path);
  VariantDictionary properties;
  if (!ip_config.GetProperties(&properties, nullptr)) {
    LOG(WARNING) << "Failed to read properties from ipconfig.";
    return;
  }
  const auto it = properties.find(shill::kAddressProperty);
  if (it != properties.end()) {
    ip_address_ = it->second.TryGet<string>();
    LOG(INFO) << "IPConfigProperty address = " << ip_address_ << " at "
              << device_path;
    base::ThreadTaskRunnerHandle::Get()->PostTask(
        FROM_HERE, base::Bind(&ShillClient::NotifyConnectivityListeners,
                              weak_factory_.GetWeakPtr(),
                              GetConnectionState() == Network::State::kOnline));
  }
}

void ShillClient::OnStateChangeForConnectingService(const string& state) {
  switch (ShillServiceStateToNetworkState(state)) {
    case Network::State::kOnline: {
      auto callback = connect_done_callback_;
      connect_done_callback_.Reset();
      CleanupConnectingService();

      if (!callback.is_null())
        callback.Run(nullptr);
      break;
    }
    case Network::State::kError: {
      ConnectToServiceError(connecting_service_);
      break;
    }
    case Network::State::kOffline:
    case Network::State::kConnecting:
      break;
  }
}

void ShillClient::OnErrorChangeForConnectingService(const std::string& error) {
  if (error.empty())
    return;

  auto callback = connect_done_callback_;
  CleanupConnectingService();

  weave::ErrorPtr weave_error;
  weave::Error::AddTo(&weave_error, FROM_HERE, kErrorDomain, error,
                      "Failed to connect to WiFi network");

  if (!callback.is_null())
    callback.Run(std::move(weave_error));
}

void ShillClient::OnStrengthChangeForConnectingService(
    uint8_t signal_strength) {
  if (signal_strength == 0 || have_called_connect_) {
    return;
  }
  VLOG(1) << "Connecting service has signal. Calling Connect().";
  have_called_connect_ = true;
  // Failures here indicate that we've already connected,
  // or are connecting, or some other very unexciting thing.
  // Ignore all that, and rely on state changes to detect
  // connectivity.
  connecting_service_->Connect(nullptr);
}

void ShillClient::OnStateChangeForSelectedService(
    const ObjectPath& service_path, const string& state) {
  // Find the device/service pair responsible for this update
  VLOG(3) << "State for potentially selected service " << service_path.value()
          << " have changed to " << state;
  for (auto& kv : devices_) {
    if (kv.second.selected_service &&
        kv.second.selected_service->GetObjectPath() == service_path) {
      VLOG(3) << "Updated cached connection state for selected service.";
      kv.second.service_state = ShillServiceStateToNetworkState(state);
      UpdateConnectivityState();
      return;
    }
  }
}

void ShillClient::UpdateConnectivityState() {
  // Update the connectivity state of the device by picking the
  // state of the currently most connected selected service.
  Network::State new_connectivity_state{Network::State::kOffline};
  for (const auto& kv : devices_) {
    if (kv.second.service_state > new_connectivity_state) {
      new_connectivity_state = kv.second.service_state;
    }
  }
  VLOG(1) << "Connectivity changed: " << EnumToString(connectivity_state_)
          << " -> " << EnumToString(new_connectivity_state);
  // Notify listeners even if state changed to the same value. Listeners may
  // want to handle this event.
  connectivity_state_ = new_connectivity_state;
  // We may call UpdateConnectivityState whenever we mutate a data structure
  // such that our connectivity status could change.  However, we don't want
  // to allow people to call into ShillClient while some other operation is
  // underway.  Therefore, call our callbacks later, when we're in a good
  // state.
  base::ThreadTaskRunnerHandle::Get()->PostTask(
      FROM_HERE, base::Bind(&ShillClient::NotifyConnectivityListeners,
                            weak_factory_.GetWeakPtr(),
                            GetConnectionState() == Network::State::kOnline));
}

void ShillClient::NotifyConnectivityListeners(bool am_online) {
  VLOG(3) << "Notifying connectivity listeners that online=" << am_online;
  for (const auto& listener : connectivity_listeners_)
    listener.Run();
}

void ShillClient::CleanupConnectingService() {
  if (connecting_service_) {
    connecting_service_->ReleaseObjectProxy(base::Bind(&IgnoreDetachEvent));
    connecting_service_.reset();
  }
  connect_done_callback_.Reset();
  have_called_connect_ = false;
}

void ShillClient::OpenSslSocket(const std::string& host,
                                uint16_t port,
                                const OpenSslSocketCallback& callback) {
  if (disable_xmpp_)
    return;
  std::unique_ptr<weave::Stream> raw_stream{
      SocketStream::ConnectBlocking(host, port)};
  if (!raw_stream) {
    brillo::ErrorPtr error;
    brillo::errors::system::AddSystemError(&error, FROM_HERE, errno);
    weave::ErrorPtr weave_error;
    ConvertError(*error.get(), &weave_error);
    base::ThreadTaskRunnerHandle::Get()->PostTask(
        FROM_HERE, base::Bind(callback, nullptr, base::Passed(&weave_error)));
    return;
  }

  SocketStream::TlsConnect(std::move(raw_stream), host, callback);
}

}  // namespace buffet
