/* Blinker
   Copyright 2011-2019 Stefan Schuermans <stefan@blinkenarea.org>
   Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html
   a blinkenarea.org project */

#include <set>

#include <BlinkenLib/BlinkenFrame.h>

#include "Stream.h"
#include "StreamRecv.h"

namespace Blinker {

/// constructor
Stream::Stream():
  m_pFrame(NULL)
{
}

/// destructor
Stream::~Stream()
{
  // free current frame
  if (m_pFrame)
    BlinkenFrameFree(m_pFrame);
}

/**
 * @brief attach a stream receiver
 * @param[in] recv stream receiver to attach
 */
void Stream::attach(StreamRecv *recv)
{
  m_recvs.insert(recv);

  // send current frame to receiver
  recv->setFrame(m_name, m_pFrame);
}

/**
 * @brief detach a stream receiver
 * @param[in] recv stream receiver to detach
 */
void Stream::detach(StreamRecv *recv)
{
  m_recvs.erase(recv);
}

/**
 * @brief set current frame
 * @param[in] pFrame current frame (NULL for none)
 */
void Stream::setFrame(stBlinkenFrame *pFrame)
{
  // leave if frame is already set to an identical one
  if (pFrame && m_pFrame && !BlinkenFrameCompare(pFrame, m_pFrame))
    return;
  if (!pFrame && !m_pFrame)
    return;

  // update local copy of current frame
  if (m_pFrame) {
    BlinkenFrameFree(m_pFrame);
    m_pFrame = NULL;
  }
  if (pFrame) {
    m_pFrame = BlinkenFrameClone(pFrame);
    // in case of NULL returned: out of memory - go on without frame
  }

  // pass frame to all receivers
  Recvs::iterator it;
  for (it = m_recvs.begin(); it != m_recvs.end(); ++it)
    (*it)->setFrame(m_name, m_pFrame);
}

/**
 * @brief get current frame
 * @return current frame (NULL for none)
 */
stBlinkenFrame * Stream::getCurFrame() const
{
  return m_pFrame;
}

} // namespace Blinker

