/*
 * This file is part of the weatherdaemon project.
 * Copyright 2025 Edward V. Emelianov <edward.emelianoff@gmail.com>.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h> // wait
#include <sys/prctl.h> //prctl
#include <usefull_macros.h>

#include "cmdlnopts.h"
#include "mainweather.h"
#include "sensors.h"
#include "server.h"

static pid_t childpid = 0;
static glob_pars *GP = NULL;

// SIGUSR1 - FORBID observations
// SIGUSR2 - allow
void signals(int signo){
    if(signo){
        if(signals != signal(signo, SIG_IGN)) exit(signo); // function called "as is", before sig registration
        if(childpid == 0){ // child -> test USR1/USR2
            LOGDBG("Child gotta signal %d", signo);
            if(signo == SIGUSR1){
                forbid_observations(1);
                LOGWARN("Got signal `observations forbidden`, set FORBIDDEN");
                signal(signo, signals);
                return;
            }else if(signo == SIGUSR2){
                forbid_observations(0);
                LOGWARN("Got signal `observations permitted`, clear FORBIDDEN");
                signal(signo, signals);
                return;
            }
        }
    }
    if(childpid){ // master
        LOGERR("Main process exits with status %d", signo);
        if(GP && GP->pidfile) unlink(GP->pidfile);
    }else{ // child
        LOGERR("Killed with status %d", signo);
        closeplugins();
        kill_servers();
    }
    usleep(1000); // let child close everything before dead
    exit(signo);
}

static void getpipe(int _U_ signo){
    WARNX("Get sigpipe!");
    LOGWARN("SIGPIPE: something disconnected?");
    // TODO: check all sensors for disconnected one
    signal(SIGPIPE, getpipe);
}

int main(int argc, char **argv){
    sl_init();
    GP = parse_args(argc, argv);
    if(!GP) ERRX("Error parsing args");
    sl_check4running((char*)__progname, GP->pidfile);
    if(!GP->sockname) ERRX("Point command socket name");
    if(GP->logfile){
        sl_loglevel_e lvl = LOGLEVEL_ERR + GP->verb;
        if(lvl >= LOGLEVEL_AMOUNT) lvl = LOGLEVEL_AMOUNT - 1;
        DBG("Loglevel: %d", lvl);
        if(!OPENLOG(GP->logfile, lvl, 1)) ERRX("Can't open log file");
        LOGMSG("Started");
    }
    if(GP->pollt > 0){
        if(!set_pollT((time_t)GP->pollt)) ERRX("Can't set polling time to %d seconds", GP->pollt);
    }
    signal(SIGTERM, signals); // kill (-15) - quit
    signal(SIGHUP, SIG_IGN);  // hup - ignore
    signal(SIGINT, signals);  // ctrl+C - quit
    signal(SIGQUIT, signals); // ctrl+\ - quit
    signal(SIGTSTP, SIG_IGN); // ignore ctrl+Z
    signal(SIGPIPE, getpipe); // socket disconnected
    signal(SIGUSR1, SIG_IGN);
    signal(SIGUSR2, SIG_IGN);
    #ifndef EBUG
    sl_daemonize();
    while(1){ // guard for dead processes
        childpid = fork();
        if(childpid){
            LOGDBG("create child with PID %d\n", childpid);
            DBG("Created child with PID %d\n", childpid);
            wait(NULL);
            WARNX("Child %d died\n", childpid);
            LOGWARN("Child %d died\n", childpid);
            sleep(1);
        }else{
            prctl(PR_SET_PDEATHSIG, SIGTERM); // send SIGTERM to child when parent dies
            break; // go out to normal functional
        }
    }
    #endif
    int nopened = openplugins(GP->plugins, GP->nplugins);
    if(nopened < 1){
        LOGERR("No plugins found; exit!");
        ERRX("Can't find any sensor plugin");
    }
    if(GP->nplugins && GP->nplugins != nopened) LOGWARN("Work without some plugins");
    // react for USRx only in child
    signal(SIGUSR1, signals);
    signal(SIGUSR2, signals);
    if(!start_servers(GP->port, GP->sockname)) ERRX("Can't run server's threads");
    //while(1) pause();
    //WARNX("TEST ends");
    //signals(0);
    return 0; // never reached
}
