/*
 * tcp_connection_listener.h
 *
 *  Created on: 02 Oct 2014
 *      Author: stephan
 */

#ifndef TCP_CONNECTION_LISTENER_H_
#define TCP_CONNECTION_LISTENER_H_
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <list>

#include <kutils/kconfig.h>
#include <klog/klog.h>

#include "daemon_obj.h"
#include "connected_client_obj.h"

class TcpConnectionListener
{
  public:
    /**
     * If daemonObj is not initialized in constructor, clients will still be able
     * to connect and send msgs to the Server, but no replies will be received.
     *
     * @param _port_num
     * @param _serial_obj
     */
    TcpConnectionListener(int _port_num, DaemonObj* _serial_obj = NULL);

    /**
     * Starts the tcp_listener thread
     */
    void StartListener() {
      pthread_create(&m_connection_listener_thread_id, 0, &Run,
          (void*) m_instance);
      pthread_detach(m_connection_listener_thread_id);
    }

    /**
     * Set the DaemonObj with supplies a serial connection to a device
     * @param _serial_obj
     */
    void SetDaemonObj(DaemonObj* _serial_obj) {
      m_serial_obj = _serial_obj;
      for (std::list<ConnectedClientObj*>::iterator iterator =
          m_comms_client_list.begin(); iterator != m_comms_client_list.end();
          ++iterator) {
        ((ConnectedClientObj*) *iterator)->SetDaemonObj(m_serial_obj);
      }
    }

    DaemonObj* GetDaemonObj() {
      return m_serial_obj;
    }

    /**
     * Returns true if there is currently an active client
     * @return
     */
    bool IsAClientConnect() {
      m_instance->RemoveDisconnectedClients();
      if (m_comms_client_list.size() > 0)
        return true;
      return false;
    }

    bool isRunning() {
      return m_running;
    }
    ;
    virtual ~TcpConnectionListener();

  private:
    int SetUpServer();
    void WaitForClient();
    static void* Run(void *arg) {
      ((TcpConnectionListener*) arg)->ClientListenerThread();
      return NULL;
    }
    void ClientListenerThread();
    void Stop();

    /**
     * Runs through the client list and removes inactive clients
     */
    void RemoveDisconnectedClients() {
      if (!m_comms_client_list.size())
        return;
      //Iterate through the list, clean up all clients which aren't active anymore
      for (std::list<ConnectedClientObj*>::iterator iterator =
          m_comms_client_list.begin(); iterator != m_comms_client_list.end();) {
        if (!((ConnectedClientObj*) *iterator)->IsActive()) {
          ConnectedClientObj* temp_obj = ((ConnectedClientObj*) *iterator);
          delete temp_obj;
          iterator = m_comms_client_list.erase(iterator);
        }
        else {
          ++iterator;
        }
      }
    }

    TcpConnectionListener* m_instance;
    pthread_t m_connection_listener_thread_id;
    /**
     * Single serial object, object receives data from clients, passes
     * it on and then replies to the client
     */
    DaemonObj* m_serial_obj;

    /**
     * List of client connections made to the mux
     */
    std::list<ConnectedClientObj*> m_comms_client_list;
    int m_port_num;

    /**
     * Tcp host host attributes
     */
    int m_host_socket;
    socklen_t m_address_size;
    struct sockaddr_in m_address;
    sockaddr_in m_socket_address;

    bool m_running;
};

#endif /* TCP_CONNECTION_LISTENER_H_ */
