/****************************************************************************
 * 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_values.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_VALUE *value, const AQH_VALUE *srcValue);



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

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

  uh=AQH_ObjectsHttpUrlHandler_new(sv,
                                   AQHOME_HTTP_PERMS_LIST_VALUES,
                                   AQHOME_HTTP_PERMS_ADD_VALUE,
                                   AQHOME_HTTP_PERMS_DEL_VALUE,
                                   AQHOME_HTTP_PERMS_EDIT_VALUE,
                                   "/values/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_VALUE *newValue;
  const char *valueName;
  int rv;

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

  newValue=AQH_Value_fromDb(db);

  valueName=AQH_Value_GetNameForSystem(newValue);
  if (!(valueName && *valueName)) {
    DBG_INFO(NULL, "Missing value name");
    AQH_Value_free(newValue);
    return GWEN_ERROR_INVALID;
  }

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

  if (id>0) {
    AQH_VALUE *value;

    DBG_INFO(NULL, "Edit existing value");
    value=AQH_Storage_GetValueById(sto, id);
    if (value==NULL) {
      AqHomeHttpService_UnlockStorage(sv);
      DBG_ERROR(NULL, "Value %d not found", id);
      AQH_Value_free(newValue);
      return GWEN_ERROR_NOT_FOUND;
    }
    AQH_Value_SetId(value, id);
    _setFromObject(value, newValue);
    AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED);
  }
  else {
    AQH_VALUE *value;

    DBG_INFO(NULL, "Adding new value");
    value=AQH_Storage_GetValueByName(sto, valueName);
    if (value) {
      AqHomeHttpService_UnlockStorage(sv);
      DBG_ERROR(NULL, "Value %s exists", valueName);
      AQH_Value_free(newValue);
      return GWEN_ERROR_FOUND;
    }
    value=AQH_Value_new();
    AQH_Value_SetId(value, 0);
    _setFromObject(value, newValue);
    AQH_Storage_AddValue(sto, value);
    AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED);
  }
  AQH_Value_free(newValue);

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



void _setFromObject(AQH_VALUE *value, const AQH_VALUE *srcValue)
{
  AQH_Value_SetName(value, AQH_Value_GetName(srcValue));
  AQH_Value_SetTopicId(value, AQH_Value_GetTopicId(srcValue));
  AQH_Value_SetValueType(value, AQH_Value_GetValueType(srcValue));
  AQH_Value_SetValueUnits(value, AQH_Value_GetValueUnits(srcValue));
  AQH_Value_SetDataPath(value, AQH_Value_GetDataPath(srcValue));
}



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

  sv=AQH_HttpUrlHandler_GetHttpService(uh);
  sto=AqHomeHttpService_GetStorage(sv);
  
  value=AQH_Storage_GetValueById(sto, id);
  if (value) {
    GWEN_DB_NODE *db;
  
    db=GWEN_DB_Group_new("value");
    AQH_Value_toDb(value, 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=\"/values/add\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">",
			 I18N("Add Value"));
  _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=\"/values/edit/%lu\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">",
			 I18N("Edit Value"),
			 (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 AQH_MQTT_TOPIC_LIST *topicList;
  unsigned long int selectedTopicId=0;
  char numbuf[16];

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

  selectedTopicId=(unsigned long int)(dbValues?GWEN_DB_GetIntValue(dbValues, "TopicId", 0, 0):0);
  snprintf(numbuf, sizeof(numbuf)-1, "%lu", selectedTopicId);
  numbuf[sizeof(numbuf)-1]=0;

  GWEN_Buffer_AppendArgs(pageBuf,
			 "  <table>"
			 "    <tr>"
			 "      <td><label for=\"name\">%s: </label></td>"
			 "      <td><input type=\"text\" name=\"name\" value=\"%s\" required></td>"
                         "    </tr>",
                         I18N("Name"),
                         dbValues?GWEN_DB_GetCharValue(dbValues, "name", 0, ""):"");
  GWEN_Buffer_AppendArgs(pageBuf,
                         "<tr><td><label for=\"topicId\">%s: </label></td>"
                         "<td><select id=\"topicId\" name=\"topicId\">",
                         I18N("Topic"));
  GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"0\">%s</option>", I18N("-- select topic --"));

  if (topicList) {
    const AQH_MQTT_TOPIC *topic;

    topic=AQH_MqttTopic_List_First(topicList);
    while(topic) {
      const char *topicName;

      topicName=AQH_MqttTopic_GetTopic(topic);
      if (topicName && *topicName) {
        snprintf(numbuf, sizeof(numbuf)-1, "%lu", (unsigned long int) AQH_MqttTopic_GetId(topic));
        numbuf[sizeof(numbuf)-1]=0;
        if (selectedTopicId && AQH_MqttTopic_GetId(topic)==selectedTopicId)
          GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%s\" selected>%s</option>", numbuf, topicName);
        else
          GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%s\">%s</option>", numbuf, topicName);
      }
      topic=AQH_MqttTopic_List_Next(topic);
    }
  }
  GWEN_Buffer_AppendString(pageBuf, "</select></td></tr>");

  GWEN_Buffer_AppendArgs(pageBuf,
                         "    <tr>"
			 "      <td><label for=\"valueUnits\">%s: </label></td>"
			 "      <td><input type=\"text\" name=\"valueUnits\" value=\"%s\"></td>"
                         "    </tr>",
                         I18N("Units"),
                         dbValues?GWEN_DB_GetCharValue(dbValues, "valueUnits", 0, ""):"");
  GWEN_Buffer_AppendArgs(pageBuf,
                         "    <tr>"
                         "      <td><label for=\"dataPath\">%s: </label></td>"
                         "      <td><input type=\"text\" name=\"dataPath\" value=\"%s\"></td>"
                         "    </tr>"
                         "  </table>",
                         I18N("Data Path (JSON)"),
                         dbValues?GWEN_DB_GetCharValue(dbValues, "dataPath", 0, ""):"");
}



void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf)
{
  AQH_SERVICE *sv;
  AQH_STORAGE *sto;
  const AQH_VALUE_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>%s</th><th></th></tr>"
			 "</thead>",
			 I18N("Values"),
			 I18N("Name"),
			 I18N("Topic"),
			 I18N("Units"),
			 I18N("Data Path"));
  GWEN_Buffer_AppendString(pageBuf, "<tbody>");
  rl=AQH_Storage_GetValueList(sto);
  if (rl) {
    const AQH_VALUE *value;

    value=AQH_Value_List_First(rl);
    while(value) {
      long unsigned int id;
      int topicId;
      const char *name;
      const char *topicName=NULL;
      const char *valueUnits;
      const char *dataPath;
      const AQH_MQTT_TOPIC *topic=NULL;

      id=(long unsigned int) AQH_Value_GetId(value);
      topicId=(long unsigned int) AQH_Value_GetTopicId(value);
      if (topicId>0)
        topic=AQH_Storage_GetMqttTopicById(sto, topicId);
      if (topic)
        topicName=AQH_MqttTopic_GetTopic(topic);

      name=AQH_Value_GetName(value);
      valueUnits=AQH_Value_GetValueUnits(value);
      dataPath=AQH_Value_GetDataPath(value);
      GWEN_Buffer_AppendArgs(pageBuf,
                             "<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td>"
                             "<td><a href=\"/values/edit/%lu\">"
                             "<IMG src=\"/pics/edit.png\" width=32 height=32 align=left border=0></a></td>"
                             "</tr>",
                             name?name:"",
                             topicName?topicName:"",
                             valueUnits?valueUnits:"",
                             dataPath?dataPath:"",
                             id);
      value=AQH_Value_List_Next(value);
    }
  }
  GWEN_Buffer_AppendString(pageBuf, "</tbody>");
  GWEN_Buffer_AppendArgs(pageBuf, "</table><a href=\"/values/add\">%s</a><br>", I18N("Add Value"));
}





