// Copyright (c) 2011 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/extensions/extension_tts_api.h"

#include "base/memory/singleton.h"
#include "base/string_number_conversions.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/speech_synthesis_library.h"

namespace util = extension_tts_api_util;

using base::DoubleToString;

namespace {
const char kCrosLibraryNotLoadedError[] = "Cros shared library not loaded.";
};

class ExtensionTtsPlatformImplChromeOs : public ExtensionTtsPlatformImpl {
 public:
  virtual bool Speak(
      const std::string& utterance,
      const std::string& locale,
      const std::string& gender,
      double rate,
      double pitch,
      double volume);

  virtual bool StopSpeaking();

  virtual bool IsSpeaking();

  // Get the single instance of this class.
  static ExtensionTtsPlatformImplChromeOs* GetInstance();

 private:
  ExtensionTtsPlatformImplChromeOs() {}
  virtual ~ExtensionTtsPlatformImplChromeOs() {}

  void AppendSpeakOption(std::string key,
                         std::string value,
                         std::string* options);

  friend struct DefaultSingletonTraits<ExtensionTtsPlatformImplChromeOs>;

  DISALLOW_COPY_AND_ASSIGN(ExtensionTtsPlatformImplChromeOs);
};

// static
ExtensionTtsPlatformImpl* ExtensionTtsPlatformImpl::GetInstance() {
  return ExtensionTtsPlatformImplChromeOs::GetInstance();
}

bool ExtensionTtsPlatformImplChromeOs::Speak(
    const std::string& utterance,
    const std::string& locale,
    const std::string& gender,
    double rate,
    double pitch,
    double volume) {
  chromeos::CrosLibrary* cros_library = chromeos::CrosLibrary::Get();
  if (!cros_library->EnsureLoaded()) {
    set_error(kCrosLibraryNotLoadedError);
    return false;
  }

  std::string options;

  if (!locale.empty()) {
    AppendSpeakOption(
        chromeos::SpeechSynthesisLibrary::kSpeechPropertyLocale,
        locale,
        &options);
  }

  if (!gender.empty()) {
    AppendSpeakOption(
        chromeos::SpeechSynthesisLibrary::kSpeechPropertyGender,
        gender,
        &options);
  }

  if (rate >= 0.0) {
    AppendSpeakOption(
        chromeos::SpeechSynthesisLibrary::kSpeechPropertyRate,
        DoubleToString(rate * 5),
        &options);
  }

  if (pitch >= 0.0) {
    // The TTS service allows a range of 0 to 2 for speech pitch.
    AppendSpeakOption(
        chromeos::SpeechSynthesisLibrary::kSpeechPropertyPitch,
        DoubleToString(pitch * 2),
        &options);
  }

  if (volume >= 0.0) {
    // The TTS service allows a range of 0 to 5 for speech volume.
    AppendSpeakOption(
        chromeos::SpeechSynthesisLibrary::kSpeechPropertyVolume,
        DoubleToString(volume * 5),
        &options);
  }

  if (!options.empty()) {
    cros_library->GetSpeechSynthesisLibrary()->SetSpeakProperties(
        options.c_str());
  }

  return cros_library->GetSpeechSynthesisLibrary()->Speak(utterance.c_str());
}

bool ExtensionTtsPlatformImplChromeOs::StopSpeaking() {
  if (chromeos::CrosLibrary::Get()->EnsureLoaded()) {
    return chromeos::CrosLibrary::Get()->GetSpeechSynthesisLibrary()->
        StopSpeaking();
  }

  set_error(kCrosLibraryNotLoadedError);
  return false;
}

bool ExtensionTtsPlatformImplChromeOs::IsSpeaking() {
  if (chromeos::CrosLibrary::Get()->EnsureLoaded()) {
    return chromeos::CrosLibrary::Get()->GetSpeechSynthesisLibrary()->
        IsSpeaking();
  }

  set_error(kCrosLibraryNotLoadedError);
  return false;
}

void ExtensionTtsPlatformImplChromeOs::AppendSpeakOption(
    std::string key,
    std::string value,
    std::string* options) {
  *options +=
      key +
      chromeos::SpeechSynthesisLibrary::kSpeechPropertyEquals +
      value +
      chromeos::SpeechSynthesisLibrary::kSpeechPropertyDelimiter;
}

// static
ExtensionTtsPlatformImplChromeOs*
ExtensionTtsPlatformImplChromeOs::GetInstance() {
  return Singleton<ExtensionTtsPlatformImplChromeOs>::get();
}