/****************************************************************************
 * This file is part of the project AqHome.
 * AqHome (c) by 2025 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/aqhome.h"
#include "aqhome/msg/node/m_value.h"
#include "aqhome/msg/node/m_node.h"

#include <gwenhywfar/debug.h>
#include <gwenhywfar/endianfns.h>



#define AQH_MSG_OFFS_VALUE_UID         0  /* 4 bytes */
#define AQH_MSG_OFFS_VALUE_MSGID       4  /* 2 bytes */
#define AQH_MSG_OFFS_VALUE_VALUEID     6  /* 1 byte */
#define AQH_MSG_OFFS_VALUE_VALUETYPE   7  /* 1 byte */
#define AQH_MSG_OFFS_VALUE_VALUE       8  /* 2 bytes */
#define AQH_MSG_OFFS_VALUE_DENOM       10 /* 2 bytes */



AQH_MESSAGE *AQH_ValueMessage_new(uint8_t destAddr, uint8_t srcAddr, uint8_t code,
                                  uint16_t msgId, uint8_t valueId, uint16_t value, uint16_t denom)
{
  uint8_t payload[12];
  uint8_t *ptr;

  ptr=payload;
  *(ptr++)=0;                     /* uid (empty) */
  *(ptr++)=0;
  *(ptr++)=0;
  *(ptr++)=0;

  *(ptr++)=msgId & 0xff;          /* msgid */
  *(ptr++)=(msgId>>8) & 0xff;

  *(ptr++)=valueId;               /* valueid */
  *(ptr++)=0;                     /* valuetype (empty) */

  *(ptr++)=value & 0xff;          /* value */
  *(ptr++)=(value>>8) & 0xff;

  *(ptr++)=denom & 0xff;          /* denom */
  *(ptr++)=(denom>>8) & 0xff;

  return AQH_NodeMessage_new(destAddr, srcAddr, code, sizeof(payload), payload);
}



uint32_t AQH_ValueMessage_GetUid(const AQH_MESSAGE *msg)
{
  return AQH_Message_ReadUint32At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_VALUE_UID, 0);
}



uint16_t AQH_ValueMessage_GetMsgId(const AQH_MESSAGE *msg)
{
  return AQH_Message_ReadUint16At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_VALUE_MSGID, 0);
}



uint8_t AQH_ValueMessage_GetValueId(const AQH_MESSAGE *msg)
{
  return AQH_Message_ReadUint8At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_VALUE_VALUEID, 0);
}



uint8_t AQH_ValueMessage_GetValueType(const AQH_MESSAGE *msg)
{
  return AQH_Message_ReadUint8At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_VALUE_VALUETYPE, 0);
}



uint16_t AQH_ValueMessage_GetValueNom(const AQH_MESSAGE *msg)
{
  return AQH_Message_ReadUint16At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_VALUE_VALUE, 0);
}



uint16_t AQH_ValueMessage_GetValueDenom(const AQH_MESSAGE *msg)
{
  return AQH_Message_ReadUint16At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_VALUE_DENOM, 0);
}



const char *AQH_ValueMessage_GetValueTypeName(const AQH_MESSAGE *msg)
{
  return AQH_ValueModality_toString(AQH_ValueMessage_GetValueType(msg));
}



const char *AQH_ValueMessage_GetValueAsWindowStateString(const AQH_MESSAGE *msg)
{
  switch(AQH_ValueMessage_GetValueNom(msg)) {
  case 0:   return "closed";
  case 128: return "tilted";
  case 255: return "open";
  default:  break;
  }
  return "unknown";
}



const char *AQH_ValueMessage_GetValueTypeUnits(const AQH_MESSAGE *msg)
{
  uint8_t t;

  t=AQH_ValueMessage_GetValueType(msg);
  switch(t) {
  case AQH_MSG_VALUE_TYPE_TEMP:     return "Celsius";
  case AQH_MSG_VALUE_TYPE_HUMIDITY: return "%";
  case AQH_MSG_VALUE_TYPE_DOOR:     return NULL;
  case AQH_MSG_VALUE_TYPE_CO2:      return "ppm";
  case AQH_MSG_VALUE_TYPE_TVOC:     return "ppb";
  default:                           break;
  }
  return NULL;
}



double AQH_ValueMessage_GetValue(const AQH_MESSAGE *msg)
{
  double value;
  double denom;
  uint16_t intDenom;

  value=AQH_ValueMessage_GetValueNom(msg);
  intDenom=AQH_ValueMessage_GetValueDenom(msg);
  if (intDenom==0)
    denom=1.0;
  else
    denom=(double) intDenom;
  return (double)(value/denom);
}



void AQH_ValueMessage_DumpToBuffer(const AQH_MESSAGE *msg, GWEN_BUFFER *dbuf, const char *sText)
{
  const char *sCmd;

  switch(AQH_NodeMessage_GetMsgType(msg)) {
  case AQH_MSG_TYPE_VALUE_REPORT:    sCmd="report"; break;
  case AQH_MSG_TYPE_VALUE_SET:       sCmd="set"; break;
  case AQH_MSG_TYPE_VALUE_SET_ACK:   sCmd="ack"; break;
  case AQH_MSG_TYPE_VALUE_SET_NACK:  sCmd="nack"; break;
  default:                           sCmd="unknown"; break;
  }

  if (AQH_ValueMessage_GetValueType(msg)==AQH_MSG_VALUE_TYPE_DOOR)
    GWEN_Buffer_AppendArgs(dbuf,
                           "0x%02x->0x%02x: VALUE(%s) %s (uid=0x%08x, msgId=%u, value_id=0x%02x type=%s(%d) value=%s [%04x/%04x])\n",
                           AQH_NodeMessage_GetSourceAddress(msg),
                           AQH_NodeMessage_GetDestAddress(msg),
                           sCmd,
                           sText,
                           (unsigned int) AQH_ValueMessage_GetUid(msg),
                           (unsigned int)AQH_ValueMessage_GetMsgId(msg),
                           AQH_ValueMessage_GetValueId(msg),
                           AQH_ValueMessage_GetValueTypeName(msg),
                           AQH_ValueMessage_GetValueType(msg),
                           AQH_ValueMessage_GetValueAsWindowStateString(msg),
                           AQH_ValueMessage_GetValueNom(msg),
                           AQH_ValueMessage_GetValueDenom(msg));
  else
    GWEN_Buffer_AppendArgs(dbuf,
                           "0x%02x->0x%02x: VALUE(%s) %s (uid=0x%08x, msgId=%u, value_id=0x%02x type=%s(%d) value=%f [%04x/%04x])\n",
                           AQH_NodeMessage_GetSourceAddress(msg),
                           AQH_NodeMessage_GetDestAddress(msg),
                           sCmd,
                           sText,
                           (unsigned int) AQH_ValueMessage_GetUid(msg),
                           (unsigned int)AQH_ValueMessage_GetMsgId(msg),
                           AQH_ValueMessage_GetValueId(msg),
                           AQH_ValueMessage_GetValueTypeName(msg),
                           AQH_ValueMessage_GetValueType(msg),
                           AQH_ValueMessage_GetValue(msg),
                           AQH_ValueMessage_GetValueNom(msg),
                           AQH_ValueMessage_GetValueDenom(msg));
}








