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

#ifndef DAEMON_OBJ_H_
#define DAEMON_OBJ_H_

#include <klog.h>

/**
 * Abstract Base class to any device daemon, communication between tcp clients and the
 * device daemon is facilitated through classes derived from this object.
 */
class DaemonObj
{
  public:
    DaemonObj() :
        m_ready_for_transfer(false) {
      pthread_mutex_init(&m_obj_mutex, NULL);
      m_instance = this;
    }

    void SetReadyForTransfer(bool _arg) {
      m_ready_for_transfer = _arg;
    }

    /**
     * If pure virtual method Connect() succeeded, readyForTransfer should return
     * true
     * @return
     */
    bool ReadyForTransfer() {
      return m_ready_for_transfer;
    }

    /**
     * unsigned char* SendReceiveMsg(unsigned char* msg, int msg_len, int* reply_len_)
     *
     * This method CAN NOT BE OVERLOADED, implement the correct SendToDeviceAndReply()
     * in the leaf classes and call this method from them in order to invoke the
     * implemented SendToDeviceAndReply().
     *
     * This is done to ensure msg integrity.
     *
     * @param _msg
     * @param _msg_len
     * @param reply_len_
     * @return reply
     */
    virtual void SendReceiveMsg(unsigned char* _msg, int _msg_len,
        unsigned char* reply_, int* reply_len_) final {

      if (ReadyForTransfer()) {
        pthread_mutex_lock(&m_obj_mutex);
        SendToDeviceAndReply(_msg, _msg_len, reply_, reply_len_);
        pthread_mutex_unlock(&m_obj_mutex);
      }
      else {
        cKlog::getLog("DaemonObj").error(
            "A connection to the serial device has not yet been established");
        *reply_len_ = -1;
      }
    }

    virtual ~DaemonObj() {
    }
  protected:
    /**
     * virtual unsigned char* SendToDeviceAndReply(unsigned char* msg, int msg_len, int* reply_len_) = 0;
     *
     * Method is protected because it has to be called inside the mutex lock.
     * This is a shared resource and is locked in SendReceiveMsg().
     *
     * Method has to be implemented and facilitate transfer between serial device
     * and the object
     *
     * @param _msg
     * @param _msg_len
     * @param reply_len_
     * @return reply
     */
    virtual void SendToDeviceAndReply(unsigned char* _msg, int _msg_len,
        unsigned char* reply_, int* reply_len_) = 0;

    /**
     * Sets up the serial connection the the device.
     * @return
     */
    virtual void Connect() = 0;

    DaemonObj* m_instance;
  private:

    bool m_ready_for_transfer;

    /**
     * m_obj_mutex protects SendToDeviceAndReply method;
     *
     * Only one client may communicate with the device at a time
     */
    pthread_mutex_t m_obj_mutex;
};

#endif /* DAEMON_OBJ_H_ */
