// Copyright (c) 2012 The Chromium 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 "chromeos/network/network_state.h"

#include "base/strings/stringprintf.h"
#include "chromeos/network/network_event_log.h"
#include "chromeos/network/network_profile_handler.h"
#include "chromeos/network/network_type_pattern.h"
#include "chromeos/network/network_util.h"
#include "chromeos/network/onc/onc_utils.h"
#include "chromeos/network/shill_property_util.h"
#include "third_party/cros_system_api/dbus/service_constants.h"

namespace {

const char kErrorUnknown[] = "Unknown";

bool ConvertListValueToStringVector(const base::ListValue& string_list,
                                    std::vector<std::string>* result) {
  for (size_t i = 0; i < string_list.GetSize(); ++i) {
    std::string str;
    if (!string_list.GetString(i, &str))
      return false;
    result->push_back(str);
  }
  return true;
}

bool IsCaCertNssSet(const base::DictionaryValue& properties) {
  std::string ca_cert_nss;
  if (properties.GetStringWithoutPathExpansion(shill::kEapCaCertNssProperty,
                                               &ca_cert_nss) &&
      !ca_cert_nss.empty()) {
    return true;
  }

  const base::DictionaryValue* provider = NULL;
  properties.GetDictionaryWithoutPathExpansion(shill::kProviderProperty,
                                               &provider);
  if (!provider)
    return false;
  if (provider->GetStringWithoutPathExpansion(
          shill::kL2tpIpsecCaCertNssProperty, &ca_cert_nss) &&
      !ca_cert_nss.empty()) {
    return true;
  }
  if (provider->GetStringWithoutPathExpansion(
          shill::kOpenVPNCaCertNSSProperty, &ca_cert_nss) &&
      !ca_cert_nss.empty()) {
    return true;
  }

  return false;
}

}  // namespace

