/****************************************************************************
 * 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 "./init_http.h"
#include "./aqhomestorage_p.h"
#include "./aqhomehttp.h"
#include "./u_login.h"
#include "./u_rooms.h"
#include "./u_devices.h"
#include "./u_mqtttopics.h"
#include "./u_values.h"
#include "./u_static.h"

#include "aqhome/msg/endpoint_tty.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/mqtt/endpoint_mqttc.h"
#include "aqhome/http/endpoint_http.h"
#include "aqhome/http/httpservice_conf.h"
#include "aqhome/http/httpservice_http.h"
#include "aqhome/http/httpservice.h"
#include "aqhome/http/content_files.h"

#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
#include <gwenhywfar/endpoint_msgio.h>
#include <gwenhywfar/directory.h>

#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif

#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif

#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <time.h>



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

//#define I18N(msg) msg
#define I18S(msg) msg



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

static void _setupEndpoint(AQHOME_STORAGE *aqh, const char *tcpAddress, int tcpPort);
static int _setupHttpService(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs);
static int _createContentRoot(AQHOME_STORAGE *aqh);
static GWEN_MSG_ENDPOINT *_acceptHttpFn(GWEN_MSG_ENDPOINT *ep, GWEN_SOCKET *sk, const GWEN_INETADDRESS *addr, void *data);

static int _createUrlHandler_login(AQHOME_STORAGE *aqh);
static int _createUrlHandler_rooms(AQHOME_STORAGE *aqh);
static int _createUrlHandler_devices(AQHOME_STORAGE *aqh);
static int _createUrlHandler_topics(AQHOME_STORAGE *aqh);
static int _createUrlHandler_values(AQHOME_STORAGE *aqh);
static int _createUrlHandler_static(AQHOME_STORAGE *aqh);



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

int AqHomeStorage_SetupHttp(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs)
{
  const char *tcpAddress;
  int tcpPort;

  tcpAddress=GWEN_DB_GetCharValue(dbArgs, "httpAddress", 0, NULL);
  tcpPort=GWEN_DB_GetIntValue(dbArgs, "httpPort", 0, AQHOME_STORAGE_DEFAULT_HTTP_PORT);

  if (tcpAddress && *tcpAddress && tcpPort) {
    int rv;

    _setupEndpoint(aqh, tcpAddress, tcpPort);
    rv=_setupHttpService(aqh, dbArgs);
    if (rv<0) {
      DBG_INFO(NULL, "here (%d)", rv);
      return rv;
    }

    rv=_createContentRoot(aqh);
    if (rv<0) {
      DBG_INFO(NULL, "here (%d)", rv);
      return rv;
    }

    rv=_createUrlHandler_login(aqh);
    if (rv<0) {
      DBG_INFO(NULL, "here (%d)", rv);
      return rv;
    }

    rv=_createUrlHandler_rooms(aqh);
    if (rv<0) {
      DBG_INFO(NULL, "here (%d)", rv);
      return rv;
    }

    rv=_createUrlHandler_devices(aqh);
    if (rv<0) {
      DBG_INFO(NULL, "here (%d)", rv);
      return rv;
    }


    rv=_createUrlHandler_topics(aqh);
    if (rv<0) {
      DBG_INFO(NULL, "here (%d)", rv);
      return rv;
    }

    rv=_createUrlHandler_values(aqh);
    if (rv<0) {
      DBG_INFO(NULL, "here (%d)", rv);
      return rv;
    }

    rv=_createUrlHandler_static(aqh);
    if (rv<0) {
      DBG_INFO(NULL, "here (%d)", rv);
      return rv;
    }

  }
  return 0;
}



void _setupEndpoint(AQHOME_STORAGE *aqh, const char *tcpAddress, int tcpPort)
{
  GWEN_MSG_ENDPOINT *ep;

  ep=GWEN_TcpdEndpoint_new(tcpAddress, tcpPort, NULL, 0);
  GWEN_TcpdEndpoint_SetAcceptFn(ep, _acceptHttpFn, aqh);

  GWEN_MsgEndpoint_Tree2_AddChild(aqh->rootEndpoint, ep);
  aqh->httpdEndpoint=ep;
}



int _setupHttpService(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs)
{
  const char *configFolder;
  const char *sourceFolder;
  int rv;

  configFolder=GWEN_DB_GetCharValue(dbArgs, "cfgdir", 0, AQHOME_STORAGE_DEFAULT_CONFIGDIR);
  sourceFolder=GWEN_DB_GetCharValue(dbArgs, "sourceFolder", 0, AQHOME_STORAGE_DEFAULT_HTTP_SOURCEDIR);
  aqh->httpService=AQH_HttpService_new(configFolder, sourceFolder);
  AqHomeHttpService_Extend(aqh->httpService);
  AqHomeHttpService_SetStorage(aqh->httpService, aqh->storage);
  rv=AQH_HttpService_LoadConfig(aqh->httpService);
  if (rv<0) {
    DBG_ERROR(NULL, "Error loading config for HTTP service (%d)", rv);
    return GWEN_ERROR_GENERIC;
  }
  AQH_HttpService_LoadAllSessions(aqh->httpService);
  return 0;
}



GWEN_MSG_ENDPOINT *_acceptHttpFn(GWEN_MSG_ENDPOINT *ep,
                                 GWEN_SOCKET *sk,
                                 const GWEN_INETADDRESS *addr,
                                 GWEN_UNUSED void *data)
{
  GWEN_MSG_ENDPOINT *epIncoming;

  /*  AQHOME_STORAGE *aqh;
 *
 *  aqh=(AQHOME_STORAGE*) data;
 */

  DBG_INFO(NULL, "Incoming HTTP connection");
  epIncoming=GWEN_MsgEndpoint_new("http", 0);
  GWEN_MsgEndpoint_SetSocket(epIncoming, sk);
  GWEN_MsgIoEndpoint_Extend(epIncoming);
  AQH_HttpEndpoint_Extend(epIncoming, AQH_ENDPOINT_HTTP_FLAGS_PASSIVE);
  return epIncoming;
}



