#include "TrackLockProxy.h"

using namespace std;
using namespace track;
//--------------------------------------------------------------
/* Constructor */
TrackLockProxy::TrackLockProxy(std::mutex &mtx, const NotesView notes)
  : m_lock(mtx)
  , m_notes(notes)
{
}
//--------------------------------------------------------------
/* Access a note by index */
const Note &TrackLockProxy::operator[](const size_t index) const
{
  return m_notes[index];
}
//--------------------------------------------------------------
/* Get the active notes at a specific time with a lookahead window */
ActiveNotes TrackLockProxy::getActiveNotesAt(const Seconds currentTime, const Seconds lookaheadWindow) const
{
  ActiveNotes result;
  getActiveNotesAt(currentTime, lookaheadWindow, result);
  return result;
}
//--------------------------------------------------------------
/* Get the active notes at a specific time with a lookahead window */
void TrackLockProxy::getActiveNotesAt(const Seconds currentTime, const Seconds lookaheadWindow, ActiveNotes &outNotes) const
{
  // Clear the output buffers before filling them with active notes
  // without releasing the allocated memory
  outNotes.playing.clear();      // Clear the currently playing notes buffer
  outNotes.upcoming.clear();     // Clear the upcoming notes buffer

  const Seconds lookaheadEnd = currentTime + lookaheadWindow;

  for (const auto &note : m_notes)
  {
    // Extract the notes that are currently playing
    if (note.startTime <= currentTime && note.endTime > currentTime)
      outNotes.playing.push_back(note);

    // Extract the notes that are upcoming in the lookahead window
    if (note.startTime <= lookaheadEnd && note.endTime >= currentTime)
      outNotes.upcoming.push_back(note);

    // Early exit: Notes are sorted by startTime, so if we reach a note
    // that starts after the lookahead window, we can stop searching
    if (note.startTime > lookaheadEnd)
      break;
  }
}
//--------------------------------------------------------------
/* Get the duration of the track */
Seconds TrackLockProxy::getDuration() const
{
  if (empty())
    return Seconds(0);

  return m_notes.back().endTime;
}
//--------------------------------------------------------------
/* Get the span of notes */
NotesView TrackLockProxy::get() const noexcept
{
  return m_notes;
}
//--------------------------------------------------------------
/* Get the first iterator of the notes */
auto TrackLockProxy::begin() const noexcept
{
  return m_notes.begin();
}
//--------------------------------------------------------------
/* Get the end iterator of the notes */
auto TrackLockProxy::end() const noexcept
{
  return m_notes.end();
}
//--------------------------------------------------------------
/* Check if the notes span is empty */
bool TrackLockProxy::empty() const noexcept
{
  return m_notes.empty();
}
//--------------------------------------------------------------
/* Get the size of the notes span */
size_t TrackLockProxy::size() const noexcept
{
  return m_notes.size();
}
//--------------------------------------------------------------
