/* 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_OPSPLITTER_H
#define BLINKER_OPSPLITTER_H

#include <map>
#include <string>

#include "BoolFile.h"
#include "Directory.h"
#include "File.h"
#include "ListTracker.h"
#include "Mgrs.h"
#include "Module.h"
#include "NameFile.h"
#include "OpConn.h"
#include "OpConnIf.h"
#include "OpReqIf.h"
#include "SettingFile.h"
#include "Time.h"
#include "TimeCallee.h"
#include "UIntFile.h"

namespace Blinker {

/// operator connection splitter
class OpSplitter: public Module, public OpReqIf, public TimeCallee
{
protected:
  /// extension to be called
  class Extension;

  /// extension list tracker
  typedef ListTracker<OpSplitter, Extension, Directory> ExtListTracker;

  /// map of extensions to call (extension name -> module name)
  typedef std::map<std::string, std::string> ExtMap;

  /// type for locally handles connection
  struct Local {
    std::string m_number;   ///< extension number dialed so far
    bool        m_sendPlay; ///< if to send a play request
    bool        m_close;    ///< if to close connection as soon as possible
  };

  /**
   * @brief map of local connections,
   *        contains all incoming connections as key for which no
   *        outgoing connection is available
   */
  typedef std::map<OpConn *, Local> MapLocal;

  /**
   * @brief map from incoming to outgoing connections,
   *        contains all incoming connectes as key for which a corresponding
   *        outgoing connection is available
   */
  typedef std::map<OpConn *, OpConn *> MapInOut;

  /// map from outgoing to incoming connections
  typedef std::map<OpConn *, OpConn *> MapOutIn;

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

  /// virtual destructor
  virtual ~OpSplitter();

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

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

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

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

  /**
   * @brief check if accepting new operator connection is possible
   * @param[in] name operator interface name
   * @return if accepting new connection is possible
   */
  virtual bool acceptNewOpConn(const std::string &name);

  /**
   * @brief new operator connection
   * @param[in] name operator interface name
   * @param[in] pConn operator connection object
   *
   * The new connection may not yet be used for sending inside this callback.
   */
  virtual void newOpConn(const std::string &name, OpConn *pConn);

  /**
   * @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:
  /**
   * @brief create new local connection
   * @param[in] pConn connection to make local
   * @param[in] close if to close connection as soon as possible
   */
  void newLocal(OpConn *pConn, bool close = false);

  /**
   * @brief a key has been pressed for a local connection
   * @param[in] itLocal local connection
   * @param[in] key the key pressed
   */
  void localKey(MapLocal::iterator itLocal, char key);

  /**
   * @brief call extension dialed over local connection
   * @param[in] itLocal local connection
   */
  void callExtension(MapLocal::iterator itLocal);

protected:
  NameFile       m_fileSound;      ///< file containing sound name
  UIntFile       m_fileMaxConn;    ///< file containing max. number of conn.
  BoolFile       m_fileSingle;     ///< file containing single mode config
  std::string    m_singleOp;       ///< operator intf. to call in single mode
  ExtListTracker m_extListTracker; ///< extension tracker
  ExtMap         m_extMap;         ///< map of extensions to call
  MapLocal       m_mapLocal;       ///< localy handled connections
  MapInOut       m_mapInOut;       ///< map from incoming to outgoing conn.
  MapOutIn       m_mapOutIn;       ///< map from outgoing to incoming conn.
}; // class OpSplitter

} // namespace Blinker

#endif // #ifndef BLINKER_OPSPLITTER_H

