// 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 "chrome/browser/speech/speech_recognition_bubble_controller.h"

#include "base/bind.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"

using content::BrowserThread;
using content::WebContents;

namespace {
const int kInvalidSessionId = 0;
}

namespace speech {

SpeechRecognitionBubbleController::SpeechRecognitionBubbleController(
    Delegate* delegate)
    : delegate_(delegate),
      current_bubble_session_id_(kInvalidSessionId),
      current_bubble_render_process_id_(0),
      current_bubble_render_view_id_(0),
      last_request_issued_(REQUEST_CLOSE) {
}

SpeechRecognitionBubbleController::~SpeechRecognitionBubbleController() {
  DCHECK_EQ(kInvalidSessionId, current_bubble_session_id_);
}

void SpeechRecognitionBubbleController::CreateBubble(
    int session_id,
    int render_process_id,
    int render_view_id,
    const gfx::Rect& element_rect) {
  current_bubble_session_id_ = session_id;
  current_bubble_render_process_id_ = render_process_id;
  current_bubble_render_view_id_ = render_view_id;

  UIRequest request(REQUEST_CREATE);
  request.render_process_id = render_process_id;
  request.render_view_id = render_view_id;
  request.element_rect = element_rect;
  ProcessRequestInUiThread(request);
}

void SpeechRecognitionBubbleController::SetBubbleRecordingMode() {
  ProcessRequestInUiThread(UIRequest(REQUEST_SET_RECORDING_MODE));
}

void SpeechRecognitionBubbleController::SetBubbleRecognizingMode() {
  ProcessRequestInUiThread(UIRequest(REQUEST_SET_RECOGNIZING_MODE));
}

void SpeechRecognitionBubbleController::SetBubbleMessage(const string16& text) {
  UIRequest request(REQUEST_SET_MESSAGE);
  request.message = text;
  ProcessRequestInUiThread(request);
}

bool SpeechRecognitionBubbleController::IsShowingMessage() const {
  return last_request_issued_ == REQUEST_SET_MESSAGE;
}

void SpeechRecognitionBubbleController::SetBubbleInputVolume(
    float volume, float noise_volume) {
  UIRequest request(REQUEST_SET_INPUT_VOLUME);
  request.volume = volume;
  request.noise_volume = noise_volume;
  ProcessRequestInUiThread(request);
}

void SpeechRecognitionBubbleController::CloseBubble() {
  current_bubble_session_id_ = kInvalidSessionId;
  ProcessRequestInUiThread(UIRequest(REQUEST_CLOSE));
}

int SpeechRecognitionBubbleController::GetActiveSessionID() const {
  return current_bubble_session_id_;
}

bool SpeechRecognitionBubbleController::IsShowingBubbleForRenderView(
    int render_process_id, int render_view_id) {
  return (current_bubble_session_id_ != kInvalidSessionId) &&
         (current_bubble_render_process_id_ == render_process_id) &&
         (current_bubble_render_view_id_ == render_view_id);
}

void SpeechRecognitionBubbleController::InfoBubbleButtonClicked(
    SpeechRecognitionBubble::Button button) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      base::Bind(
          &SpeechRecognitionBubbleController::InvokeDelegateButtonClicked,
          this, button));
}

void SpeechRecognitionBubbleController::InfoBubbleFocusChanged() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      base::Bind(
          &SpeechRecognitionBubbleController::InvokeDelegateFocusChanged,
          this));
}

void SpeechRecognitionBubbleController::InvokeDelegateButtonClicked(
    SpeechRecognitionBubble::Button button) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  DCHECK_NE(kInvalidSessionId, current_bubble_session_id_);
  delegate_->InfoBubbleButtonClicked(current_bubble_session_id_, button);
}

void SpeechRecognitionBubbleController::InvokeDelegateFocusChanged() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  DCHECK_NE(kInvalidSessionId, current_bubble_session_id_);
  delegate_->InfoBubbleFocusChanged(current_bubble_session_id_);
}

void SpeechRecognitionBubbleController::ProcessRequestInUiThread(
    const UIRequest& request) {
  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    last_request_issued_ = request.type;
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
        &SpeechRecognitionBubbleController::ProcessRequestInUiThread,
        this,
        request));
    return;
  }

  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  switch (request.type) {
    case REQUEST_CREATE:
      bubble_.reset(SpeechRecognitionBubble::Create(
          tab_util::GetWebContentsByID(request.render_process_id,
                                       request.render_view_id),
          this,
          request.element_rect));

      if (!bubble_.get()) {
        // Could be null if tab or display rect were invalid.
        // Simulate the cancel button being clicked to inform the delegate.
        BrowserThread::PostTask(
            BrowserThread::IO, FROM_HERE, base::Bind(
                &SpeechRecognitionBubbleController::InvokeDelegateButtonClicked,
                this, SpeechRecognitionBubble::BUTTON_CANCEL));
        return;
      }
      bubble_->Show();
      bubble_->SetWarmUpMode();
      break;
    case REQUEST_SET_RECORDING_MODE:
      DCHECK(bubble_.get());
      bubble_->SetRecordingMode();
      break;
    case REQUEST_SET_RECOGNIZING_MODE:
      DCHECK(bubble_.get());
      bubble_->SetRecognizingMode();
      break;
    case REQUEST_SET_MESSAGE:
      DCHECK(bubble_.get());
      bubble_->SetMessage(request.message);
      break;
    case REQUEST_SET_INPUT_VOLUME:
      DCHECK(bubble_.get());
      bubble_->SetInputVolume(request.volume, request.noise_volume);
      break;
    case REQUEST_CLOSE:
      bubble_.reset();
      break;
    default:
      NOTREACHED();
      break;
  }
}

SpeechRecognitionBubbleController::UIRequest::UIRequest(RequestType type_value)
    : type(type_value),
      volume(0.0F),
      noise_volume(0.0F),
      render_process_id(0),
      render_view_id(0) {
}

SpeechRecognitionBubbleController::UIRequest::~UIRequest() {
}

}  // namespace speech
