// Copyright 2014 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_usb.h"

#include <memory>
#include <utility>

#include "base/bind.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "media/midi/midi_service.h"
#include "media/midi/task_service.h"
#include "media/midi/usb_midi_descriptor_parser.h"

namespace midi {

using mojom::PortState;
using mojom::Result;

MidiManagerUsb::MidiManagerUsb(MidiService* service,
                               std::unique_ptr<UsbMidiDevice::Factory> factory)
    : MidiManager(service), device_factory_(std::move(factory)) {}

MidiManagerUsb::~MidiManagerUsb() {
  if (!service()->task_service()->UnbindInstance())
    return;

  // Finalization steps should be implemented after the UnbindInstance() call
  // above, if we need.
}

void MidiManagerUsb::StartInitialization() {
  if (!service()->task_service()->BindInstance())
    return CompleteInitialization(Result::INITIALIZATION_ERROR);

  Initialize();
}

void MidiManagerUsb::Initialize() {
  // This is safe because EnumerateDevices cancels the operation on destruction.
  device_factory_->EnumerateDevices(
      this, base::BindOnce(&MidiManagerUsb::OnEnumerateDevicesDone,
                           base::Unretained(this)));
}

void MidiManagerUsb::DispatchSendMidiData(MidiManagerClient* client,
                                          uint32_t port_index,
                                          const std::vector<uint8_t>& data,
                                          base::TimeTicks timestamp) {
  if (port_index >= output_streams_.size()) {
    // |port_index| is provided by a renderer so we can't believe that it is
    // in the valid range.
    return;
  }
  base::TimeDelta delay = MidiService::TimestampToTimeDeltaDelay(timestamp);

  // output_streams_[port_index] is alive unless MidiManagerUsb is deleted.
  service()->task_service()->PostBoundDelayedTask(
      TaskService::kDefaultRunnerId,
      base::BindOnce(&UsbMidiOutputStream::Send,
                     base::Unretained(output_streams_[port_index].get()), data),
      delay);
  service()->task_service()->PostBoundDelayedTask(
      TaskService::kDefaultRunnerId,
      base::BindOnce(&MidiManager::AccumulateMidiBytesSent,
                     base::Unretained(this), client, data.size()),
      delay);
}

void MidiManagerUsb::ReceiveUsbMidiData(UsbMidiDevice* device,
                                        int endpoint_number,
                                        const uint8_t* data,
                                        size_t size,
                                        base::TimeTicks time) {
  if (!input_stream_)
    return;
  input_stream_->OnReceivedData(device,
                                endpoint_number,
                                data,
                                size,
                                time);
}

void MidiManagerUsb::OnDeviceAttached(std::unique_ptr<UsbMidiDevice> device) {
  int device_id = static_cast<int>(devices_.size());
  devices_.push_back(std::move(device));
  AddPorts(devices_.back().get(), device_id);
}

void MidiManagerUsb::OnDeviceDetached(size_t index) {
  if (index >= devices_.size()) {
    return;
  }
  UsbMidiDevice* device = devices_[index].get();
  for (size_t i = 0; i < output_streams_.size(); ++i) {
    if (output_streams_[i]->jack().device == device) {
      SetOutputPortState(static_cast<uint32_t>(i), PortState::DISCONNECTED);
    }
  }
  const std::vector<UsbMidiJack>& input_jacks = input_stream_->jacks();
  for (size_t i = 0; i < input_jacks.size(); ++i) {
    if (input_jacks[i].device == device) {
      SetInputPortState(static_cast<uint32_t>(i), PortState::DISCONNECTED);
    }
  }
}

void MidiManagerUsb::OnReceivedData(size_t jack_index,
                                    const uint8_t* data,
                                    size_t size,
                                    base::TimeTicks time) {
  ReceiveMidiData(static_cast<uint32_t>(jack_index), data, size, time);
}


void MidiManagerUsb::OnEnumerateDevicesDone(bool result,
                                            UsbMidiDevice::Devices* devices) {
  if (result) {
    input_stream_.reset(new UsbMidiInputStream(this));
    devices->swap(devices_);
    for (size_t i = 0; i < devices_.size(); ++i) {
      if (!AddPorts(devices_[i].get(), static_cast<int>(i))) {
        result = false;
        break;
      }
    }
  }
  service()->task_service()->PostBoundTask(
      TaskService::kDefaultRunnerId,
      base::BindOnce(&MidiManager::CompleteInitialization,
                     base::Unretained(this),
                     result ? Result::OK : Result::INITIALIZATION_ERROR));
}

bool MidiManagerUsb::AddPorts(UsbMidiDevice* device, int device_id) {
  UsbMidiDescriptorParser parser;
  std::vector<uint8_t> descriptor = device->GetDescriptors();
  const uint8_t* data = descriptor.size() > 0 ? &descriptor[0] : NULL;
  std::vector<UsbMidiJack> jacks;
  bool parse_result = parser.Parse(device,
                                   data,
                                   descriptor.size(),
                                   &jacks);
  if (!parse_result)
    return false;

  std::string manufacturer(device->GetManufacturer());
  std::string product_name(device->GetProductName());
  std::string version(device->GetDeviceVersion());

  for (size_t j = 0; j < jacks.size(); ++j) {
    // Port ID must be unique in a MIDI manager. This ID setting is
    // sufficiently unique although there is no user-friendly meaning.
    // TODO(yhirano): Use a hashed string as ID.
    std::string id(
        base::StringPrintf("usb:port-%d-%ld", device_id, static_cast<long>(j)));
    if (jacks[j].direction() == UsbMidiJack::DIRECTION_OUT) {
      output_streams_.push_back(
          std::make_unique<UsbMidiOutputStream>(jacks[j]));
      AddOutputPort(mojom::PortInfo(id, manufacturer, product_name, version,
                                    PortState::OPENED));
    } else {
      DCHECK_EQ(jacks[j].direction(), UsbMidiJack::DIRECTION_IN);
      input_stream_->Add(jacks[j]);
      AddInputPort(mojom::PortInfo(id, manufacturer, product_name, version,
                                   PortState::OPENED));
    }
  }
  return true;
}

}  // namespace midi
