/****************************************************************************
 * 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 "./u_mqtttopics.h"
#include "./u_objects.h"
#include "./aqhomehttp.h"

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



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



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

static int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id);
static GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id);
static int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
static int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
static void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf);

static void _writeEditingTable(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
static void _setFromObject(AQH_MQTT_TOPIC *mqttTopic, const AQH_MQTT_TOPIC *srcMqttTopic);



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

AQH_HTTP_URLHANDLER *AQH_MqttTopicsHttpUrlHandler_new(AQH_SERVICE *sv)
{
  AQH_HTTP_URLHANDLER *uh;

  uh=AQH_ObjectsHttpUrlHandler_new(sv,
                                   AQHOME_HTTP_PERMS_LIST_TOPICS,
                                   AQHOME_HTTP_PERMS_ADD_TOPIC,
                                   AQHOME_HTTP_PERMS_DEL_TOPIC,
                                   AQHOME_HTTP_PERMS_EDIT_TOPIC,
                                   "/mqtttopics/list");
  AQH_ObjectsHttpUrlHandler_SetAddOrEditObjectFn(uh, _addOrEditObject);
  AQH_ObjectsHttpUrlHandler_SetFindObjectByIdAndReturnAsDbFn(uh, _findObjectByIdAndReturnAsDb);
  AQH_ObjectsHttpUrlHandler_SetWriteAddPageFn(uh, _writeAddPage);
  AQH_ObjectsHttpUrlHandler_SetWriteEditPageFn(uh, _writeEditPage);
  AQH_ObjectsHttpUrlHandler_SetListObjectsIntoBufferFn(uh, _listObjectsIntoBuffer);

  return uh;
}



int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id)
{
  AQH_SERVICE *sv;
  AQH_STORAGE *sto;
  AQH_MQTT_TOPIC *newMqttTopic;
  const char *topic;
  int rv;

  sv=AQH_HttpUrlHandler_GetHttpService(uh);
  sto=AqHomeHttpService_GetStorage(sv);

  newMqttTopic=AQH_MqttTopic_fromDb(db);

  topic=AQH_MqttTopic_GetTopic(newMqttTopic);
  if (!(topic && *topic)) {
    DBG_INFO(NULL, "Missing mqttTopic topic");
    AQH_MqttTopic_free(newMqttTopic);
    return GWEN_ERROR_INVALID;
  }

  rv=AqHomeHttpService_LockStorage(sv);
  if (rv<0) {
    DBG_ERROR(NULL, "Error locking storage");
    AQH_MqttTopic_free(newMqttTopic);
    return GWEN_ERROR_IO;
  }

  if (id>0) {
    AQH_MQTT_TOPIC *mqttTopic;

    DBG_INFO(NULL, "Edit existing mqttTopic");
    mqttTopic=AQH_Storage_GetMqttTopicById(sto, id);
    if (mqttTopic==NULL) {
      AqHomeHttpService_UnlockStorage(sv);
      DBG_ERROR(NULL, "MqttTopic %d not found", id);
      AQH_MqttTopic_free(newMqttTopic);
      return GWEN_ERROR_NOT_FOUND;
    }
    AQH_MqttTopic_SetId(mqttTopic, id);
    _setFromObject(mqttTopic, newMqttTopic);
    AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED);
  }
  else {
    AQH_MQTT_TOPIC *mqttTopic;

    DBG_INFO(NULL, "Adding new mqttTopic");
    mqttTopic=AQH_Storage_GetMqttTopicByTopic(sto, topic);
    if (mqttTopic) {
      AqHomeHttpService_UnlockStorage(sv);
      DBG_ERROR(NULL, "MqttTopic %s exists", topic);
      AQH_MqttTopic_free(newMqttTopic);
      return GWEN_ERROR_FOUND;
    }
    mqttTopic=AQH_MqttTopic_new();
    AQH_MqttTopic_SetId(mqttTopic, 0);
    _setFromObject(mqttTopic, newMqttTopic);
    AQH_Storage_AddMqttTopic(sto, mqttTopic);
    AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED);
  }
  AQH_MqttTopic_free(newMqttTopic);

  rv=AqHomeHttpService_UnlockStorage(sv);
  if (rv<0) {
    DBG_ERROR(NULL, "Error unlocking storage");
    return GWEN_ERROR_IO;
  }
  return 0;
}



void _setFromObject(AQH_MQTT_TOPIC *mqttTopic, const AQH_MQTT_TOPIC *srcMqttTopic)
{
  AQH_MqttTopic_SetDeviceId(mqttTopic, AQH_MqttTopic_GetDeviceId(srcMqttTopic));
  AQH_MqttTopic_SetTopic(mqttTopic, AQH_MqttTopic_GetTopic(srcMqttTopic));
  AQH_MqttTopic_SetDataType(mqttTopic, AQH_MqttTopic_GetDataType(srcMqttTopic));
}



GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id)
{
  AQH_SERVICE *sv;
  AQH_STORAGE *sto;
  const AQH_MQTT_TOPIC *mqttTopic;

  sv=AQH_HttpUrlHandler_GetHttpService(uh);
  sto=AqHomeHttpService_GetStorage(sv);
  
  mqttTopic=AQH_Storage_GetMqttTopicById(sto, id);
  if (mqttTopic) {
    GWEN_DB_NODE *db;
  
    db=GWEN_DB_Group_new("mqttTopic");
    AQH_MqttTopic_toDb(mqttTopic, db);
    return db;
  }
  return NULL;
}



int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
{
  GWEN_Buffer_AppendArgs(pageBuf,
                         "<h2>%s</h2><br>\n"
			 "<form action=\"/mqtttopics/add\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">",
			 I18N("Add MQTT Topic"));
  _writeEditingTable(uh, dbValues, pageBuf);
  GWEN_Buffer_AppendArgs(pageBuf, "<input type=\"submit\" value=\"%s\"></form>", I18N("Submit"));
  return 0;
}



int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
{

  GWEN_Buffer_AppendArgs(pageBuf,
                         "<h2>%s</h2><br>\n"
			 "<form action=\"/mqtttopics/edit/%lu\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">",
			 I18N("Edit MQTT Topic"),
			 (long unsigned int)(dbValues?GWEN_DB_GetIntValue(dbValues, "id", 0, 0):0));
  _writeEditingTable(uh, dbValues, pageBuf);
  GWEN_Buffer_AppendArgs(pageBuf, "<input type=\"submit\" value=\"%s\"></form>", I18N("Submit"));
  return 0;
}



void _writeEditingTable(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
{
  AQH_SERVICE *sv;
  AQH_STORAGE *sto;
  const GWEN_STRINGLIST *seenTopicsList;
  const AQH_DEVICE_LIST *deviceList;
  unsigned long int selectedDeviceId=0;
  int dataType;
  char numbuf[16];

  sv=AQH_HttpUrlHandler_GetHttpService(uh);
  sto=AqHomeHttpService_GetStorage(sv);
  deviceList=AQH_Storage_GetDeviceList(sto);

  selectedDeviceId=(unsigned long int)(dbValues?GWEN_DB_GetIntValue(dbValues, "deviceId", 0, 0):0);
  snprintf(numbuf, sizeof(numbuf)-1, "%lu", selectedDeviceId);
  numbuf[sizeof(numbuf)-1]=0;
  dataType=dbValues?GWEN_DB_GetIntValue(dbValues, "dataType", 0, AQH_MqttTopicType_Num):0;

  /* topic */
  GWEN_Buffer_AppendArgs(pageBuf,
                         "<table>"
                         "<tr>"
                         "  <td><label for=\"topic\">%s: </label></td>"
                         "  <td>"
                         "    <input list=\"seenTopics\" type=\"text\" name=\"topic\" id=\"topic\" value=\"%s\" size=\"64\" required>\n"
                         "      <datalist id=\"seenTopics\">",
                         I18N("MQTT Topic"),
                         dbValues?GWEN_DB_GetCharValue(dbValues, "topic", 0, ""):"");
  seenTopicsList=AQH_Storage_GetRecvdTopicList(sto);
  if (seenTopicsList && GWEN_StringList_Count(seenTopicsList)) {
    GWEN_STRINGLISTENTRY *se;

    se=GWEN_StringList_FirstEntry(seenTopicsList);
    while(se) {
      const char *s=GWEN_StringListEntry_Data(se);
      if (s && *s) {
        DBG_INFO(NULL, "Adding MQTT string %s", s);
        GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%s\">\n", s);
      }
      se=GWEN_StringListEntry_Next(se);
    }
  }
  else {
  }
  GWEN_Buffer_AppendString(pageBuf, "</datalist></td></tr>");


  /* device */
  GWEN_Buffer_AppendArgs(pageBuf,
                         "<tr><td><label for=\"deviceId\">%s: </label></td>"
                         "<td><select id=\"deviceId\" name=\"deviceId\">",
                         I18N("Device"));
  GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"0\">%s</option>\n", I18N("-- select device --"));

  if (deviceList) {
    const AQH_DEVICE *device;

    device=AQH_Device_List_First(deviceList);
    while(device) {
      const char *deviceName;

      deviceName=AQH_Device_GetName(device);
      if (deviceName && *deviceName) {
        snprintf(numbuf, sizeof(numbuf)-1, "%lu", (unsigned long int) AQH_Device_GetId(device));
        numbuf[sizeof(numbuf)-1]=0;
	if (selectedDeviceId && AQH_Device_GetId(device)==selectedDeviceId)
          GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%s\" selected>%s</option>\n", numbuf, deviceName);
        else
          GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%s\">%s</option>\n", numbuf, deviceName);
      }
      device=AQH_Device_List_Next(device);
    }
  }
  GWEN_Buffer_AppendString(pageBuf, "</select></td></tr>\n");

  /* data type */
  GWEN_Buffer_AppendArgs(pageBuf,
			 "<tr><td><label for=\"dataType\">%s: </label></td>"
                         "<td><select id=\"dataType\" name=\"dataType\">",
			 I18N("Data Type"));
  if (dataType==AQH_MqttTopicType_Num)
    GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%d\" selected>%s</option>", AQH_MqttTopicType_Num, I18N("numeric"));
  else
    GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%d\" >%s</option>", AQH_MqttTopicType_Num, I18N("numeric"));
  if (dataType==AQH_MqttTopicType_Json)
    GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%d\" selected>%s</option>", AQH_MqttTopicType_Json, I18N("JSON"));
  else
    GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%d\" >%s</option>", AQH_MqttTopicType_Json, I18N("JSON"));
  GWEN_Buffer_AppendString(pageBuf, "</select></td></tr>\n");


  if (seenTopicsList && GWEN_StringList_Count(seenTopicsList)) {
    GWEN_STRINGLISTENTRY *se;

    GWEN_Buffer_AppendArgs(pageBuf, "<tr><td valign=\"top\"><label for=\"receivedTopicsList\">%s: </label></td>", I18N("Received Topics"));
    GWEN_Buffer_AppendString(pageBuf, "<td><output name=\"receivedTopicsList\" id=\"receivedTopicsList\">");

    se=GWEN_StringList_FirstEntry(seenTopicsList);
    while(se) {
      const char *s=GWEN_StringListEntry_Data(se);
      if (s && *s)
        GWEN_Buffer_AppendArgs(pageBuf, "%s<br>\n", s);
      se=GWEN_StringListEntry_Next(se);
    }
    GWEN_Buffer_AppendString(pageBuf, "</output></td></tr>");
  }



  GWEN_Buffer_AppendString(pageBuf, "</tbody></table>\n");
}



