/*
 *  Copyright 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "pc/dtmf_sender.h"

#include <ctype.h>
#include <string.h>

#include <string>

#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/ref_counted_object.h"
#include "rtc_base/task_utils/to_queued_task.h"
#include "rtc_base/thread.h"

namespace webrtc {

// RFC4733
//  +-------+--------+------+---------+
//  | Event | Code   | Type | Volume? |
//  +-------+--------+------+---------+
//  | 0--9  | 0--9   | tone | yes     |
//  | *     | 10     | tone | yes     |
//  | #     | 11     | tone | yes     |
//  | A--D  | 12--15 | tone | yes     |
//  +-------+--------+------+---------+
// The "," is a special event defined by the WebRTC spec. It means to delay for
// 2 seconds before processing the next tone. We use -1 as its code.
static const int kDtmfCommaDelay = -1;
static const char kDtmfValidTones[] = ",0123456789*#ABCDabcd";
static const char kDtmfTonesTable[] = ",0123456789*#ABCD";
// The duration cannot be more than 6000ms or less than 40ms. The gap between
// tones must be at least 50 ms.
// Source for values: W3C WEBRTC specification.
// https://w3c.github.io/webrtc-pc/#dom-rtcdtmfsender-insertdtmf
static const int kDtmfDefaultDurationMs = 100;
static const int kDtmfMinDurationMs = 40;
static const int kDtmfMaxDurationMs = 6000;
static const int kDtmfDefaultGapMs = 50;
static const int kDtmfMinGapMs = 30;

// Get DTMF code from the DTMF event character.
bool GetDtmfCode(char tone, int* code) {
  // Convert a-d to A-D.
  char event = toupper(tone);
  const char* p = strchr(kDtmfTonesTable, event);
  if (!p) {
    return false;
  }
  *code = p - kDtmfTonesTable - 1;
  return true;
}

rtc::scoped_refptr<DtmfSender> DtmfSender::Create(
    rtc::Thread* signaling_thread,
    DtmfProviderInterface* provider) {
  if (!signaling_thread) {
    return nullptr;
  }
  return rtc::make_ref_counted<DtmfSender>(signaling_thread, provider);
}

DtmfSender::DtmfSender(rtc::Thread* signaling_thread,
                       DtmfProviderInterface* provider)
    : observer_(nullptr),
      signaling_thread_(signaling_thread),
      provider_(provider),
      duration_(kDtmfDefaultDurationMs),
      inter_tone_gap_(kDtmfDefaultGapMs),
      comma_delay_(kDtmfDefaultCommaDelayMs) {
  RTC_DCHECK(signaling_thread_);
  if (provider_) {
    RTC_DCHECK(provider_->GetOnDestroyedSignal());
    provider_->GetOnDestroyedSignal()->connect(
        this, &DtmfSender::OnProviderDestroyed);
  }
}

DtmfSender::~DtmfSender() {
  RTC_DCHECK_RUN_ON(signaling_thread_);
  StopSending();
}

void DtmfSender::RegisterObserver(DtmfSenderObserverInterface* observer) {
  RTC_DCHECK_RUN_ON(signaling_thread_);
  observer_ = observer;
}

void DtmfSender::UnregisterObserver() {
  RTC_DCHECK_RUN_ON(signaling_thread_);
  observer_ = nullptr;
}

bool DtmfSender::CanInsertDtmf() {
  RTC_DCHECK_RUN_ON(signaling_thread_);
  if (!provider_) {
    return false;
  }
  return provider_->CanInsertDtmf();
}

bool DtmfSender::InsertDtmf(const std::string& tones,
                            int duration,
                            int inter_tone_gap,
                            int comma_delay) {
  RTC_DCHECK_RUN_ON(signaling_thread_);

  if (duration > kDtmfMaxDurationMs || duration < kDtmfMinDurationMs ||
      inter_tone_gap < kDtmfMinGapMs || comma_delay < kDtmfMinGapMs) {
    RTC_LOG(LS_ERROR)
        << "InsertDtmf is called with invalid duration or tones gap. "
           "The duration cannot be more than "
        << kDtmfMaxDurationMs << "ms or less than " << kDtmfMinDurationMs
        << "ms. The gap between tones must be at least " << kDtmfMinGapMs
        << "ms.";
    return false;
  }

  if (!CanInsertDtmf()) {
    RTC_LOG(LS_ERROR)
        << "InsertDtmf is called on DtmfSender that can't send DTMF.";
    return false;
  }

  tones_ = tones;
  duration_ = duration;
  inter_tone_gap_ = inter_tone_gap;
  comma_delay_ = comma_delay;

  // Cancel any remaining tasks for previous tones.
  if (safety_flag_) {
    safety_flag_->SetNotAlive();
  }
  safety_flag_ = PendingTaskSafetyFlag::Create();
  // Kick off a new DTMF task.
  QueueInsertDtmf(RTC_FROM_HERE, 1 /*ms*/);
  return true;
}

