/****************************************************************************
 * 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 "./c_updatedata.h"
#include "./aqhome_data_p.h"
#include "./loop.h"
#include "aqhome/ipc/data/ipc_data.h"
#include "aqhome/ipc/data/msg_data_multidata.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/msg_ipc_result.h"
#include "aqhome/ipc/msg_ipc_tag16.h"

#include <gwenhywfar/debug.h>



/* ------------------------------------------------------------------------------------------------
 * defines
 * ------------------------------------------------------------------------------------------------
 */

#define DISABLE_DEBUGLOG



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

static int _storeDataPoints(AQHOME_DATA *aqh, const AQH_VALUE *v, const uint64_t *dataPoints, unsigned int numValues);
static void _sendDataChangedMsgToAllClients(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epSrc, const AQH_VALUE *v,
					    const uint64_t *dataPoints, uint32_t numValues);



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

void AqHomeData_HandleUpdateData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg)
{
  GWEN_MSG *outMsg;
  int resultCode=AQH_MSG_IPC_SUCCESS;
  const GWEN_TAG16 *tag;
  AQH_VALUE *recvdValue;
  const char *valueName;
  const uint64_t *dataPoints=NULL;
  unsigned int numberOfPoints=0;

  AQH_MultiDataDataIpcMsg_Parse(recvdMsg, 0);

  recvdValue=AQH_MultiDataDataIpcMsg_ReadValue(recvdMsg);
  valueName=recvdValue?AQH_Value_GetName(recvdValue):NULL;
  tag=AQH_Tag16IpcMsg_FindFirstTagByType(recvdMsg, AQH_MSGDATA_MULTIDATA_TAGS_DATA);
  dataPoints=tag?((const uint64_t*)GWEN_Tag16_GetTagData(tag)):NULL;
  numberOfPoints=(tag?GWEN_Tag16_GetTagLength(tag):0)/(2*sizeof(uint64_t));

  if (numberOfPoints>0) {
    AQH_VALUE *value;

    value=AqHomeData_GetOrCreateValueForDriverWithTemplate(aqh, ep, recvdValue);
    if (value) {
      resultCode=_storeDataPoints(aqh, value, dataPoints, numberOfPoints);
      if (resultCode==AQH_MSG_IPC_SUCCESS)
        _sendDataChangedMsgToAllClients(aqh, ep, value, dataPoints, numberOfPoints);
    }
    else {
      DBG_INFO(NULL, "No permissions to add datapoint for value \"%s\"", valueName);
      resultCode=AQH_MSG_IPC_ERROR_PERMS;
    }
  }
  else {
    DBG_INFO(NULL, "No datapoints");
    resultCode=AQH_MSG_IPC_ERROR_INVALID;
  }
  AQH_Value_free(recvdValue);

  outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT, resultCode);
  GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
}



int _storeDataPoints(AQHOME_DATA *aqh, const AQH_VALUE *v, const uint64_t *dataPoints, unsigned int numValues)
{
  uint32_t i;

  for(i=0; i<numValues; i++) {
    uint64_t timestamp;
    union {double f; uint64_t i;} u;
    int rv;

    timestamp=*(dataPoints++);
    u.i=*(dataPoints++);
    rv=AQH_Storage_AddDatapoint(aqh->storage, AQH_Value_GetId(v), timestamp, u.f);
    if (rv<0) {
      DBG_INFO(NULL, "here (%d)", rv);
      return AQH_MSG_IPC_ERROR_GENERIC;
    }
    else {
      DBG_DEBUG(NULL, "Datapoint added for value \"%s\"", AQH_Value_GetNameForSystem(v));
    }
  } /* for */

  return AQH_MSG_IPC_SUCCESS;
}



void _sendDataChangedMsgToAllClients(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epSrc, const AQH_VALUE *v,
				     const uint64_t *dataPoints, uint32_t numValues)
{
  GWEN_MSG_ENDPOINT *ep;

  ep=GWEN_MsgEndpoint_Tree2_GetFirstChild(aqh->ipcdEndpoint);
  while(ep) {
    if (ep!=epSrc) {
      if (GWEN_MsgEndpoint_GetFlags(ep) & AQH_IPCENDPOINT_FLAGS_WANTUPDATES) {
	GWEN_MSG *msg;

	DBG_DEBUG(AQH_LOGDOMAIN, "Sending update msg to endpoint %s", GWEN_MsgEndpoint_GetName(ep));
        msg=AQH_MultiDataDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_DATACHANGED, v, dataPoints, numValues);
        GWEN_MsgEndpoint_AddSendMessage(ep, msg);
      }
      else {
	DBG_DEBUG(AQH_LOGDOMAIN, "Endpoint %s doesn't want updates", GWEN_MsgEndpoint_GetName(ep));
      }
    }
    else {
      DBG_DEBUG(AQH_LOGDOMAIN, "Not sending update msg to source of updates");
    }
    ep=GWEN_MsgEndpoint_Tree2_GetNext(ep);
  }
}



