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

#include <string>

#include <base/logging.h>
#include <base/strings/stringprintf.h>
#include <brillo/type_name_undecorate.h>
#include <shill/dbus-constants.h>
#include <shill/dbus-proxies.h>

using chromeos_update_engine::connection_utils::ParseConnectionType;
using org::chromium::flimflam::ManagerProxyInterface;
using org::chromium::flimflam::ServiceProxyInterface;
using std::string;

namespace chromeos_update_manager {

bool RealShillProvider::Init() {
  ManagerProxyInterface* manager_proxy = shill_proxy_->GetManagerProxy();
  if (!manager_proxy)
    return false;

  // Subscribe to the manager's PropertyChanged signal.
  manager_proxy->RegisterPropertyChangedSignalHandler(
      base::Bind(&RealShillProvider::OnManagerPropertyChanged,
                 base::Unretained(this)),
      base::Bind(&RealShillProvider::OnSignalConnected,
                 base::Unretained(this)));

  // 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.
  brillo::VariantDictionary properties;
  brillo::ErrorPtr error;
  if (!manager_proxy->GetProperties(&properties, &error))
    return true;

  const auto& prop_default_service =
      properties.find(shill::kDefaultServiceProperty);
  if (prop_default_service != properties.end()) {
    OnManagerPropertyChanged(prop_default_service->first,
                             prop_default_service->second);
  }

  return true;
}

void RealShillProvider::OnManagerPropertyChanged(const string& name,
                                                 const brillo::Any& value) {
  if (name == shill::kDefaultServiceProperty) {
    dbus::ObjectPath service_path = value.TryGet<dbus::ObjectPath>();
    if (!service_path.IsValid()) {
      LOG(WARNING) << "Got an invalid DefaultService path. The property value "
                      "contains a "
                   << value.GetUndecoratedTypeName()
                   << ", read as the object path: '" << service_path.value()
                   << "'";
    }
    ProcessDefaultService(service_path);
  }
}

void RealShillProvider::OnSignalConnected(const string& interface_name,
                                          const string& signal_name,
                                          bool successful) {
  if (!successful) {
    LOG(ERROR) << "Couldn't connect to the signal " << interface_name << "."
               << signal_name;
  }
}

bool RealShillProvider::ProcessDefaultService(
    const dbus::ObjectPath& default_service_path) {
  // We assume that if the service path didn't change, then the connection
  // type and the tethering status of it also didn't change.
  if (default_service_path_ == default_service_path)
    return true;

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

  if (!is_connected) {
    var_conn_type_.UnsetValue();
    var_conn_tethering_.UnsetValue();
    return true;
  }

  // We create and dispose the ServiceProxyInterface on every request.
  std::unique_ptr<ServiceProxyInterface> service =
      shill_proxy_->GetServiceForPath(default_service_path_);

  // Get the connection properties synchronously.
  brillo::VariantDictionary properties;
  brillo::ErrorPtr error;
  if (!service->GetProperties(&properties, &error)) {
    var_conn_type_.UnsetValue();
    var_conn_tethering_.UnsetValue();
    return false;
  }

  // Get the connection tethering mode.
  const auto& prop_tethering = properties.find(shill::kTetheringProperty);
  if (prop_tethering == properties.end()) {
    // Remove the value if not present on the service. This most likely means an
    // error in shill and the policy will handle it, but we will print a log
    // message as well for accessing an unused variable.
    var_conn_tethering_.UnsetValue();
    LOG(ERROR) << "Could not find connection type (service: "
               << default_service_path_.value() << ")";
  } else {
    // If the property doesn't contain a string value, the empty string will
    // become kUnknown.
    var_conn_tethering_.SetValue(
        chromeos_update_engine::connection_utils::ParseConnectionTethering(
            prop_tethering->second.TryGet<string>()));
  }

  // Get the connection type.
  const auto& prop_type = properties.find(shill::kTypeProperty);
  if (prop_type == properties.end()) {
    var_conn_type_.UnsetValue();
    LOG(ERROR) << "Could not find connection tethering mode (service: "
               << default_service_path_.value() << ")";
  } else {
    string type_str = prop_type->second.TryGet<string>();
    if (type_str == shill::kTypeVPN) {
      const auto& prop_physical =
          properties.find(shill::kPhysicalTechnologyProperty);
      if (prop_physical == properties.end()) {
        LOG(ERROR) << "No PhysicalTechnology property found for a VPN"
                   << " connection (service: " << default_service_path_.value()
                   << "). Using default kUnknown value.";
        var_conn_type_.SetValue(
            chromeos_update_engine::ConnectionType::kUnknown);
      } else {
        var_conn_type_.SetValue(
            ParseConnectionType(prop_physical->second.TryGet<string>()));
      }
    } else {
      var_conn_type_.SetValue(ParseConnectionType(type_str));
    }
  }

  return true;
}

}  // namespace chromeos_update_manager
