/* 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 <map>
#include <string>

#include "OpConn.h"
#include "OpConnIf.h"
#include "OpMgr.h"
#include "OpReqIf.h"

namespace Blinker {

/// constructor
OpMgr::OpMgr()
{
}

/// destructor
OpMgr::~OpMgr()
{
}

/**
 * @brief open operator interface
 * @param[in] name operator interface name
 * @param[in] pOpReqIf interface to call on incoming operator request
 * @return if operator interface could be opened
 */
bool OpMgr::open(const std::string &name, OpReqIf *pOpReqIf)
{
  if (m_reqIfs.find(name) != m_reqIfs.end())
    return false; // already open
  m_reqIfs[name] = pOpReqIf;
  return true;
}

/**
 * @brief close operator interface
 * @param[in] name operator interface name
 * @return if interface name was open before
 */
bool OpMgr::close(const std::string &name)
{
  ReqIfMap::iterator itReqIf = m_reqIfs.find(name);
  if (itReqIf == m_reqIfs.end())
    return false; // was not open
  m_reqIfs.erase(itReqIf);
  return true;
}

/**
 * @brief check if operator interface will accept new connection
 * @param[in] name operator interface to connect to
 * @return if a new connection would be accepted
 */
bool OpMgr::canConnect(const std::string &name)
{
  // find requested interface
  ReqIfMap::iterator itReqIf = m_reqIfs.find(name);
  if (itReqIf == m_reqIfs.end())
    return false; // not open

  // check with server side if new connection is accepted
  return itReqIf->second->acceptNewOpConn(name);
}

/**
 * @brief connect to operator interface
 * @param[in] name operator interface to connect to
 * @param[in] pOpConnIf interface to call on connection events
 * @return operator connection object (or NULL on error)
 */
OpConn * OpMgr::connect(const std::string &name, OpConnIf *pOpConnIf)
{
  // find requested interface
  ReqIfMap::iterator itReqIf = m_reqIfs.find(name);
  if (itReqIf == m_reqIfs.end())
    return NULL; // not open

  // check with server side if new connection is accepted
  if (!itReqIf->second->acceptNewOpConn(name))
    return NULL; // not accepted

  // create new connection
  OpConn *pConnCli = new OpConn(pOpConnIf);
  OpConn *pConnSrv = new OpConn(itReqIf->second);
  pConnCli->setRemote(pConnSrv);
  pConnSrv->setRemote(pConnCli);

  // deliver new connection
  itReqIf->second->newOpConn(name, pConnSrv);
  return pConnCli;
}

} // namespace Blinker

