/****************************************************************************
 * This file is part of the project AqHome.
 * AqHome (c) by 2023 Martin Preuss, all rights reserved.
 *
 * The license for this file can be found in the file COPYING which you
 * should have received along with this file.
 ****************************************************************************/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include "aqhome/ipc/endpoint_ipcclient.h"
#include "aqhome/ipc/data/ipc_data.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/data/msg_data_connect.h"
#include "aqhome/ipc/msg_ipc_result.h"

#include <gwenhywfar/endpoint_ipc.h>
#include <gwenhywfar/endpoint_tcpc.h>
#include <gwenhywfar/endpoint_multilayer.h>
#include <gwenhywfar/debug.h>


#define AQH_MSG_ENDPOINT_IPCCLIENT_NAME     "ipc-client"



/* ------------------------------------------------------------------------------------------------
 * forward declarations
 * ------------------------------------------------------------------------------------------------
 */

static int _startConnect(GWEN_MSG_ENDPOINT *ep, GWEN_MSG_ENDPOINT *epChild);
static void _checkSockets(GWEN_MSG_ENDPOINT *ep,
                          GWEN_MSG_ENDPOINT *epChild,
                          GWEN_SOCKETSET *readSet,
                          GWEN_SOCKETSET *writeSet,
                          GWEN_SOCKETSET *xSet);



/* ------------------------------------------------------------------------------------------------
 * implementations
 * ------------------------------------------------------------------------------------------------
 */

GWEN_MSG_ENDPOINT *AQH_ClientIpcEndpoint_new(const char *name, int groupId)
{
  GWEN_MSG_ENDPOINT *ep;

  ep=GWEN_MultilayerEndpoint_new(name?name:AQH_MSG_ENDPOINT_IPCCLIENT_NAME, groupId);
  GWEN_MultilayerEndpoint_SetStartConnectFn(ep, _startConnect);
  GWEN_MultilayerEndpoint_SetCheckSocketsFn(ep, _checkSockets);

  return ep;
}



int _startConnect(GWEN_MSG_ENDPOINT *ep, GWEN_MSG_ENDPOINT *epChild)
{
  if (epChild) {
    int rv;
    GWEN_MSG *msg;
    uint32_t flagsForConnectMsg;

    flagsForConnectMsg=(GWEN_MsgEndpoint_GetFlags(ep) & AQH_ENDPOINT_IPCCLIENT_FLAGS_WANTUPDATES)?AQH_IPCENDPOINT_FLAGS_WANTUPDATES:0;

    rv=GWEN_TcpcEndpoint_StartConnect(epChild);
    if (rv<0 && rv!=GWEN_ERROR_IN_PROGRESS) {
      DBG_INFO(AQH_LOGDOMAIN, "Error starting to connect child layer (%d)", rv);
      return rv;
    }
    msg=AQH_ConnectDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_CONNECT_REQ,
                                  AQH_IpcEndpoint_GetServiceName(epChild),
                                  AQH_IpcEndpoint_GetUserName(epChild),
                                  AQH_IpcEndpoint_GetPassword(epChild),
                                  flagsForConnectMsg);
    GWEN_MsgEndpoint_AddSendMessage(epChild, msg);
    GWEN_MsgEndpoint_SetState(ep, GWEN_MSG_ENDPOINT_STATE_CONNECTING);
    return rv; /* result from GWEN_TcpcEndpoint_StartConnect() above */
  }
  return GWEN_ERROR_GENERIC;
}



void _checkSockets(GWEN_MSG_ENDPOINT *ep,
                   GWEN_MSG_ENDPOINT *epChild,
                   GWEN_SOCKETSET *readSet,
                   GWEN_SOCKETSET *writeSet,
                   GWEN_SOCKETSET *xSet)
{
  GWEN_MSG *msg;

  GWEN_MsgEndpoint_CheckSockets(epChild, readSet, writeSet, xSet); /* let base layer work */

  msg=GWEN_MsgEndpoint_GetFirstReceivedMessage(epChild);
  while(msg)  {
    GWEN_MSG *msgNext;
    uint16_t code;

    msgNext=GWEN_Msg_List_Next(msg);
    code=GWEN_IpcMsg_GetCode(msg);
    if (code==AQH_MSGTYPE_IPC_DATA_RESULT) {
      uint32_t resultCode;

      GWEN_Msg_List_Del(msg); /* remove from list */
      resultCode=AQH_ResultIpcMsg_GetResultCode(msg);
      if (resultCode==AQH_MSG_IPC_SUCCESS) {
        DBG_INFO(AQH_LOGDOMAIN, "Positive CONNECT response, connected");
        GWEN_MsgEndpoint_SetState(ep, GWEN_MSG_ENDPOINT_STATE_CONNECTED);
      }
      else {
        DBG_ERROR(AQH_LOGDOMAIN, "Negative CONNECT response (%d)", code);
        GWEN_MsgEndpoint_Disconnect(epChild);
        GWEN_MsgEndpoint_Disconnect(ep);
      }
      GWEN_Msg_free(msg);
      break;
    }
    else {
      DBG_ERROR(AQH_LOGDOMAIN, "Ignoring response (%u)", code);
      GWEN_Msg_free(msg);
    }
    msg=msgNext;
  } /* while */
}






