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

#ifndef BLINKER_RECEIVER_H
#define BLINKER_RECEIVER_H

#include <string>

#include <BlinkenLib/BlinkenProto.h>
#include <BlinkenLib/BlinkenFrame.h>

#include "Directory.h"
#include "File.h"
#include "IoCallee.h"
#include "Mgrs.h"
#include "Module.h"
#include "OutStreamFile.h"
#include "Protocol.h"
#include "ProtocolFile.h"
#include "SettingFile.h"
#include "Time.h"
#include "TimeCallee.h"

namespace Blinker {

/// stream receiver
template<typename ADDR, typename SOCK>
class Receiver: public IoCallee, public Module, public TimeCallee
{
protected:
  /// type for address setting file
  typedef SettingFile<ADDR> AddrFile;

public:
  /**
   * @brief constructor
   * @param[in] name module name
   * @param[in] mgrs managers
   * @param[in] dirBase base directory
   */
  Receiver(const std::string &name, Mgrs &mgrs, const Directory &dirBase);

  /// virtual destructor
  virtual ~Receiver();

private:
  /// copy constructor disabled
  Receiver(const Receiver &that);

  /// assignment operator disabled
  const Receiver & operator=(const Receiver &that);

public:
  /// check for update of configuration
  virtual void updateConfig();

  /// callback when requested time reached
  virtual void timeCall();

  /**
   * @brief callback when I/O object is readable
   * @param[in] io I/O object that is readable
   */
  virtual void ioReadCall(Io *io);

  /**
   * @brief callback when I/O object is writable
   * @param[in] io I/O object that is writable
   */
  virtual void ioWriteCall(Io *io);

protected:
  /// (re-)read protocol
  void readProto();

  /// (re-)read source address
  void readSrc();

  /// create socket and bind it
  void createSock();

  /// destroy socket
  void destroySock();

  /**
   * @brief request stream / cancel stream request
   * @param req if to send a request (otherwise: cancel request)
   */
  void request(bool req);

  /// receive data from socket
  void receiveFromSock();

  /**
   * @brief process frame
   * @param[in] data received frame protocol data
   */
  void procFrame(const std::string &data);

  /// update time callback
  void updateTimeCallback();

protected:
  OutStreamFile m_fileOutStream; ///< output stream name file
  AddrFile      m_fileBind;      ///< bind address file
  AddrFile      m_fileSrc;       ///< source address file
  ProtocolFile  m_fileProtocol;  ///< protocol file
  SOCK          *m_pSock;        ///< socket to use for receiving stream
  Time          m_timeout;       ///< timeout of network stream
  bool          m_needTimeout;   ///< if a timeout is needed
  Time          m_nextReq;       ///< when to send next request
  bool          m_needNextReq;   ///< if a next request is needed
}; // class Receiver

} // namespace Blinker

#endif // #ifndef BLINKER_RECEIVER_H