std::string DtmfSender::tones() const {
  RTC_DCHECK_RUN_ON(signaling_thread_);
  return tones_;
}

int DtmfSender::duration() const {
  RTC_DCHECK_RUN_ON(signaling_thread_);
  return duration_;
}

int DtmfSender::inter_tone_gap() const {
  RTC_DCHECK_RUN_ON(signaling_thread_);
  return inter_tone_gap_;
}

int DtmfSender::comma_delay() const {
  RTC_DCHECK_RUN_ON(signaling_thread_);
  return comma_delay_;
}

void DtmfSender::QueueInsertDtmf(const rtc::Location& posted_from,
                                 uint32_t delay_ms) {
  signaling_thread_->PostDelayedTask(
      ToQueuedTask(safety_flag_,
                   [this] {
                     RTC_DCHECK_RUN_ON(signaling_thread_);
                     DoInsertDtmf();
                   }),
      delay_ms);
}

void DtmfSender::DoInsertDtmf() {
  // Get the first DTMF tone from the tone buffer. Unrecognized characters will
  // be ignored and skipped.
  size_t first_tone_pos = tones_.find_first_of(kDtmfValidTones);
  int code = 0;
  if (first_tone_pos == std::string::npos) {
    tones_.clear();
    // Fire a “OnToneChange” event with an empty string and stop.
    if (observer_) {
      observer_->OnToneChange(std::string(), tones_);
      observer_->OnToneChange(std::string());
    }
    return;
  } else {
    char tone = tones_[first_tone_pos];
    if (!GetDtmfCode(tone, &code)) {
      // The find_first_of(kDtmfValidTones) should have guarantee |tone| is
      // a valid DTMF tone.
      RTC_NOTREACHED();
    }
  }

  int tone_gap = inter_tone_gap_;
  if (code == kDtmfCommaDelay) {
    // Special case defined by WebRTC - By default, the character ',' indicates
    // a delay of 2 seconds before processing the next character in the tones
    // parameter. The comma delay can be set to a non default value via
    // InsertDtmf to comply with legacy WebRTC clients.
    tone_gap = comma_delay_;
  } else {
    if (!provider_) {
      RTC_LOG(LS_ERROR) << "The DtmfProvider has been destroyed.";
      return;
    }
    // The provider starts playout of the given tone on the
    // associated RTP media stream, using the appropriate codec.
    if (!provider_->InsertDtmf(code, duration_)) {
      RTC_LOG(LS_ERROR) << "The DtmfProvider can no longer send DTMF.";
      return;
    }
    // Wait for the number of milliseconds specified by |duration_|.
    tone_gap += duration_;
  }

  // Fire a “OnToneChange” event with the tone that's just processed.
  if (observer_) {
    observer_->OnToneChange(tones_.substr(first_tone_pos, 1),
                            tones_.substr(first_tone_pos + 1));
    observer_->OnToneChange(tones_.substr(first_tone_pos, 1));
  }

  // Erase the unrecognized characters plus the tone that's just processed.
  tones_.erase(0, first_tone_pos + 1);

  // Continue with the next tone.
  QueueInsertDtmf(RTC_FROM_HERE, tone_gap);
}

void DtmfSender::OnProviderDestroyed() {
  RTC_DCHECK_RUN_ON(signaling_thread_);

  RTC_LOG(LS_INFO) << "The Dtmf provider is deleted. Clear the sending queue.";
  StopSending();
  provider_ = nullptr;
}

void DtmfSender::StopSending() {
  if (safety_flag_) {
    safety_flag_->SetNotAlive();
  }
}

}  // namespace webrtc
