/* 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_SIPPHONE_H
#define BLINKER_SIPPHONE_H

#include <condition_variable>
#include <mutex>
#include <string>
#include <thread>

#include "File.h"
#include "Module.h"
#include "NameFile.h"
#include "OpConn.h"
#include "OpConnIf.h"
#include "Time.h"
#include "TimeCallee.h"

namespace Blinker {

/// SIP phone connector
class SipPhone: public Module, public OpConnIf, public TimeCallee
{
public:
  /// configuration data for worker
  struct ConfigData {
    std::string soundDir; ///< directory of sound files
    std::string logFileName; ///< base name of log file
  };
  /// data shared between linphone thread and main Blinker thread
  struct SharedData {
    /// protection for this structure
    std::mutex mtx;
    /// worker threads waits on this condition, related mutex is g_mtx
    std::condition_variable cond;
    /// Blinker -> SIP
    //@{
    bool run; ///< whether to keep worker running (false = exit)
    bool reregister; ///< flag to trigger (re-)registration
    std::string server; ///< SIP server, empty means invalid
    std::string username; ///< SIP username, empty = no auth
    std::string password; ///< SIP password, empty = no auth
    bool reqPlay; ///< flag to trigger playing sound
    std::string reqPlayName; ///< name of sound to play
    bool hangup; ///< flag to trigger hangup of phone call
    //@}
    /// SIP -> Blinker
    //@{
    bool accepted; ///< flag for incoming/accepted phone call
    std::string dtmf; ///< DTMF keys received
    bool terminated; ///< flag for phone call is terminated
    //@}
  };

public:
  /**
   * @brief global initialization (call once before using this class)
   * @param[in] globalLogDir directory for global SIP log files
   */
  static void init(const Directory &globalLogDir);

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

  /// virtual destructor
  virtual ~SipPhone();

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

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

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

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

  /**
   * @brief key command received on operator connection
   * @param[in] pConn operator connection object
   * @param[in] key key that was pressed
   */
  virtual void opConnRecvKey(OpConn *pConn, char key);

  /**
   * @brief play command received on operator connection
   * @param[in] pConn operator connection object
   * @param[in] sound name of sound to play
   */
  virtual void opConnRecvPlay(OpConn *pConn, const std::string &sound);

  /**
   * @brief operator connection is closed
   * @param[in] pConn operator connection object
   *
   * The connection may not be used for sending any more in this callback.
   */
  virtual void opConnClose(OpConn *pConn);

protected:
  /// (re-)register with SIP server
  void sipRegister();

  /// deregister with SIP server
  void sipDeregister();

protected:
  NameFile    m_fileServer;   ///< name of SIP server
  NameFile    m_fileUsername; ///< SIP username
  NameFile    m_filePassword; ///< SIP password
  NameFile    m_fileTarget;   ///< target operator interface name to connect to
  ConfigData  m_configData;   ///< configuration data for worker
  std::thread m_worker;       ///< worker thread
  SharedData  m_sharedData;   ///< data shared between worker and main
  OpConn      *m_curConn;     ///< current connection
}; // class SipPhone

} // namespace Blinker

#endif // #ifndef BLINKER_SIPPHONE_H

