/****************************************************************************
 * 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.h"
#include "./fini.h"
#include "./loop.h"
#include "./loop_mqtt.h"

#include "aqhome/aqhome.h"

#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/logger.h>
#include <gwenhywfar/db.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/cgui.h>
#include <gwenhywfar/text.h>

#ifdef HAVE_SIGNAL_H
# include <signal.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

#define AQHOME_MQTTLOG_PING_INTERVAL 120
#define AQHOME_MQTTLOG_SAVE_INTERVAL 60

#define FULL_DEBUG



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

static void _serve(AQHOME_MQTT *aqh);

#ifdef HAVE_SIGNAL_H
static int _setSignalHandlers(void);
static int _setupSigAction(struct sigaction *sa, int sig);
static void _signalHandler(int s);
static struct sigaction saINT,saTERM, saHUP, saTSTP, saCONT;
#endif



/* ------------------------------------------------------------------------------------------------
 * static vars
 * ------------------------------------------------------------------------------------------------
 */

static int stopService=0;



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

int main(int argc, char **argv)
{
  AQHOME_MQTT *aqh;
  GWEN_DB_NODE *dbArgs;
  int rv;
  GWEN_GUI *gui;
  const char *s;

  rv=GWEN_Init();
  if (rv) {
    fprintf(stderr, "ERROR: Unable to init Gwen.\n");
    return 2;
  }

  GWEN_Logger_Open(0, "aqhome-mqttlog", 0, GWEN_LoggerType_Console, GWEN_LoggerFacility_User);
  GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Warning);

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

  aqh=AqHomeMqtt_new();
  rv=AqHomeMqtt_Init(aqh, argc, argv);
  if (rv<0) {
    if (rv==GWEN_ERROR_CLOSE)
      return 1;
    DBG_INFO(NULL, "here (%d)", rv);
    return 2;
  }

  dbArgs=AqHomeMqtt_GetDbArgs(aqh);

  gui=GWEN_Gui_CGui_new();
  s=GWEN_DB_GetCharValue(dbArgs, "charset", 0, NULL);
  if (s && *s)
    GWEN_Gui_SetCharSet(gui, s);
  GWEN_Gui_SetGui(gui);

  _serve(aqh);

  AqHomeMqtt_Fini(aqh);
  AqHomeMqtt_free(aqh);

  GWEN_Gui_SetGui(NULL);
  GWEN_Gui_free(gui);

  return 0;
}



void _serve(AQHOME_MQTT *aqh)
{
  int rv;
  int timeout;
  time_t startTime;
  time_t lastPingSendTime;
  time_t lastSaveTime;
  GWEN_DB_NODE *dbArgs;

  startTime=time(NULL);
  lastSaveTime=time(NULL);

  dbArgs=AqHomeMqtt_GetDbArgs(aqh);

  rv=_setSignalHandlers();
  if (rv<0) {
    DBG_ERROR(NULL, "Error setting signal handlers (%d)", rv);
    return;
  }

  timeout=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 0);

  lastPingSendTime=time(NULL);

  while(!stopService) {
    DBG_DEBUG(NULL, "Next loop");
    AqHomeMqttLog_Loop(aqh, 2000);

    if (timeout) {
      time_t now;

      now=time(NULL);
      if ((now-startTime)>timeout) {
        DBG_ERROR(NULL, "Timeout, stopping service");
        break;
      }
    }
    if (1){
      time_t now;

      now=time(NULL);
      if (now-lastPingSendTime>AQHOME_MQTTLOG_PING_INTERVAL) {
        rv=AqHomeMqttLog_SendPing(aqh);
        if (rv<0) {
          DBG_INFO(NULL, "Error sending PING");
        }
        lastPingSendTime=time(NULL);
      }
    }

    if (1){
      time_t now;

      now=time(NULL);
      if (now-lastSaveTime>AQHOME_MQTTLOG_SAVE_INTERVAL) {
        DBG_ERROR(NULL, "Writing device files");
        rv=AqHomeMqtt_SaveRuntimeDeviceFiles(aqh);
        if (rv<0) {
          DBG_INFO(NULL, "Error writing runtime data");
        }
        lastSaveTime=time(NULL);
      }
    }

  } /* while */

  rv=AqHomeMqtt_SaveRuntimeDeviceFiles(aqh);
  if (rv<0) {
    DBG_INFO(NULL, "Error writing runtime data");
  }

}



int _setSignalHandlers(void)
{
#ifdef HAVE_SIGNAL_H
  int rv;

  rv=_setupSigAction(&saINT, SIGINT);
  if (rv)
    return rv;

  rv=_setupSigAction(&saTERM, SIGTERM);
  if (rv)
    return rv;

  rv=_setupSigAction(&saHUP, SIGHUP);
  if (rv)
    return rv;

#  ifdef SIGTSTP
  rv=_setupSigAction(&saTSTP, SIGTSTP);
  if (rv)
    return rv;
#  endif

#  ifdef SIGCONT
  rv=_setupSigAction(&saCONT, SIGCONT);
  if (rv)
    return rv;
#  endif
#endif
  return 0;
}



int _setupSigAction(struct sigaction *sa, int sig)
{
  sa->sa_handler=_signalHandler;
  sigemptyset(&sa->sa_mask);
  sa->sa_flags=0;
  if (sigaction(sig, sa, 0)) {
    DBG_ERROR(NULL, "Could not setup signal handler for signal %d", sig);
    return GWEN_ERROR_IO;
  }

  return 0;
}



void _signalHandler(int s)
{
  switch(s) {
  case SIGINT:
  case SIGTERM:
  case SIGHUP:
    DBG_WARN(0, "Received signal %d, stopping service in next loop.",s);
    stopService=1;
    break;
  default:
    DBG_WARN(0, "Unknown signal %d",s);
    break;
  }
}



