// Copyright (c) 2013 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 "ash/system/chromeos/network/network_connect.h"

#include "ash/shell.h"
#include "ash/system/chromeos/network/network_observer.h"
#include "ash/system/chromeos/network/network_state_notifier.h"
#include "ash/system/tray/system_tray_delegate.h"
#include "ash/system/tray/system_tray_notifier.h"
#include "base/bind.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chromeos/login/login_state.h"
#include "chromeos/network/device_state.h"
#include "chromeos/network/network_configuration_handler.h"
#include "chromeos/network/network_connection_handler.h"
#include "chromeos/network/network_event_log.h"
#include "chromeos/network/network_handler_callbacks.h"
#include "chromeos/network/network_profile.h"
#include "chromeos/network/network_profile_handler.h"
#include "chromeos/network/network_state.h"
#include "chromeos/network/network_state_handler.h"
#include "grit/ash_strings.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
#include "ui/base/l10n/l10n_util.h"

using chromeos::DeviceState;
using chromeos::NetworkConfigurationHandler;
using chromeos::NetworkConnectionHandler;
using chromeos::NetworkHandler;
using chromeos::NetworkProfile;
using chromeos::NetworkProfileHandler;
using chromeos::NetworkState;

namespace ash {

namespace {

// TODO(stevenjb): This should be in service_constants.h
const char kErrorInProgress[] = "org.chromium.flimflam.Error.InProgress";

// Returns true for carriers that can be activated through Shill instead of
// through a WebUI dialog.
bool IsDirectActivatedCarrier(const std::string& carrier) {
  if (carrier == shill::kCarrierSprint)
    return true;
  return false;
}

void ShowErrorNotification(const std::string& error,
                           const std::string& service_path) {
  Shell::GetInstance()->system_tray_notifier()->network_state_notifier()->
      ShowNetworkConnectError(error, service_path);
}

void OnConnectFailed(const std::string& service_path,
                     gfx::NativeWindow owning_window,
                     const std::string& error_name,
                     scoped_ptr<base::DictionaryValue> error_data) {
  NET_LOG_ERROR("Connect Failed: " + error_name, service_path);

  // If a new connect attempt canceled this connect, no need to notify the user.
  if (error_name == NetworkConnectionHandler::kErrorConnectCanceled)
    return;

  if (error_name == NetworkConnectionHandler::kErrorPassphraseRequired ||
      error_name == NetworkConnectionHandler::kErrorConfigurationRequired ||
      error_name == NetworkConnectionHandler::kErrorAuthenticationRequired) {
    ash::Shell::GetInstance()->system_tray_delegate()->ConfigureNetwork(
        service_path);
    return;
  }

  if (error_name == NetworkConnectionHandler::kErrorCertificateRequired) {
    ash::Shell::GetInstance()->system_tray_delegate()->EnrollOrConfigureNetwork(
        service_path, owning_window);
    return;
  }

  if (error_name == NetworkConnectionHandler::kErrorActivationRequired) {
    network_connect::ActivateCellular(service_path);
    return;
  }

  if (error_name == NetworkConnectionHandler::kErrorConnected ||
      error_name == NetworkConnectionHandler::kErrorConnecting) {
    ash::Shell::GetInstance()->system_tray_delegate()->ShowNetworkSettings(
        service_path);
    return;
  }

  // ConnectFailed or unknown error; show a notification.
  ShowErrorNotification(error_name, service_path);

  // Show a configure dialog for ConnectFailed errors.
  if (error_name != NetworkConnectionHandler::kErrorConnectFailed)
    return;

  // If Shill reports an InProgress error, don't try to configure the network.
  std::string dbus_error_name;
  error_data.get()->GetString(
      chromeos::network_handler::kDbusErrorName, &dbus_error_name);
  if (dbus_error_name == kErrorInProgress)
    return;

  ash::Shell::GetInstance()->system_tray_delegate()->ConfigureNetwork(
      service_path);
}

void OnConnectSucceeded(const std::string& service_path) {
  NET_LOG_USER("Connect Succeeded", service_path);
  ash::Shell::GetInstance()->system_tray_notifier()->NotifyClearNetworkMessage(
      NetworkObserver::ERROR_CONNECT_FAILED);
}

// If |check_error_state| is true, error state for the network is checked,
// otherwise any current error state is ignored (e.g. for recently configured
// networks or repeat connect attempts). |owning_window| will be used to parent
// any configuration UI on failure and may be NULL (in which case the default
// window will be used).
void CallConnectToNetwork(const std::string& service_path,
                          bool check_error_state,
                          gfx::NativeWindow owning_window) {
  NET_LOG_USER("ConnectToNetwork", service_path);

  ash::Shell::GetInstance()->system_tray_notifier()->NotifyClearNetworkMessage(
      NetworkObserver::ERROR_CONNECT_FAILED);

  NetworkHandler::Get()->network_connection_handler()->ConnectToNetwork(
      service_path,
      base::Bind(&OnConnectSucceeded, service_path),
      base::Bind(&OnConnectFailed, service_path, owning_window),
      check_error_state);
}

void OnActivateFailed(const std::string& service_path,
                     const std::string& error_name,
                      scoped_ptr<base::DictionaryValue> error_data) {
  NET_LOG_ERROR("Unable to activate network", service_path);
  ShowErrorNotification(
      NetworkConnectionHandler::kErrorActivateFailed, service_path);
}

void OnActivateSucceeded(const std::string& service_path) {
  NET_LOG_USER("Activation Succeeded", service_path);
}

void OnConfigureFailed(const std::string& error_name,
                       scoped_ptr<base::DictionaryValue> error_data) {
  NET_LOG_ERROR("Unable to configure network", "");
  ShowErrorNotification(NetworkConnectionHandler::kErrorConfigureFailed, "");
}

void OnConfigureSucceeded(const std::string& service_path) {
  NET_LOG_USER("Configure Succeeded", service_path);
  // After configuring a network, ignore any (possibly stale) error state.
  const bool check_error_state = false;
  const gfx::NativeWindow owning_window = NULL;
  CallConnectToNetwork(service_path, check_error_state, owning_window);
}

void SetPropertiesFailed(const std::string& desc,
                         const std::string& service_path,
                         const std::string& config_error_name,
                         scoped_ptr<base::DictionaryValue> error_data) {
  NET_LOG_ERROR(desc + ": Failed: " + config_error_name, service_path);
  ShowErrorNotification(
      NetworkConnectionHandler::kErrorConfigureFailed, service_path);
}

void SetPropertiesToClear(base::DictionaryValue* properties_to_set,
                          std::vector<std::string>* properties_to_clear) {
  // Move empty string properties to properties_to_clear.
  for (base::DictionaryValue::Iterator iter(*properties_to_set);
       !iter.IsAtEnd(); iter.Advance()) {
    std::string value_str;
    if (iter.value().GetAsString(&value_str) && value_str.empty())
      properties_to_clear->push_back(iter.key());
  }
  // Remove cleared properties from properties_to_set.
  for (std::vector<std::string>::iterator iter = properties_to_clear->begin();
       iter != properties_to_clear->end(); ++iter) {
    properties_to_set->RemoveWithoutPathExpansion(*iter, NULL);
  }
}

void ClearPropertiesAndConnect(
    const std::string& service_path,
    const std::vector<std::string>& properties_to_clear) {
  NET_LOG_USER("ClearPropertiesAndConnect", service_path);
  // After configuring a network, ignore any (possibly stale) error state.
  const bool check_error_state = false;
  const gfx::NativeWindow owning_window = NULL;
  NetworkHandler::Get()->network_configuration_handler()->ClearProperties(
      service_path,
      properties_to_clear,
      base::Bind(&CallConnectToNetwork,
                 service_path, check_error_state,
                 owning_window),
      base::Bind(&SetPropertiesFailed, "ClearProperties", service_path));
}

// Returns false if !shared and no valid profile is available, which will
// trigger an error and abort.
bool GetNetworkProfilePath(bool shared, std::string* profile_path) {
  if (shared) {
    *profile_path = NetworkProfileHandler::kSharedProfilePath;
    return true;
  }

  if (!chromeos::LoginState::Get()->IsUserAuthenticated()) {
    NET_LOG_ERROR("User profile specified before login", "");
    return false;
  }

  const NetworkProfile* profile  =
      NetworkHandler::Get()->network_profile_handler()->
      GetDefaultUserProfile();
  if (!profile) {
    NET_LOG_ERROR("No user profile for unshared network configuration", "");
    return false;
  }

  *profile_path = profile->path;
  return true;
}

void ConfigureSetProfileSucceeded(
    const std::string& service_path,
    scoped_ptr<base::DictionaryValue> properties_to_set) {
  std::vector<std::string> properties_to_clear;
  SetPropertiesToClear(properties_to_set.get(), &properties_to_clear);
  NetworkHandler::Get()->network_configuration_handler()->SetProperties(
      service_path,
      *properties_to_set,
      base::Bind(&ClearPropertiesAndConnect,
                 service_path,
                 properties_to_clear),
      base::Bind(&SetPropertiesFailed, "SetProperties", service_path));
}

}  // namespace

namespace network_connect {

void ConnectToNetwork(const std::string& service_path,
                      gfx::NativeWindow owning_window) {
  const bool check_error_state = true;
  CallConnectToNetwork(service_path, check_error_state, owning_window);
}

void ActivateCellular(const std::string& service_path) {
  NET_LOG_USER("ActivateCellular", service_path);
  const DeviceState* cellular_device =
      NetworkHandler::Get()->network_state_handler()->
      GetDeviceStateByType(flimflam::kTypeCellular);
  if (!cellular_device) {
    NET_LOG_ERROR("ActivateCellular with no Device", service_path);
    return;
  }
  if (!IsDirectActivatedCarrier(cellular_device->carrier())) {
    // For non direct activation, show the mobile setup dialog which can be
    // used to activate the network.
    ash::Shell::GetInstance()->system_tray_delegate()->ShowMobileSetup(
        service_path);
    return;
  }
  const NetworkState* cellular =
      NetworkHandler::Get()->network_state_handler()->
      GetNetworkState(service_path);
  if (!cellular || cellular->type() != flimflam::kTypeCellular) {
    NET_LOG_ERROR("ActivateCellular with no Service", service_path);
    return;
  }
  if (cellular->activation_state() == flimflam::kActivationStateActivated) {
    NET_LOG_ERROR("ActivateCellular for activated service", service_path);
    return;
  }

  NetworkHandler::Get()->network_connection_handler()->ActivateNetwork(
      service_path,
      "",  // carrier
      base::Bind(&OnActivateSucceeded, service_path),
      base::Bind(&OnActivateFailed, service_path));
}

void ConfigureNetworkAndConnect(const std::string& service_path,
                                const base::DictionaryValue& properties,
                                bool shared) {
  NET_LOG_USER("ConfigureNetworkAndConnect", service_path);

  scoped_ptr<base::DictionaryValue> properties_to_set(properties.DeepCopy());

  std::string profile_path;
  if (!GetNetworkProfilePath(shared, &profile_path)) {
    ShowErrorNotification(
        NetworkConnectionHandler::kErrorConfigureFailed, service_path);
    return;
  }
  NetworkHandler::Get()->network_configuration_handler()->SetNetworkProfile(
      service_path, profile_path,
      base::Bind(&ConfigureSetProfileSucceeded,
                 service_path, base::Passed(&properties_to_set)),
      base::Bind(&SetPropertiesFailed,
                 "SetProfile: " + profile_path, service_path));
}

void CreateConfigurationAndConnect(base::DictionaryValue* properties,
                                   bool shared) {
  NET_LOG_USER("CreateConfigurationAndConnect", "");
  std::string profile_path;
  if (!GetNetworkProfilePath(shared, &profile_path)) {
    ShowErrorNotification(NetworkConnectionHandler::kErrorConfigureFailed, "");
    return;
  }
  properties->SetStringWithoutPathExpansion(
      flimflam::kProfileProperty, profile_path);
  NetworkHandler::Get()->network_configuration_handler()->CreateConfiguration(
      *properties,
      base::Bind(&OnConfigureSucceeded),
      base::Bind(&OnConfigureFailed));
}

string16 ErrorString(const std::string& error) {
  if (error.empty())
    return string16();
  if (error == flimflam::kErrorOutOfRange)
    return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_OUT_OF_RANGE);
  if (error == flimflam::kErrorPinMissing)
    return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_PIN_MISSING);
  if (error == flimflam::kErrorDhcpFailed)
    return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_DHCP_FAILED);
  if (error == flimflam::kErrorConnectFailed)
    return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_CONNECT_FAILED);
  if (error == flimflam::kErrorBadPassphrase)
    return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_BAD_PASSPHRASE);
  if (error == flimflam::kErrorBadWEPKey)
    return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_BAD_WEPKEY);
  if (error == flimflam::kErrorActivationFailed) {
    return l10n_util::GetStringUTF16(
        IDS_CHROMEOS_NETWORK_ERROR_ACTIVATION_FAILED);
  }
  if (error == flimflam::kErrorNeedEvdo)
    return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_NEED_EVDO);
  if (error == flimflam::kErrorNeedHomeNetwork) {
    return l10n_util::GetStringUTF16(
        IDS_CHROMEOS_NETWORK_ERROR_NEED_HOME_NETWORK);
  }
  if (error == flimflam::kErrorOtaspFailed)
    return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_OTASP_FAILED);
  if (error == flimflam::kErrorAaaFailed)
    return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_AAA_FAILED);
  if (error == flimflam::kErrorInternal)
    return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_INTERNAL);
  if (error == flimflam::kErrorDNSLookupFailed) {
    return l10n_util::GetStringUTF16(
        IDS_CHROMEOS_NETWORK_ERROR_DNS_LOOKUP_FAILED);
  }
  if (error == flimflam::kErrorHTTPGetFailed) {
    return l10n_util::GetStringUTF16(
        IDS_CHROMEOS_NETWORK_ERROR_HTTP_GET_FAILED);
  }
  if (error == flimflam::kErrorIpsecPskAuthFailed) {
    return l10n_util::GetStringUTF16(
        IDS_CHROMEOS_NETWORK_ERROR_IPSEC_PSK_AUTH_FAILED);
  }
  if (error == flimflam::kErrorIpsecCertAuthFailed ||
      error == shill::kErrorEapAuthenticationFailed) {
    return l10n_util::GetStringUTF16(
        IDS_CHROMEOS_NETWORK_ERROR_CERT_AUTH_FAILED);
  }
  if (error == shill::kErrorEapLocalTlsFailed) {
    return l10n_util::GetStringUTF16(
        IDS_CHROMEOS_NETWORK_ERROR_EAP_LOCAL_TLS_FAILED);
  }
  if (error == shill::kErrorEapRemoteTlsFailed) {
    return l10n_util::GetStringUTF16(
        IDS_CHROMEOS_NETWORK_ERROR_EAP_REMOTE_TLS_FAILED);
  }
  if (error == flimflam::kErrorPppAuthFailed) {
    return l10n_util::GetStringUTF16(
        IDS_CHROMEOS_NETWORK_ERROR_PPP_AUTH_FAILED);
  }

  if (StringToLowerASCII(error) ==
      StringToLowerASCII(std::string(flimflam::kUnknownString))) {
    return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_UNKNOWN);
  }
  return l10n_util::GetStringFUTF16(IDS_NETWORK_UNRECOGNIZED_ERROR,
                                    UTF8ToUTF16(error));
}

}  // network_connect
}  // ash