int _createContentRoot(AQHOME_STORAGE *aqh)
{
  const char *sourceFolder;
  GWEN_BUFFER *nbuf1;
  GWEN_BUFFER *nbuf2;
  AQH_HTTP_CONTENT *c;

  sourceFolder=AQH_HttpService_GetSourceFolder(aqh->httpService);

  nbuf1=GWEN_Buffer_new(0, 256, 0, 1);
  nbuf2=GWEN_Buffer_new(0, 256, 0, 1);

  GWEN_Buffer_AppendString(nbuf1, sourceFolder);
  GWEN_Buffer_AppendString(nbuf1, GWEN_DIR_SEPARATOR_S AQHOME_STORAGE_SITEHEADER);

  GWEN_Buffer_AppendString(nbuf2, sourceFolder);
  GWEN_Buffer_AppendString(nbuf2, GWEN_DIR_SEPARATOR_S AQHOME_STORAGE_SITEFOOTER);

  c=AQH_HttpContentFiles_new("root", GWEN_Buffer_GetStart(nbuf1), GWEN_Buffer_GetStart(nbuf2));
  if (c==NULL) {
    DBG_INFO(NULL,
	     "Unable to create content for root (header=[%s], footer=[%s])",
	     GWEN_Buffer_GetStart(nbuf1), GWEN_Buffer_GetStart(nbuf2));
    GWEN_Buffer_free(nbuf2);
    GWEN_Buffer_free(nbuf1);
    return GWEN_ERROR_GENERIC;
  }
  AqHomeHttpService_SetContentTree(aqh->httpService, c);

  GWEN_Buffer_free(nbuf2);
  GWEN_Buffer_free(nbuf1);
  return 0;
}



int _createUrlHandler_login(AQHOME_STORAGE *aqh)
{
  AQH_HTTP_URLHANDLER *uh;

  uh=AQH_LoginHttpUrlHandler_new(aqh->httpService);
  AQH_HttpUrlHandler_SetContentProvider(uh, AqHomeHttpService_GetContentTree(aqh->httpService));
  AQH_HttpUrlHandler_AddUrlPattern(uh, "/login");
  AQH_HttpService_AddUrlHandler(aqh->httpService, uh);
  return 0;
}



int _createUrlHandler_rooms(AQHOME_STORAGE *aqh)
{
  AQH_HTTP_URLHANDLER *uh;

  uh=AQH_RoomsHttpUrlHandler_new(aqh->httpService);
  AQH_HttpUrlHandler_SetContentProvider(uh, AqHomeHttpService_GetContentTree(aqh->httpService));
  AQH_HttpUrlHandler_AddUrlPattern(uh, "/rooms/*");
  AQH_HttpService_AddUrlHandler(aqh->httpService, uh);
  return 0;
}



int _createUrlHandler_devices(AQHOME_STORAGE *aqh)
{
  AQH_HTTP_URLHANDLER *uh;

  uh=AQH_DevicesHttpUrlHandler_new(aqh->httpService);
  AQH_HttpUrlHandler_SetContentProvider(uh, AqHomeHttpService_GetContentTree(aqh->httpService));
  AQH_HttpUrlHandler_AddUrlPattern(uh, "/devices/*");
  AQH_HttpService_AddUrlHandler(aqh->httpService, uh);
  return 0;
}



int _createUrlHandler_topics(AQHOME_STORAGE *aqh)
{
  AQH_HTTP_URLHANDLER *uh;

  uh=AQH_MqttTopicsHttpUrlHandler_new(aqh->httpService);
  AQH_HttpUrlHandler_SetContentProvider(uh, AqHomeHttpService_GetContentTree(aqh->httpService));
  AQH_HttpUrlHandler_AddUrlPattern(uh, "/mqtttopics/*");
  AQH_HttpService_AddUrlHandler(aqh->httpService, uh);
  return 0;
}



int _createUrlHandler_values(AQHOME_STORAGE *aqh)
{
  AQH_HTTP_URLHANDLER *uh;

  uh=AQH_ValuesHttpUrlHandler_new(aqh->httpService);
  AQH_HttpUrlHandler_SetContentProvider(uh, AqHomeHttpService_GetContentTree(aqh->httpService));
  AQH_HttpUrlHandler_AddUrlPattern(uh, "/values/*");
  AQH_HttpService_AddUrlHandler(aqh->httpService, uh);
  return 0;
}



int _createUrlHandler_static(AQHOME_STORAGE *aqh)
{
  AQH_HTTP_URLHANDLER *uh;
  GWEN_BUFFER *nameBuf;
  const char *sourceFolder;

  sourceFolder=AQH_HttpService_GetSourceFolder(aqh->httpService);
  nameBuf=GWEN_Buffer_new(0, 256, 0, 1);
  GWEN_Buffer_AppendString(nameBuf, sourceFolder);
  GWEN_Buffer_AppendString(nameBuf, GWEN_DIR_SEPARATOR_S AQHOME_STORAGE_STATIC_RELFOLDER GWEN_DIR_SEPARATOR_S "pics");

  uh=AQH_StaticHttpUrlHandler_new(aqh->httpService, GWEN_Buffer_GetStart(nameBuf));
  GWEN_Buffer_free(nameBuf);
  AQH_HttpUrlHandler_AddUrlPattern(uh, "/pics/*");
  AQH_HttpService_AddUrlHandler(aqh->httpService, uh);
  return 0;
}




