// Copyright 2017 The Chromium OS 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 "midis/seq_handler.h"

#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include <base/bind.h>
#include <poll.h>

#include "media/midi/message_util.h"
#include "midis/constants.h"

namespace {

const unsigned int kCreateInputPortCaps =
    SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_NO_EXPORT;
const unsigned int kCreateOutputPortCaps =
    SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_NO_EXPORT;
const unsigned int kCreatePortType =
    SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION;
const char kSndSeqName[] = "hw";

}  // namespace

namespace midis {

SeqHandler::SeqHandler() : weak_factory_(this) {}

SeqHandler::SeqHandler(AddDeviceCallback add_device_cb,
                       RemoveDeviceCallback remove_device_cb,
                       HandleReceiveDataCallback handle_rx_data_cb,
                       IsDevicePresentCallback is_device_present_cb,
                       IsPortPresentCallback is_port_present_cb)
    : add_device_cb_(add_device_cb),
      remove_device_cb_(remove_device_cb),
      handle_rx_data_cb_(handle_rx_data_cb),
      is_device_present_cb_(is_device_present_cb),
      is_port_present_cb_(is_port_present_cb),
      weak_factory_(this) {}

bool SeqHandler::InitSeq() {
  // Create client handles.
  snd_seq_t* tmp_seq = nullptr;
  int err =
      snd_seq_open(&tmp_seq, kSndSeqName, SND_SEQ_OPEN_INPUT, SND_SEQ_NONBLOCK);
  if (err != 0) {
    LOG(ERROR) << "snd_seq_open fails: " << snd_strerror(err);
    return false;
  }
  ScopedSeqPtr in_client(tmp_seq);
  tmp_seq = nullptr;
  in_client_id_ = snd_seq_client_id(in_client.get());

  err = snd_seq_open(&tmp_seq, kSndSeqName, SND_SEQ_OPEN_OUTPUT, 0);
  if (err != 0) {
    LOG(ERROR) << "snd_seq_open fails: " << snd_strerror(err);
    return false;
  }

  ScopedSeqPtr out_client(tmp_seq);
  tmp_seq = nullptr;
  out_client_id_ = snd_seq_client_id(out_client.get());

  // Name the clients.
  err = snd_seq_set_client_name(in_client.get(), "midis (input)");
  if (err != 0) {
    LOG(ERROR) << "snd_seq_set_client_name fails: " << snd_strerror(err);
    return false;
  }
  err = snd_seq_set_client_name(out_client.get(), "midis (output)");
  if (err != 0) {
    LOG(ERROR) << "snd_seq_set_client_name fails: " << snd_strerror(err);
    return false;
  }

  // Create input port.
  in_port_id_ = snd_seq_create_simple_port(
      in_client.get(), NULL, kCreateInputPortCaps, kCreatePortType);
  if (in_port_id_ < 0) {
    LOG(ERROR) << "snd_seq_create_simple_port fails: "
               << snd_strerror(in_port_id_);
    return false;
  }

  // Subscribe to the announce port.
  snd_seq_port_subscribe_t* subs;
  snd_seq_port_subscribe_alloca(&subs);
  snd_seq_addr_t announce_sender;
  snd_seq_addr_t announce_dest;
  announce_sender.client = SND_SEQ_CLIENT_SYSTEM;
  announce_sender.port = SND_SEQ_PORT_SYSTEM_ANNOUNCE;
  announce_dest.client = in_client_id_;
  announce_dest.port = in_port_id_;
  snd_seq_port_subscribe_set_sender(subs, &announce_sender);
  snd_seq_port_subscribe_set_dest(subs, &announce_dest);
  err = snd_seq_subscribe_port(in_client.get(), subs);
  if (err != 0) {
    LOG(ERROR) << "snd_seq_subscribe_port on the announce port fails: "
               << snd_strerror(err);
    return false;
  }

  in_client_ = std::move(in_client);
  out_client_ = std::move(out_client);

  // Initialize decoder.
  decoder_ = CreateMidiEvent(0);

  EnumerateExistingDevices();

  // Obtain the poll file descriptor to watch.
  pfd_ = std::make_unique<pollfd>();
  snd_seq_poll_descriptors(in_client_.get(), pfd_.get(), 1, POLLIN);

  watcher_ = base::FileDescriptorWatcher::WatchReadable(
      pfd_->fd,
      base::BindRepeating(&SeqHandler::ProcessAlsaClientFd,
                          weak_factory_.GetWeakPtr()));
  if (!watcher_) {
    in_client_.reset();
    out_client_.reset();
    decoder_.reset();
    pfd_.reset();
    return false;
  }

  return true;
}

void SeqHandler::ProcessAlsaClientFd() {
  int remaining;
  do {
    snd_seq_event_t* event;
    int err = SndSeqEventInput(in_client_.get(), &event);
    remaining = SndSeqEventInputPending(in_client_.get(), 0);

    if (err == -ENOSPC) {
      // Handle out of space error.
      LOG(ERROR) << "snd_seq_event_input detected buffer overrun";
      // We've lost events: check another way to see if we need to shut
      // down.
    } else if (err == -EAGAIN) {
      // We've read all the data.
    } else if (err < 0) {
      // Handle other errors.
      LOG(ERROR) << "snd_seq_event_input fails: " << snd_strerror(err);
      // TODO(pmalani): Stop the message loop here then.
    } else if (event->source.client == SND_SEQ_CLIENT_SYSTEM &&
               event->source.port == SND_SEQ_PORT_SYSTEM_ANNOUNCE) {
      // Handle announce events.
      switch (event->type) {
        case SND_SEQ_EVENT_PORT_START:
          // Don't use SND_SEQ_EVENT_CLIENT_START because the
          // client name may not be set by the time we query
          // it. It should be set by the time ports are made.
          AddSeqDevice(event->data.addr.client);
          AddSeqPort(event->data.addr.client, event->data.addr.port);
          break;
        case SND_SEQ_EVENT_CLIENT_EXIT:
          // Check for disconnection of our "out" client. This means "shut
          // down".
          if (event->data.addr.client == out_client_id_) {
            // TODO(pmalani): Stop the message loop here then.
            remaining = 0;
          } else {
            RemoveSeqDevice(event->data.addr.client);
          }
          break;
        case SND_SEQ_EVENT_PORT_EXIT:
          RemoveSeqPort(event->data.addr.client, event->data.addr.port);
          break;
      }
    } else {
      // Normal operation.
      ProcessMidiEvent(event);
    }
  } while (remaining > 0);
}

void SeqHandler::AddSeqDevice(uint32_t device_id) {
  if (is_device_present_cb_.Run(0 /* TODO(pmalani): Remove card number */,
                                device_id)) {
    LOG(INFO) << "Device: " << device_id << " already exists.";
    return;
  }

  // Check that the device isn't our own in/our client.
  if (device_id == in_client_id_ || device_id == out_client_id_) {
    return;
  }

  snd_seq_client_info_t* client_info;
  snd_seq_client_info_alloca(&client_info);
  int err =
      snd_seq_get_any_client_info(in_client_.get(), device_id, client_info);
  if (err != 0) {
    LOG(ERROR) << "Failed to get client info.";
    return;
  }

  std::string name(snd_seq_client_info_get_name(client_info));

  // Store the list of MIDI ports and corresponding capabilities in a map.
  std::map<uint32_t, unsigned int> port_caps;
  snd_seq_port_info_t* port_info;
  snd_seq_port_info_alloca(&port_info);
  snd_seq_port_info_set_client(port_info, device_id);
  snd_seq_port_info_set_port(port_info, -1);
  while (!snd_seq_query_next_port(in_client_.get(), port_info)) {
    if (!(snd_seq_port_info_get_type(port_info) &
          SND_SEQ_PORT_TYPE_MIDI_GENERIC)) {
      LOG(INFO) << "Skipping non-MIDI port.";
      continue;
    }
    port_caps.emplace(snd_seq_port_info_get_port(port_info),
                      snd_seq_port_info_get_capability(port_info));
  }

  // If the number of MIDI ports is 0, there is no use in creating
  // a device.
  if (port_caps.size() == 0) {
    LOG(INFO) << "Connected device: " << name << " has no MIDI ports.";
    return;
  }

  auto dev = std::make_unique<Device>(
      name, std::string(),
      0 /* card number; TODO(pmalani) remove card number */, device_id,
      port_caps.size(), 0 /* device flags TODO(pmalani): flags not needed. */,
      base::Bind(&SeqHandler::SubscribeInPort, base::Unretained(this)),
      base::Bind(&SeqHandler::SubscribeOutPort, base::Unretained(this)),
      base::Bind(&SeqHandler::UnsubscribeInPort, weak_factory_.GetWeakPtr()),
      base::Bind(&SeqHandler::UnsubscribeOutPort, weak_factory_.GetWeakPtr()),
      base::Bind(&SeqHandler::SendMidiData, weak_factory_.GetWeakPtr()),
      std::move(port_caps));
  add_device_cb_.Run(std::move(dev));
}

void SeqHandler::AddSeqPort(uint32_t device_id, uint32_t port_id) {
  if (!is_port_present_cb_.Run(0, device_id, port_id)) {
    LOG(WARNING) << "Received port start event for new port: " << port_id
                 << " on  device: " << device_id << "; ignoring";
  }
}

void SeqHandler::RemoveSeqDevice(uint32_t device_id) {
  remove_device_cb_.Run(0 /* FIXME remove card number */, device_id);
}

void SeqHandler::RemoveSeqPort(uint32_t device_id, uint32_t port_id) {
  if (!is_port_present_cb_.Run(0, device_id, port_id)) {
    LOG(WARNING) << "Received port start event for new port: " << port_id
                 << " on  device: " << device_id << "; ignoring";
  }
}

bool SeqHandler::SubscribeInPort(uint32_t device_id, uint32_t port_id) {
  snd_seq_port_subscribe_t* subs;
  snd_seq_port_subscribe_alloca(&subs);
  snd_seq_addr_t sender;
  sender.client = device_id;
  sender.port = port_id;
  snd_seq_port_subscribe_set_sender(subs, &sender);

  snd_seq_addr_t dest;
  dest.client = in_client_id_;
  dest.port = in_port_id_;
  snd_seq_port_subscribe_set_dest(subs, &dest);

  int err = snd_seq_subscribe_port(in_client_.get(), subs);
  if (err != 0) {
    LOG(ERROR) << "snd_seq_subscribe_port fails: " << snd_strerror(err);
    return false;
  }

  return true;
}

int SeqHandler::SubscribeOutPort(uint32_t device_id, uint32_t port_id) {
  int out_port;
  out_port = snd_seq_create_simple_port(out_client_.get(), NULL,
                                        kCreateOutputPortCaps, kCreatePortType);
  if (out_port < 0) {
    LOG(INFO) << "snd_seq_creat_simple_port (output) failed: "
              << snd_strerror(out_port);
    return -1;
  }

  snd_seq_port_subscribe_t* subs;
  snd_seq_port_subscribe_alloca(&subs);
  snd_seq_addr_t sender;
  sender.client = out_client_id_;
  sender.port = out_port;
  snd_seq_port_subscribe_set_sender(subs, &sender);

  snd_seq_addr_t dest;
  dest.client = device_id;
  dest.port = port_id;
  snd_seq_port_subscribe_set_dest(subs, &dest);

  int err = snd_seq_subscribe_port(out_client_.get(), subs);
  if (err != 0) {
    snd_seq_delete_simple_port(out_client_.get(), out_port);
    LOG(ERROR) << "snd_seq_subscribe_port fails: " << snd_strerror(err);
    return -1;
  }

  return out_port;
}

void SeqHandler::UnsubscribeInPort(uint32_t device_id, uint32_t port_id) {
  snd_seq_port_subscribe_t* subs;
  snd_seq_port_subscribe_alloca(&subs);
  snd_seq_addr_t sender;
  sender.client = device_id;
  sender.port = port_id;
  snd_seq_port_subscribe_set_sender(subs, &sender);
  snd_seq_addr_t dest;
  dest.client = in_client_id_;
  dest.port = in_port_id_;
  snd_seq_port_subscribe_set_dest(subs, &dest);

  int err = snd_seq_unsubscribe_port(in_client_.get(), subs);
  if (err != 0) {
    LOG(WARNING) << "snd_seq_unsubscribe_port fails: " << snd_strerror(err);
    return;
  }
}

void SeqHandler::UnsubscribeOutPort(int out_port_id) {
  snd_seq_delete_simple_port(out_client_.get(), out_port_id);
}

bool SeqHandler::EncodeMidiBytes(int out_port_id,
                                 snd_seq_t* out_client,
                                 const uint8_t* buffer,
                                 size_t buf_len,
                                 snd_midi_event_t* encoder) {
  if (buf_len == 0 || buf_len > kMaxBufSize) {
    return false;
  }

  for (int i = 0; i < buf_len; i++) {
    snd_seq_event_t event;
    int result = snd_midi_event_encode_byte(encoder, buffer[i], &event);
    if (result < 0) {
      LOG(ERROR) << "Error snd_midi_event_encode_byte(): " << result;
      return false;
    }
    if (result == 1) {
      // Send the message.
      snd_seq_ev_set_source(&event, out_port_id);
      snd_seq_ev_set_subs(&event);
      snd_seq_ev_set_direct(&event);
      int expected_length = snd_seq_event_length(&event);
      result = SndSeqEventOutputDirect(out_client, &event);
      if (result != expected_length) {
        LOG(WARNING) << "Error in snd_seq_event_output_direct(): " << result;
        return false;
      }
      return true;
    }
  }

  // If we reached here, something went wrong.
  return false;
}

void SeqHandler::SendMidiData(int out_port_id,
                              const uint8_t* buffer,
                              size_t buf_len) {
  std::vector<uint8_t> v(buffer, buffer + buf_len);
  if (!midi::IsValidWebMIDIData(v)) {
    LOG(WARNING) << "Received invalid MIDI Data.";
    return;
  }

  snd_midi_event_t* encoder;
  int ret = snd_midi_event_new(buf_len, &encoder);
  if (ret != 0) {
    LOG(ERROR) << "Error snd_midi_event_new(): " << ret;
    return;
  }
  bool success =
      EncodeMidiBytes(out_port_id, out_client_.get(), buffer, buf_len, encoder);
  if (!success) {
    LOG(WARNING) << "Failed to send MIDI data to output port: " << out_port_id;
  }
  snd_midi_event_free(encoder);
}

void SeqHandler::ProcessMidiEvent(snd_seq_event_t* event) {
  uint32_t device_id = event->source.client;
  uint32_t subdevice_num = event->source.port;

  if (event->type == SND_SEQ_EVENT_SYSEX) {
    // SysEX, so pass it through without decoding.
    handle_rx_data_cb_.Run(0, device_id, subdevice_num,
                           static_cast<char*>(event->data.ext.ptr),
                           event->data.ext.len);
  } else {
    // Normal message, so decode and send.
    unsigned char buf[12];
    int64_t count =
        snd_midi_event_decode(decoder_.get(), buf, sizeof(buf), event);
    if (count <= 0) {
      if (count != -ENOENT) {
        LOG(ERROR) << "snd_midi_event_decoder failed: " << snd_strerror(count);
      }
    } else {
      handle_rx_data_cb_.Run(0, device_id, subdevice_num,
                             reinterpret_cast<char*>(buf), count);
    }
  }
}

int SeqHandler::SndSeqEventOutputDirect(snd_seq_t* out_client,
                                        snd_seq_event_t* event) {
  return snd_seq_event_output_direct(out_client, event);
}

int SeqHandler::SndSeqEventInput(snd_seq_t* in_client, snd_seq_event_t** ev) {
  return snd_seq_event_input(in_client, ev);
}

int SeqHandler::SndSeqEventInputPending(snd_seq_t* in_client,
                                        int fetch_sequencer) {
  return snd_seq_event_input_pending(in_client, fetch_sequencer);
}

void SeqHandler::EnumerateExistingDevices() {
  snd_seq_client_info_t* client_info;
  snd_seq_client_info_alloca(&client_info);
  snd_seq_port_info_t* port_info;
  snd_seq_port_info_alloca(&port_info);

  snd_seq_client_info_set_client(client_info, -1);
  while (!snd_seq_query_next_client(in_client_.get(), client_info)) {
    int device_id = snd_seq_client_info_get_client(client_info);
    AddSeqDevice(device_id);

    // Call AddSeqPort to make sure we "process" all the ports of a client.
    // Note that currently we don't support the dynamic addition / deletion
    // of ports.
    snd_seq_port_info_set_client(port_info, device_id);
    snd_seq_port_info_set_port(port_info, -1);
    while (!snd_seq_query_next_port(in_client_.get(), port_info)) {
      int port_id = snd_seq_port_info_get_port(port_info);
      AddSeqPort(device_id, port_id);
    }
  }
}

SeqHandler::ScopedMidiEventPtr SeqHandler::CreateMidiEvent(size_t buf_size) {
  snd_midi_event_t* tmp = nullptr;
  snd_midi_event_new(buf_size, &tmp);
  ScopedMidiEventPtr ev(tmp);
  tmp = nullptr;
  snd_midi_event_no_status(ev.get(), 1);

  return ev;
}

}  // namespace midis