void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf)
{
  AQH_SERVICE *sv;
  AQH_STORAGE *sto;
  const AQH_MQTT_TOPIC_LIST *rl;

  sv=AQH_HttpUrlHandler_GetHttpService(uh);
  sto=AqHomeHttpService_GetStorage(sv);

  GWEN_Buffer_AppendArgs(pageBuf,
			 "<h2>%s</h2>"
			 "<table class=\"dataTable\">"
			 "<thead>"
			 "  <tr><th>%s</th><th>%s</th><th>%s</th><th></th></tr>"
			 "</thead>",
			 I18N("Mqtt Topics"),
			 I18N("Topic"),
			 I18N("Device"),
			 I18N("Datatype"));
  GWEN_Buffer_AppendString(pageBuf, "<tbody>");
  rl=AQH_Storage_GetMqttTopicList(sto);
  if (rl) {
    const AQH_MQTT_TOPIC *mqttTopic;

    mqttTopic=AQH_MqttTopic_List_First(rl);
    while(mqttTopic) {
      long unsigned int id;
      int deviceId;
      const char *topic;
      int dataType;
      const char *deviceName=NULL;
      const AQH_DEVICE *device=NULL;

      id=(long unsigned int) AQH_MqttTopic_GetId(mqttTopic);
      deviceId=(long unsigned int) AQH_MqttTopic_GetDeviceId(mqttTopic);
      if (deviceId>0)
	device=AQH_Storage_GetDeviceById(sto, deviceId);
      if (device)
	deviceName=AQH_Device_GetName(device);

      topic=AQH_MqttTopic_GetTopic(mqttTopic);
      dataType=AQH_MqttTopic_GetDataType(mqttTopic);
      GWEN_Buffer_AppendArgs(pageBuf,
			     "<tr><td>%s</td><td>%s</td><td>%s</td>"
                             "<td><a href=\"/mqtttopics/edit/%lu\">"
                             "<IMG src=\"/pics/edit.png\" width=32 height=32 align=left border=0></a></td>"
                             "</tr>",
			     topic?topic:"",
			     deviceName?deviceName:"",
			     AQH_MqttTopicType_toString(dataType),
			     id);
      mqttTopic=AQH_MqttTopic_List_Next(mqttTopic);
    }
  }
  GWEN_Buffer_AppendString(pageBuf, "</tbody>");
  GWEN_Buffer_AppendArgs(pageBuf, "</table><a href=\"/mqtttopics/add\">%s</a><br>", I18N("Add MqttTopic"));
}





