// Copyright (c) 2013 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 "media/midi/midi_manager.h"

#include "base/bind.h"
#include "base/debug/trace_event.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_loop_proxy.h"

namespace media {

MidiManager::MidiManager()
    : initialized_(false),
      result_(MIDI_NOT_SUPPORTED) {
}

MidiManager::~MidiManager() {
}

#if !defined(OS_MACOSX) && !defined(OS_WIN) && !defined(USE_ALSA) && \
    !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
MidiManager* MidiManager::Create() {
  return new MidiManager;
}
#endif

void MidiManager::StartSession(MidiManagerClient* client) {
  bool session_is_ready;
  bool session_needs_initialization = false;
  bool too_many_pending_clients_exist = false;

  {
    base::AutoLock auto_lock(lock_);
    session_is_ready = initialized_;
    if (clients_.find(client) != clients_.end() ||
        pending_clients_.find(client) != pending_clients_.end()) {
      // Should not happen. But just in case the renderer is compromised.
      NOTREACHED();
      return;
    }
    if (!session_is_ready) {
      // Do not accept a new request if the pending client list contains too
      // many clients.
      too_many_pending_clients_exist =
          pending_clients_.size() >= kMaxPendingClientCount;

      if (!too_many_pending_clients_exist) {
        // Call StartInitialization() only for the first request.
        session_needs_initialization = pending_clients_.empty();
        pending_clients_.insert(client);
      }
    }
  }

  // Lazily initialize the MIDI back-end.
  if (!session_is_ready) {
    if (session_needs_initialization) {
      TRACE_EVENT0("midi", "MidiManager::StartInitialization");
      session_thread_runner_ =
          base::MessageLoop::current()->message_loop_proxy();
      StartInitialization();
    }
    if (too_many_pending_clients_exist) {
      // Return an error immediately if there are too many requests.
      client->CompleteStartSession(MIDI_INITIALIZATION_ERROR);
      return;
    }
    // CompleteInitialization() will be called asynchronously when platform
    // dependent initialization is finished.
    return;
  }

  // Platform dependent initialization was already finished for previously
  // initialized clients.
  MidiResult result;
  {
    base::AutoLock auto_lock(lock_);
    if (result_ == MIDI_OK) {
      AddInitialPorts(client);
      clients_.insert(client);
    }
    result = result_;
  }
  client->CompleteStartSession(result);
}

void MidiManager::EndSession(MidiManagerClient* client) {
  // At this point, |client| can be in the destruction process, and calling
  // any method of |client| is dangerous.
  base::AutoLock auto_lock(lock_);
  clients_.erase(client);
  pending_clients_.erase(client);
}

void MidiManager::DispatchSendMidiData(MidiManagerClient* client,
                                       uint32 port_index,
                                       const std::vector<uint8>& data,
                                       double timestamp) {
  NOTREACHED();
}

void MidiManager::StartInitialization() {
  CompleteInitialization(MIDI_NOT_SUPPORTED);
}

void MidiManager::CompleteInitialization(MidiResult result) {
  DCHECK(session_thread_runner_.get());
  // It is safe to post a task to the IO thread from here because the IO thread
  // should have stopped if the MidiManager is going to be destructed.
  session_thread_runner_->PostTask(
      FROM_HERE,
      base::Bind(&MidiManager::CompleteInitializationInternal,
                 base::Unretained(this),
                 result));
}

void MidiManager::AddInputPort(const MidiPortInfo& info) {
  base::AutoLock auto_lock(lock_);
  input_ports_.push_back(info);
  for (auto client : clients_)
    client->AddInputPort(info);
}

void MidiManager::AddOutputPort(const MidiPortInfo& info) {
  base::AutoLock auto_lock(lock_);
  output_ports_.push_back(info);
  for (auto client : clients_)
    client->AddOutputPort(info);
}

void MidiManager::ReceiveMidiData(
    uint32 port_index,
    const uint8* data,
    size_t length,
    double timestamp) {
  base::AutoLock auto_lock(lock_);

  for (auto client : clients_)
    client->ReceiveMidiData(port_index, data, length, timestamp);
}

void MidiManager::CompleteInitializationInternal(MidiResult result) {
  TRACE_EVENT0("midi", "MidiManager::CompleteInitialization");

  base::AutoLock auto_lock(lock_);
  DCHECK(clients_.empty());
  DCHECK(!initialized_);
  initialized_ = true;
  result_ = result;

  for (auto client : pending_clients_) {
    if (result_ == MIDI_OK) {
      AddInitialPorts(client);
      clients_.insert(client);
    }
    client->CompleteStartSession(result_);
  }
  pending_clients_.clear();
}

void MidiManager::AddInitialPorts(MidiManagerClient* client) {
  lock_.AssertAcquired();

  for (const auto& info : input_ports_)
    client->AddInputPort(info);
  for (const auto& info : output_ports_)
    client->AddOutputPort(info);
}

}  // namespace media
