/*
 * service_graph_collect.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 <stdlib.h>
#include <stdint.h>
#include <string.h>

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

#include <skalibs/stralloc.h>

#include <66/service.h>
#include <66/resolve.h>
#include <66/sanitize.h>
#include <66/state.h>
#include <66/graph.h>
#include <66/enum.h>

/** list all services of the system dependending of the flag passed.
 * STATE_FLAGS_TOPARSE -> call sanitize_source
 * STATE_FLAGS_TOPROPAGATE -> it build with the dependencies/requiredby services.
 * STATE_FLAGS_ISSUPERVISED -> only keep already supervised service*/
void service_graph_collect(graph_t *g, char const *alist, size_t alen, resolve_service_t *ares, unsigned int *areslen, ssexec_t *info, uint32_t flag)
{
    log_flow () ;

    int r ;
    size_t pos = 0 ;
    ss_state_t ste = STATE_ZERO ;
    stralloc sa = STRALLOC_ZERO ;

    resolve_wrapper_t_ref wres = 0 ;

    for (; pos < alen ; pos += strlen(alist + pos) + 1) {

        char const *name = alist + pos ;

        if (service_resolve_array_search(ares, (*areslen), name) < 0) {

            resolve_service_t res = RESOLVE_SERVICE_ZERO ;
            /** need to make a copy of the resolve due of the freed
             * of the wres struct at the end of the process */
            resolve_service_t cp = RESOLVE_SERVICE_ZERO ;
            wres = resolve_set_struct(DATA_SERVICE, &res) ;

            /** double pass with resolve_read.
             * The service may already exist, respects the treename before the
             * call of sanitize_source if the -t option was not set by user.
             * The service do not exist yet, sanitize it with sanitize_source
             * and read again the resolve file to know the change */
            r = resolve_read_g(wres, info->base.s, name) ;
            if (r < 0)
                log_dieu(LOG_EXIT_SYS, "read resolve file: ", name) ;

            if (r) {

                if (!info->opt_tree) {

                    info->treename.len = 0 ;

                    if (!auto_stra(&info->treename, res.sa.s + res.treename))
                        log_die_nomem("stralloc") ;
                }

            } else if (FLAGS_ISSET(flag, STATE_FLAGS_TOPARSE)) {

                sanitize_source(name, info) ;

            } else
                continue ;

            if (resolve_read_g(wres, info->base.s, name) <= 0)
                log_dieu(LOG_EXIT_SYS, "read resolve file of: ", name, " -- please make a bug report") ;

            if (!state_read(&ste, &res))
                log_dieu(LOG_EXIT_SYS, "read state file of: ", name, " -- please make a bug report") ;

            if (FLAGS_ISSET(flag, STATE_FLAGS_ISEARLIER)) {

                if (res.earlier) {

                    if (!service_resolve_copy(&cp, &res))
                        log_dieu(LOG_EXIT_SYS, "copy resolve file of: ", name, " -- please make a bug report") ;

                    ares[(*areslen)++] = cp ;
                    continue ;
                }
                resolve_free(wres) ;
                continue ;
            }

            if (FLAGS_ISSET(flag, STATE_FLAGS_ISSUPERVISED)) {

                if (ste.issupervised == STATE_FLAGS_TRUE) {

                    if (!service_resolve_copy(&cp, &res))
                        log_dieu(LOG_EXIT_SYS, "copy resolve file of: ", name, " -- please make a bug report") ;

                    ares[(*areslen)++] = cp ;

                } else {

                    resolve_free(wres) ;
                    continue ;
                }

            } else {

                if (!service_resolve_copy(&cp, &res))
                    log_dieu(LOG_EXIT_SYS, "copy resolve file of: ", name, " -- please make a bug report") ;

                ares[(*areslen)++] = cp ;
            }

            if (FLAGS_ISSET(flag, STATE_FLAGS_TOPROPAGATE)) {

                if (res.dependencies.ndepends && FLAGS_ISSET(flag, STATE_FLAGS_WANTUP)) {

                    sa.len = 0 ;

                    if (!sastr_clean_string(&sa, res.sa.s + res.dependencies.depends))
                        log_dieu(LOG_EXIT_SYS, "clean string") ;

                    service_graph_collect(g, sa.s, sa.len, ares, areslen, info, flag) ;

                }

                if (res.dependencies.nrequiredby && FLAGS_ISSET(flag, STATE_FLAGS_WANTDOWN)) {

                    sa.len = 0 ;

                    if (!sastr_clean_string(&sa, res.sa.s + res.dependencies.requiredby))
                        log_dieu(LOG_EXIT_SYS, "clean string") ;

                    service_graph_collect(g, sa.s, sa.len, ares, areslen, info, flag) ;
                }

            }
            resolve_free(wres) ;
        }
    }

    stralloc_free(&sa) ;
}