// Copyright 2015 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 "chrome/browser/ui/android/bluetooth_chooser_android.h"

#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ssl/chrome_security_state_model_client.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "components/prefs/pref_service.h"
#include "components/url_formatter/elide_url.h"
#include "content/public/browser/android/content_view_core.h"
#include "content/public/browser/render_frame_host.h"
#include "jni/BluetoothChooserDialog_jni.h"
#include "ui/android/window_android.h"
#include "url/gurl.h"
#include "url/origin.h"

using base::android::AttachCurrentThread;
using base::android::ConvertUTF8ToJavaString;
using base::android::ConvertUTF16ToJavaString;
using base::android::ScopedJavaLocalRef;

BluetoothChooserAndroid::BluetoothChooserAndroid(
    content::RenderFrameHost* frame,
    const EventHandler& event_handler)
    : web_contents_(content::WebContents::FromRenderFrameHost(frame)),
      event_handler_(event_handler) {
  const url::Origin origin = frame->GetLastCommittedOrigin();
  DCHECK(!origin.unique());

  base::android::ScopedJavaLocalRef<jobject> window_android =
      content::ContentViewCore::FromWebContents(web_contents_)
          ->GetWindowAndroid()
          ->GetJavaObject();

  ChromeSecurityStateModelClient* security_model_client =
      ChromeSecurityStateModelClient::FromWebContents(web_contents_);
  DCHECK(security_model_client);

  // Create (and show) the BluetoothChooser dialog.
  JNIEnv* env = AttachCurrentThread();
  Profile* profile =
      Profile::FromBrowserContext(web_contents_->GetBrowserContext());
  std::string languages =
      profile->GetPrefs()->GetString(prefs::kAcceptLanguages);
  base::android::ScopedJavaLocalRef<jstring> origin_string =
      base::android::ConvertUTF16ToJavaString(
          env, url_formatter::FormatUrlForSecurityDisplay(
                   frame->GetLastCommittedURL(), languages));
  java_dialog_.Reset(Java_BluetoothChooserDialog_create(
      env, window_android.obj(), origin_string.obj(),
      security_model_client->GetSecurityInfo().security_level,
      reinterpret_cast<intptr_t>(this)));
}

BluetoothChooserAndroid::~BluetoothChooserAndroid() {
  if (!java_dialog_.is_null()) {
    Java_BluetoothChooserDialog_closeDialog(AttachCurrentThread(),
                                            java_dialog_.obj());
  }
}

bool BluetoothChooserAndroid::CanAskForScanningPermission() {
  // Creating the dialog returns null if Chromium can't ask for permission to
  // scan for BT devices.
  return !java_dialog_.is_null();
}

void BluetoothChooserAndroid::SetAdapterPresence(AdapterPresence presence) {
  JNIEnv* env = AttachCurrentThread();
  if (presence != AdapterPresence::POWERED_ON) {
    Java_BluetoothChooserDialog_notifyAdapterTurnedOff(env, java_dialog_.obj());
  } else {
    Java_BluetoothChooserDialog_notifyAdapterTurnedOn(env, java_dialog_.obj());
    RestartSearch();
  }
}

void BluetoothChooserAndroid::ShowDiscoveryState(DiscoveryState state) {
  // These constants are used in BluetoothChooserDialog.notifyDiscoveryState.
  int java_state = -1;
  switch (state) {
    case DiscoveryState::FAILED_TO_START:
      java_state = 0;
      break;
    case DiscoveryState::DISCOVERING:
      java_state = 1;
      break;
    case DiscoveryState::IDLE:
      java_state = 2;
      break;
  }
  Java_BluetoothChooserDialog_notifyDiscoveryState(
      AttachCurrentThread(), java_dialog_.obj(), java_state);
}

void BluetoothChooserAndroid::AddDevice(const std::string& device_id,
                                        const base::string16& device_name) {
  JNIEnv* env = AttachCurrentThread();
  ScopedJavaLocalRef<jstring> java_device_id =
      ConvertUTF8ToJavaString(env, device_id);
  ScopedJavaLocalRef<jstring> java_device_name =
      ConvertUTF16ToJavaString(env, device_name);
  Java_BluetoothChooserDialog_addDevice(
      env, java_dialog_.obj(), java_device_id.obj(), java_device_name.obj());
}

void BluetoothChooserAndroid::RemoveDevice(const std::string& device_id) {
  JNIEnv* env = AttachCurrentThread();
  ScopedJavaLocalRef<jstring> java_device_id =
      ConvertUTF16ToJavaString(env, base::UTF8ToUTF16(device_id));
  Java_BluetoothChooserDialog_removeDevice(env, java_dialog_.obj(),
                                           java_device_id.obj());
}

void BluetoothChooserAndroid::OnDialogFinished(
    JNIEnv* env,
    const JavaParamRef<jobject>& obj,
    jint event_type,
    const JavaParamRef<jstring>& device_id) {
  // Values are defined in BluetoothChooserDialog as DIALOG_FINISHED constants.
  switch (event_type) {
    case 0:
      event_handler_.Run(Event::DENIED_PERMISSION, "");
      return;
    case 1:
      event_handler_.Run(Event::CANCELLED, "");
      return;
    case 2:
      event_handler_.Run(
          Event::SELECTED,
          base::android::ConvertJavaStringToUTF8(env, device_id));
      return;
  }
  NOTREACHED();
}

void BluetoothChooserAndroid::RestartSearch() {
  event_handler_.Run(Event::RESCAN, "");
}

void BluetoothChooserAndroid::RestartSearch(JNIEnv*,
                                            const JavaParamRef<jobject>&) {
  RestartSearch();
}

void BluetoothChooserAndroid::ShowBluetoothOverviewLink(
    JNIEnv* env,
    const JavaParamRef<jobject>& obj) {
  OpenURL(chrome::kChooserBluetoothOverviewURL);
  event_handler_.Run(Event::SHOW_OVERVIEW_HELP, "");
}

void BluetoothChooserAndroid::ShowBluetoothAdapterOffLink(
    JNIEnv* env,
    const JavaParamRef<jobject>& obj) {
  OpenURL(chrome::kChooserBluetoothOverviewURL);
  event_handler_.Run(Event::SHOW_ADAPTER_OFF_HELP, "");
}

void BluetoothChooserAndroid::ShowNeedLocationPermissionLink(
    JNIEnv* env,
    const JavaParamRef<jobject>& obj) {
  OpenURL(chrome::kChooserBluetoothOverviewURL);
  event_handler_.Run(Event::SHOW_NEED_LOCATION_HELP, "");
}

// static
bool BluetoothChooserAndroid::Register(JNIEnv* env) {
  return RegisterNativesImpl(env);
}

void BluetoothChooserAndroid::OpenURL(const char* url) {
  web_contents_->OpenURL(content::OpenURLParams(
      GURL(url), content::Referrer(), NEW_FOREGROUND_TAB,
      ui::PAGE_TRANSITION_AUTO_TOPLEVEL, false /* is_renderer_initiated */));
}