namespace chromeos {

NetworkState::NetworkState(const std::string& path)
    : ManagedState(MANAGED_TYPE_NETWORK, path),
      visible_(false),
      connectable_(false),
      prefix_length_(0),
      signal_strength_(0),
      activate_over_non_cellular_networks_(false),
      cellular_out_of_credits_(false),
      has_ca_cert_nss_(false) {
}

NetworkState::~NetworkState() {
}

bool NetworkState::PropertyChanged(const std::string& key,
                                   const base::Value& value) {
  // Keep care that these properties are the same as in |GetProperties|.
  if (ManagedStatePropertyChanged(key, value))
    return true;
  if (key == shill::kSignalStrengthProperty) {
    return GetIntegerValue(key, value, &signal_strength_);
  } else if (key == shill::kStateProperty) {
    return GetStringValue(key, value, &connection_state_);
  } else if (key == shill::kVisibleProperty) {
    return GetBooleanValue(key, value, &visible_);
  } else if (key == shill::kConnectableProperty) {
    return GetBooleanValue(key, value, &connectable_);
  } else if (key == shill::kErrorProperty) {
    if (!GetStringValue(key, value, &error_))
      return false;
    if (ErrorIsValid(error_))
      last_error_ = error_;
    else
      error_.clear();
    return true;
  } else if (key == shill::kActivationStateProperty) {
    return GetStringValue(key, value, &activation_state_);
  } else if (key == shill::kRoamingStateProperty) {
    return GetStringValue(key, value, &roaming_);
  } else if (key == shill::kSecurityProperty) {
    return GetStringValue(key, value, &security_);
  } else if (key == shill::kEapMethodProperty) {
    return GetStringValue(key, value, &eap_method_);
  } else if (key == shill::kUIDataProperty) {
    scoped_ptr<NetworkUIData> new_ui_data =
        shill_property_util::GetUIDataFromValue(value);
    if (!new_ui_data) {
      NET_LOG_ERROR("Failed to parse " + key, path());
      return false;
    }
    ui_data_ = *new_ui_data;
    return true;
  } else if (key == shill::kNetworkTechnologyProperty) {
    return GetStringValue(key, value, &network_technology_);
  } else if (key == shill::kDeviceProperty) {
    return GetStringValue(key, value, &device_path_);
  } else if (key == shill::kGuidProperty) {
    return GetStringValue(key, value, &guid_);
  } else if (key == shill::kProfileProperty) {
    return GetStringValue(key, value, &profile_path_);
  } else if (key == shill::kActivateOverNonCellularNetworkProperty) {
    return GetBooleanValue(key, value, &activate_over_non_cellular_networks_);
  } else if (key == shill::kOutOfCreditsProperty) {
    return GetBooleanValue(key, value, &cellular_out_of_credits_);
  } else if (key == shill::kProxyConfigProperty) {
    std::string proxy_config_str;
    if (!value.GetAsString(&proxy_config_str)) {
      NET_LOG_ERROR("Failed to parse " + key, path());
      return false;
    }

    proxy_config_.Clear();
    if (proxy_config_str.empty())
      return true;

    scoped_ptr<base::DictionaryValue> proxy_config_dict(
        onc::ReadDictionaryFromJson(proxy_config_str));
    if (proxy_config_dict) {
      // Warning: The DictionaryValue returned from
      // ReadDictionaryFromJson/JSONParser is an optimized derived class that
      // doesn't allow releasing ownership of nested values. A Swap in the wrong
      // order leads to memory access errors.
      proxy_config_.MergeDictionary(proxy_config_dict.get());
    } else {
      NET_LOG_ERROR("Failed to parse " + key, path());
    }
    return true;
  }
  return false;
}

bool NetworkState::InitialPropertiesReceived(
    const base::DictionaryValue& properties) {
  NET_LOG_DEBUG("InitialPropertiesReceived", path());
  bool changed = false;
  if (!properties.HasKey(shill::kTypeProperty)) {
    NET_LOG_ERROR("NetworkState has no type",
                  shill_property_util::GetNetworkIdFromProperties(properties));
    return false;
  }
  // Ensure that the network has a valid name.
  changed |= UpdateName(properties);

  // Set the has_ca_cert_nss_ property.
  bool had_ca_cert_nss = has_ca_cert_nss_;
  has_ca_cert_nss_ = IsCaCertNssSet(properties);
  changed |= had_ca_cert_nss != has_ca_cert_nss_;

  // By convention, all visible WiFi networks have a SignalStrength > 0.
  if (visible() && type() == shill::kTypeWifi) {
    if (signal_strength_ <= 0)
      signal_strength_ = 1;
  }

  return changed;
}

void NetworkState::GetStateProperties(base::DictionaryValue* dictionary) const {
  ManagedState::GetStateProperties(dictionary);

  // Properties shared by all types.
  dictionary->SetStringWithoutPathExpansion(shill::kGuidProperty, guid());
  dictionary->SetStringWithoutPathExpansion(shill::kSecurityProperty,
                                            security());

  if (visible()) {
    if (!error().empty())
      dictionary->SetStringWithoutPathExpansion(shill::kErrorProperty, error());
    dictionary->SetStringWithoutPathExpansion(shill::kStateProperty,
                                              connection_state());
  }

  // Wireless properties
  if (!NetworkTypePattern::Wireless().MatchesType(type()))
    return;

  if (visible()) {
    dictionary->SetBooleanWithoutPathExpansion(shill::kConnectableProperty,
                                               connectable());
    dictionary->SetIntegerWithoutPathExpansion(shill::kSignalStrengthProperty,
                                               signal_strength());
  }

  // Wifi properties
  if (NetworkTypePattern::WiFi().MatchesType(type())) {
    dictionary->SetStringWithoutPathExpansion(shill::kEapMethodProperty,
                                              eap_method());
  }

  // Mobile properties
  if (NetworkTypePattern::Mobile().MatchesType(type())) {
    dictionary->SetStringWithoutPathExpansion(
        shill::kNetworkTechnologyProperty,
        network_technology());
    dictionary->SetStringWithoutPathExpansion(shill::kActivationStateProperty,
                                              activation_state());
    dictionary->SetStringWithoutPathExpansion(shill::kRoamingStateProperty,
                                              roaming());
    dictionary->SetBooleanWithoutPathExpansion(shill::kOutOfCreditsProperty,
                                               cellular_out_of_credits());
  }
}

void NetworkState::IPConfigPropertiesChanged(
    const base::DictionaryValue& properties) {
  for (base::DictionaryValue::Iterator iter(properties);
       !iter.IsAtEnd(); iter.Advance()) {
    std::string key = iter.key();
    const base::Value& value = iter.value();

    if (key == shill::kAddressProperty) {
      GetStringValue(key, value, &ip_address_);
    } else if (key == shill::kGatewayProperty) {
      GetStringValue(key, value, &gateway_);
    } else if (key == shill::kNameServersProperty) {
      const base::ListValue* dns_servers;
      if (value.GetAsList(&dns_servers)) {
        dns_servers_.clear();
        ConvertListValueToStringVector(*dns_servers, &dns_servers_);
      }
    } else if (key == shill::kPrefixlenProperty) {
      GetIntegerValue(key, value, &prefix_length_);
    } else if (key == shill::kWebProxyAutoDiscoveryUrlProperty) {
      std::string url_string;
      if (GetStringValue(key, value, &url_string)) {
        if (url_string.empty()) {
          web_proxy_auto_discovery_url_ = GURL();
        } else {
          GURL gurl(url_string);
          if (gurl.is_valid()) {
            web_proxy_auto_discovery_url_ = gurl;
          } else {
            NET_LOG_ERROR("Invalid WebProxyAutoDiscoveryUrl: " + url_string,
                          path());
            web_proxy_auto_discovery_url_ = GURL();
          }
        }
      }
    }
  }
}

bool NetworkState::RequiresActivation() const {
  return (type() == shill::kTypeCellular &&
          activation_state() != shill::kActivationStateActivated &&
          activation_state() != shill::kActivationStateUnknown);
}

std::string NetworkState::connection_state() const {
  if (!visible())
    return shill::kStateDisconnect;
  return connection_state_;
}

bool NetworkState::IsConnectedState() const {
  return visible() && StateIsConnected(connection_state_);
}

bool NetworkState::IsConnectingState() const {
  return visible() && StateIsConnecting(connection_state_);
}

bool NetworkState::IsInProfile() const {
  // kTypeEthernetEap is always saved. We need this check because it does
  // not show up in the visible list, but its properties may not be available
  // when it first shows up in ServiceCompleteList. See crbug.com/355117.
  return !profile_path_.empty() || type() == shill::kTypeEthernetEap;
}

bool NetworkState::IsPrivate() const {
  return !profile_path_.empty() &&
      profile_path_ != NetworkProfileHandler::GetSharedProfilePath();
}

std::string NetworkState::GetDnsServersAsString() const {
  std::string result;
  for (size_t i = 0; i < dns_servers_.size(); ++i) {
    if (i != 0)
      result += ",";
    result += dns_servers_[i];
  }
  return result;
}

std::string NetworkState::GetNetmask() const {
  return network_util::PrefixLengthToNetmask(prefix_length_);
}

std::string NetworkState::GetSpecifier() const {
  if (!update_received()) {
    NET_LOG_ERROR("GetSpecifier called before update", path());
    return std::string();
  }
  if (type() == shill::kTypeWifi)
    return name() + "_" + security_;
  if (!name().empty())
    return name();
  return type();  // For unnamed networks such as ethernet.
}

void NetworkState::SetGuid(const std::string& guid) {
  guid_ = guid;
}

bool NetworkState::UpdateName(const base::DictionaryValue& properties) {
  std::string updated_name =
      shill_property_util::GetNameFromProperties(path(), properties);
  if (updated_name != name()) {
    set_name(updated_name);
    return true;
  }
  return false;
}

// static
bool NetworkState::StateIsConnected(const std::string& connection_state) {
  return (connection_state == shill::kStateReady ||
          connection_state == shill::kStateOnline ||
          connection_state == shill::kStatePortal);
}

// static
bool NetworkState::StateIsConnecting(const std::string& connection_state) {
  return (connection_state == shill::kStateAssociation ||
          connection_state == shill::kStateConfiguration ||
          connection_state == shill::kStateCarrier);
}

// static
bool NetworkState::ErrorIsValid(const std::string& error) {
  // Shill uses "Unknown" to indicate an unset or cleared error state.
  return !error.empty() && error != kErrorUnknown;
}

}  // namespace chromeos
