// 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 <base/logging.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
