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

#include "CallMgr.h"
#include "Directory.h"
#include "File.h"
#include "Mgrs.h"
#include "Module.h"
#include "OpConn.h"
#include "OpConnIf.h"
#include "OpMgr.h"
#include "OpPrinter.h"
#include "OpReqIf.h"
#include "Time.h"
#include "TimeCallee.h"

namespace Blinker {

/**
 * @brief constructor
 * @param[in] name module name
 * @param[in] mgrs managers
 * @param[in] dirBase base directory
 */
OpPrinter::OpPrinter(const std::string &name, Mgrs &mgrs,
                     const Directory &dirBase):
  Module(name, mgrs, dirBase)
{
  // open operator connection interface
  m_mgrs.m_opMgr.open(m_name, this);
}

/// virtual destructor
OpPrinter::~OpPrinter()
{
  // close operator connection interface
  m_mgrs.m_opMgr.close(m_name);

  // close open operator connections
  while (!m_opConns.empty()) {
    OpConns::iterator itOpConn = m_opConns.begin();
    (*itOpConn)->close();
    m_opConns.erase(itOpConn);
  }
}

/// check for update of configuration
void OpPrinter::updateConfig()
{
  // nothing to do here for this module
}

/// callback when requested time reached
void OpPrinter::timeCall()
{
  while (!m_sendPlay.empty()) {
    OpConns::iterator it = m_sendPlay.begin();
    (*it)->sendPlay("opprinter");
    m_sendPlay.erase(it);
  }
}

/**
 * @brief check if accepting new operator connection is possible
 * @param[in] name operator interface name
 * @return if accepting new connection is possible
 */
bool OpPrinter::acceptNewOpConn(const std::string &name)
{
  return true; // accept all connections
  (void)name; // unused
}

/**
 * @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.
 */
void OpPrinter::newOpConn(const std::string &name, OpConn *pConn)
{
  m_opConns.insert(pConn);
  std::cout << "new connection " << pConn << std::endl;
  m_sendPlay.insert(pConn); // schedule sending play command
  m_mgrs.m_callMgr.requestTimeCall(this, Time::now());
  (void)name; // unused
}

/**
 * @brief key command received on operator connection
 * @param[in] pConn operator connection object
 * @param[in] key key that was pressed
 */
void OpPrinter::opConnRecvKey(OpConn *pConn, char key)
{
  std::cout << "key \"" << key << "\" on connection " << pConn << std::endl;

  // reply to some keys with play command for sounds
  switch (key) {
    case '0': pConn->sendPlay("zero"); break;
    case '1': pConn->sendPlay("one"); break;
    case '2': pConn->sendPlay("two"); break;
    case '3': pConn->sendPlay("three"); break;
    case '4': pConn->sendPlay("four"); break;
    case '5': pConn->sendPlay("five"); break;
    case '6': pConn->sendPlay("six"); break;
    case '7': pConn->sendPlay("seven"); break;
    case '8': pConn->sendPlay("eight"); break;
    case '9': pConn->sendPlay("nine"); break;
    case '*': pConn->sendPlay("star"); break;
    case '#':
      std::cout << "closing connection " << pConn << std::endl;
      pConn->close();
      m_opConns.erase(pConn);
      m_sendPlay.erase(pConn); // could be in there, better be on safe side
      break;
  }
}

/**
 * @brief play command received on operator connection
 * @param[in] pConn operator connection object
 * @param[in] sound name of sound to play
 */
void OpPrinter::opConnRecvPlay(OpConn *pConn, const std::string &sound)
{
  // this interface is usually not called for incoming connections
  std::cout << "play sound \"" << sound << "\" on connection " << pConn
            << std::endl;
}

/**
 * @brief operator connection is closed
 * @param[in] pConn operator connection object
 *
 * The connection may not be used for sending any more in this callback.
 */
void OpPrinter::opConnClose(OpConn *pConn)
{
  std::cout << "connection " << pConn << " closed" << std::endl;
  m_opConns.erase(pConn);
  m_sendPlay.erase(pConn); // could be in there, better be on safe side
}

} // namespace Blinker

