/*
 * service_resolve_setnwrite.c
 *
 * Copyright (c) 2018-2021 Eric Vidal <eric@obarun.org>
 *
 * All rights reserved.
 *
 * This file is part of Obarun. It is subject to the license terms in
 * the LICENSE file found in the top-level directory of this
 * distribution.
 * This file may not be copied, modified, propagated, or distributed
 * except according to the terms contained in the LICENSE file./
 */

#include <string.h>

#include <oblibs/log.h>
#include <oblibs/string.h>

#include <skalibs/types.h>
#include <skalibs/stralloc.h>

#include <66/enum.h>
#include <66/constants.h>
#include <66/resolve.h>
#include <66/state.h>
#include <66/ssexec.h>
#include <66/parser.h>
#include <66/utils.h>
#include <66/service.h>

int service_resolve_setnwrite(sv_alltype *services, ssexec_t *info, char const *dst)
{
    log_flow() ;

    int e = 0 ;
    char ownerstr[UID_FMT] ;
    size_t ownerlen = uid_fmt(ownerstr,info->owner), id, nid ;
    ownerstr[ownerlen] = 0 ;

    stralloc destlog = STRALLOC_ZERO ;
    stralloc ndeps = STRALLOC_ZERO ;
    stralloc other_deps = STRALLOC_ZERO ;

    ss_state_t sta = STATE_ZERO ;
    resolve_service_t res = RESOLVE_SERVICE_ZERO ;
    resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, &res) ;

    resolve_init(wres) ;

    char *name = keep.s + services->cname.name ;
    size_t namelen = strlen(name) ;
    char logname[namelen + SS_LOG_SUFFIX_LEN + 1] ;
    char logreal[namelen + SS_LOG_SUFFIX_LEN + 1] ;
    char stmp[info->livetree.len + 1 + info->treename.len + SS_SVDIRS_LEN + 1 + namelen + SS_LOG_SUFFIX_LEN + 1] ;

    size_t livelen = info->live.len - 1 ;
    char state[livelen + SS_STATE_LEN + 1 + ownerlen + 1 + info->treename.len + 1 + namelen + 1] ;
    auto_strings(state, info->live.s, SS_STATE, "/", ownerstr, "/", info->treename.s) ;


    res.type = services->cname.itype ;
    res.name = resolve_add_string(wres,name) ;
    res.description = resolve_add_string(wres,keep.s + services->cname.description) ;
    res.version = resolve_add_string(wres,keep.s + services->cname.version) ;
    res.tree = resolve_add_string(wres,info->tree.s) ;
    res.treename = resolve_add_string(wres,info->treename.s) ;
    res.live = resolve_add_string(wres,info->live.s) ;
    res.state = resolve_add_string(wres,state) ;
    res.src = resolve_add_string(wres,keep.s + services->src) ;

    if (services->srconf > 0)
        res.srconf = resolve_add_string(wres,keep.s + services->srconf) ;

    if (res.type == TYPE_ONESHOT) {

        if (services->type.oneshot.up.exec >= 0) {

            res.exec_run = resolve_add_string(wres,keep.s + services->type.oneshot.up.exec) ;
            res.real_exec_run = resolve_add_string(wres,keep.s + services->type.oneshot.up.real_exec) ;
        }

        if (services->type.oneshot.down.exec >= 0) {

            res.exec_finish = resolve_add_string(wres,keep.s + services->type.oneshot.down.exec) ;
            res.real_exec_finish = resolve_add_string(wres,keep.s + services->type.oneshot.down.real_exec) ;
        }
    }

    if (res.type == TYPE_CLASSIC || res.type == TYPE_LONGRUN) {

        if (services->type.classic_longrun.run.exec >= 0) {
            res.exec_run = resolve_add_string(wres,keep.s + services->type.classic_longrun.run.exec) ;
            res.real_exec_run = resolve_add_string(wres,keep.s + services->type.classic_longrun.run.real_exec) ;
        }

        if (services->type.classic_longrun.finish.exec >= 0) {

            res.exec_finish = resolve_add_string(wres,keep.s + services->type.classic_longrun.finish.exec) ;
            res.real_exec_finish = resolve_add_string(wres,keep.s + services->type.classic_longrun.finish.real_exec) ;
        }
    }

    res.ndepends = services->cname.nga ;
    res.noptsdeps = services->cname.nopts ;
    res.nextdeps = services->cname.next ;
    res.ncontents = services->cname.ncontents ;

    if (services->flags[0])
        res.down = 1 ;

    res.disen = 1 ;

    if (res.type == TYPE_CLASSIC) {

        auto_strings(stmp, info->scandir.s, "/", name) ;
        res.runat = resolve_add_string(wres,stmp) ;

    } else if (res.type >= TYPE_BUNDLE) {

        auto_strings(stmp, info->livetree.s, "/", info->treename.s, SS_SVDIRS, "/", name) ;
        res.runat = resolve_add_string(wres,stmp) ;
    }

    if (state_check(state,name)) {

        if (!state_read(&sta,state,name)) {
            log_warnusys("read state file of: ",name) ;
            goto err ;
        }

        if (!sta.init)
            state_setflag(&sta,SS_FLAGS_RELOAD,SS_FLAGS_TRUE) ;

        if (sta.init) {

            state_setflag(&sta,SS_FLAGS_INIT,SS_FLAGS_TRUE) ;

        } else {

            state_setflag(&sta,SS_FLAGS_INIT,SS_FLAGS_FALSE) ;
        }

        state_setflag(&sta,SS_FLAGS_UNSUPERVISE,SS_FLAGS_FALSE) ;

        if (!state_write(&sta,res.sa.s + res.state,name)) {
            log_warnusys("write state file of: ",name) ;
            goto err ;
        }
    }

    if (res.ndepends)
    {
        id = services->cname.idga, nid = res.ndepends ;
        for (;nid; id += strlen(deps.s + id) + 1, nid--) {

            if (!stralloc_catb(&ndeps,deps.s + id,strlen(deps.s + id)) ||
                !stralloc_catb(&ndeps," ",1)) {
                    log_warnsys("stralloc") ;
                    goto err ;
                }
        }
        ndeps.len-- ;

        if (!stralloc_0(&ndeps)) {
            log_warnsys("stralloc") ;
            goto err ;
        }

        res.depends = resolve_add_string(wres,ndeps.s) ;
    }

    if (res.noptsdeps)
    {
        id = services->cname.idopts, nid = res.noptsdeps ;
        for (;nid; id += strlen(deps.s + id) + 1, nid--) {

            if (!stralloc_catb(&other_deps,deps.s + id,strlen(deps.s + id)) ||
                !stralloc_catb(&other_deps," ",1)) {
                    log_warnsys("stralloc") ;
                    goto err ;
                }
        }
        other_deps.len-- ;

        if (!stralloc_0(&other_deps)) {
            log_warnsys("stralloc") ;
            goto err ;
        }

        res.optsdeps = resolve_add_string(wres,other_deps.s) ;
    }

    if (res.nextdeps)
    {
        other_deps.len = 0 ;
        id = services->cname.idext, nid = res.nextdeps ;
        for (;nid; id += strlen(deps.s + id) + 1, nid--) {

            if (!stralloc_catb(&other_deps,deps.s + id,strlen(deps.s + id)) ||
                !stralloc_catb(&other_deps," ",1)){
                    log_warnsys("stralloc") ;
                    goto err ;
                }
        }
        other_deps.len-- ;

        if (!stralloc_0(&other_deps)){
            log_warnsys("stralloc") ;
            goto err ;
        }

        res.extdeps = resolve_add_string(wres,other_deps.s) ;
    }

    if (res.ncontents) {

        other_deps.len = 0 ;
        id = services->cname.idcontents, nid = res.ncontents ;
        for (;nid; id += strlen(deps.s + id) + 1, nid--) {

            if (!stralloc_catb(&other_deps,deps.s + id,strlen(deps.s + id)) ||
                !stralloc_catb(&other_deps," ",1)) {
                    log_warnsys("stralloc") ;
                    goto err ;
                }
        }
        other_deps.len-- ;
        if (!stralloc_0(&other_deps)) {
            log_warnsys("stralloc") ;
            goto err ;
        }
        res.contents = resolve_add_string(wres,other_deps.s) ;
    }

    if (services->opts[0]) {

        // destination of the logger
        if (services->type.classic_longrun.log.destination < 0) {

            if(info->owner > 0) {

                if (!auto_stra(&destlog, get_userhome(info->owner), "/", SS_LOGGER_USERDIR, name)) {
                    log_warnsys("stralloc") ;
                    goto err ;
                }

            } else {

                if (!auto_stra(&destlog, SS_LOGGER_SYSDIR, name)) {
                    log_warnsys("stralloc") ;
                    goto err ;
                }
            }

        } else {

            if (!auto_stra(&destlog,keep.s + services->type.classic_longrun.log.destination)) {
                log_warnsys("stralloc") ;
                goto err ;
            }
        }

        res.dstlog = resolve_add_string(wres,destlog.s) ;

        if ((res.type == TYPE_CLASSIC) || (res.type == TYPE_LONGRUN)) {

            auto_strings(logname, name, SS_LOG_SUFFIX) ;
            auto_strings(logreal, name) ;

            if (res.type == TYPE_CLASSIC) {
                auto_strings(logreal + namelen, "/log") ;

            } else {

                auto_strings(logreal + namelen,"-log") ;
            }

            res.logger = resolve_add_string(wres,logname) ;
            res.logreal = resolve_add_string(wres,logreal) ;
            if (ndeps.len)
                ndeps.len--;

            if (!stralloc_catb(&ndeps," ",1) ||
                !stralloc_cats(&ndeps,res.sa.s + res.logger) ||
                !stralloc_0(&ndeps)) {
                    log_warnsys("stralloc") ;
                    goto err ;
                }

            res.depends = resolve_add_string(wres,ndeps.s) ;

            if (res.type == TYPE_CLASSIC) {

                res.ndepends = 1 ;

            } else if (res.type == TYPE_LONGRUN) {

                res.ndepends += 1 ;
            }

            if (services->type.classic_longrun.log.run.exec >= 0)
                res.exec_log_run = resolve_add_string(wres,keep.s + services->type.classic_longrun.log.run.exec) ;

            if (services->type.classic_longrun.log.run.real_exec >= 0)
                res.real_exec_log_run = resolve_add_string(wres,keep.s + services->type.classic_longrun.log.run.real_exec) ;

            if (!service_resolve_setlognwrite(&res,dst))
                goto err ;
        }
    }

    if (!resolve_write(wres,dst,res.sa.s + res.name)) {

        log_warnusys("write resolve file: ",dst,SS_RESOLVE,"/",res.sa.s + res.name) ;
        goto err ;
    }

    e = 1 ;

    err:
        resolve_free(wres) ;
        stralloc_free(&ndeps) ;
        stralloc_free(&other_deps) ;
        stralloc_free(&destlog) ;
        return e ;
}