/*
 *  Copyright (c) 2011 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 "webrtc/voice_engine/channel_manager.h"

#include "webrtc/common.h"
#include "webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory.h"
#include "webrtc/voice_engine/channel.h"

namespace webrtc {
namespace voe {

ChannelOwner::ChannelOwner(class Channel* channel)
    : channel_ref_(new ChannelRef(channel)) {}

ChannelOwner::ChannelOwner(const ChannelOwner& channel_owner)
    : channel_ref_(channel_owner.channel_ref_) {
  ++channel_ref_->ref_count;
}

ChannelOwner::~ChannelOwner() {
  if (--channel_ref_->ref_count == 0)
    delete channel_ref_;
}

ChannelOwner& ChannelOwner::operator=(const ChannelOwner& other) {
  if (other.channel_ref_ == channel_ref_)
    return *this;

  if (--channel_ref_->ref_count == 0)
    delete channel_ref_;

  channel_ref_ = other.channel_ref_;
  ++channel_ref_->ref_count;

  return *this;
}

ChannelOwner::ChannelRef::ChannelRef(class Channel* channel)
    : channel(channel), ref_count(1) {}

ChannelManager::ChannelManager(uint32_t instance_id, const Config& config)
    : instance_id_(instance_id), last_channel_id_(-1), config_(config) {}

ChannelOwner ChannelManager::CreateChannel() {
  return CreateChannel(CreateBuiltinAudioDecoderFactory());
}

ChannelOwner ChannelManager::CreateChannel(const Config& external_config) {
  return CreateChannel(external_config, CreateBuiltinAudioDecoderFactory());
}

ChannelOwner ChannelManager::CreateChannel(
    const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory) {
  return CreateChannelInternal(config_, decoder_factory);
}

ChannelOwner ChannelManager::CreateChannel(
    const Config& external_config,
    const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory) {
  return CreateChannelInternal(external_config, decoder_factory);
}

ChannelOwner ChannelManager::CreateChannelInternal(
    const Config& config,
    const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory) {
  Channel* channel;
  Channel::CreateChannel(channel, ++last_channel_id_, instance_id_, config,
                         decoder_factory);
  ChannelOwner channel_owner(channel);

  rtc::CritScope crit(&lock_);

  channels_.push_back(channel_owner);

  return channel_owner;
}

ChannelOwner ChannelManager::GetChannel(int32_t channel_id) {
  rtc::CritScope crit(&lock_);

  for (size_t i = 0; i < channels_.size(); ++i) {
    if (channels_[i].channel()->ChannelId() == channel_id)
      return channels_[i];
  }
  return ChannelOwner(NULL);
}

void ChannelManager::GetAllChannels(std::vector<ChannelOwner>* channels) {
  rtc::CritScope crit(&lock_);

  *channels = channels_;
}

void ChannelManager::DestroyChannel(int32_t channel_id) {
  assert(channel_id >= 0);
  // Holds a reference to a channel, this is used so that we never delete
  // Channels while holding a lock, but rather when the method returns.
  ChannelOwner reference(NULL);
  {
    rtc::CritScope crit(&lock_);
    std::vector<ChannelOwner>::iterator to_delete = channels_.end();
    for (auto it = channels_.begin(); it != channels_.end(); ++it) {
      Channel* channel = it->channel();
      // For channels associated with the channel to be deleted, disassociate
      // with that channel.
      channel->DisassociateSendChannel(channel_id);

      if (channel->ChannelId() == channel_id) {
        to_delete = it;
      }
    }
    if (to_delete != channels_.end()) {
      reference = *to_delete;
      channels_.erase(to_delete);
    }
  }
}

void ChannelManager::DestroyAllChannels() {
  // Holds references so that Channels are not destroyed while holding this
  // lock, but rather when the method returns.
  std::vector<ChannelOwner> references;
  {
    rtc::CritScope crit(&lock_);
    references = channels_;
    channels_.clear();
  }
}

size_t ChannelManager::NumOfChannels() const {
  rtc::CritScope crit(&lock_);
  return channels_.size();
}

ChannelManager::Iterator::Iterator(ChannelManager* channel_manager)
    : iterator_pos_(0) {
  channel_manager->GetAllChannels(&channels_);
}

Channel* ChannelManager::Iterator::GetChannel() {
  if (iterator_pos_ < channels_.size())
    return channels_[iterator_pos_].channel();
  return NULL;
}

bool ChannelManager::Iterator::IsValid() {
  return iterator_pos_ < channels_.size();
}

void ChannelManager::Iterator::Increment() {
  ++iterator_pos_;
}

}  // namespace voe
}  // namespace webrtc
