/*
 * main.c
 * WiFi Data Elements Collector (proxy).
 *
 * Copyright (C) 2020i-2023 IOPSYS Software Solutions AB. All rights reserved.
 *
 * Author: anjan.chanda@iopsys.eu
 *
 * See LICENSE file for license related information.
 *
 */

#include "debug.h"
#include "decollector.h"
#include "utils.h"
#include "wifi_dataelements.h"

#include <easymesh.h>

#include <libubus.h>
#include <libubox/uloop.h>
#include <libubox/utils.h>

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "version.h"

#ifdef DECOLLECTOR_BUILD_TR181_PLUGIN
#include <libbbfdm-ubus/bbfdm-ubus.h>

extern DM_MAP_OBJ tDynamicObj[]; /* Global data model structure */

struct wifi_data_element *bbfdm_wifi_de = NULL; /* Global data element structure */
uint32_t bbfdm_collect_interval = DECOLLECTOR_REFRESH_INT; /* Automatic refresh interval in seconds */
#endif

bool syslogging = false;

extern int decollector_init(void **priv, const struct decollector_useropts *opts);
extern int decollector_exit(void *priv);

static void usage(void)
{
	fprintf(stderr, "Usage: decollector [options]\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "options:\n");
	fprintf(stderr, "   -h               usage\n");
	fprintf(stderr, "   -D               run in the background as a daemon\n");
	fprintf(stderr, "   -s <socket path> ubus socket\n");
	fprintf(stderr, "   -t <seconds>,    collection interval in seconds\n");
	fprintf(stderr, "   -d,              debug mode; more 'd's more verbose\n");
	fprintf(stderr, "   -l               log to syslog\n");
	fprintf(stderr, "   -p <pidfile>     pid file path\n");
	fprintf(stderr, "   -r               Multi-AP profile: 1, 2 or 3\n");
	fprintf(stderr, "   -v               show version\n");
	fprintf(stderr, "\n");
}

static void print_version(void)
{
	printf("decollector: version '%s-g%s'\n", verstring, githash);
}

int main(int argc, char **argv)
{
#if (EASYMESH_VERSION > 2)
	const int SUPPORTED_MAP_PROFILE = MULTIAP_PROFILE_3;
#else
	const int SUPPORTED_MAP_PROFILE = MULTIAP_PROFILE_2;
#endif
	struct decollector_useropts opts = {
		.ubus_sockpath = NULL,
		.pidfile = DECOLLECTOR_PIDFILE,
		.objname = WIFI_DATAELEMENTS_OBJECT,
		.daemonize = false,
		.debug_level = 0,
		.syslogging = false,
		.logfile = NULL,
		.logfile_isfifo = false,
		.refresh_int = DECOLLECTOR_REFRESH_INT,
		.em_profile = SUPPORTED_MAP_PROFILE,
	};
	void *decollector_handle;
	int ret;
	int ch;
	char *endptr = NULL;
#ifdef DECOLLECTOR_BUILD_TR181_PLUGIN
	struct bbfdm_context bbfdm_ctx = {0};
	int dm_type = 0;
#endif

	while ((ch = getopt(argc, argv, "hvDt:dlp:s:r:o:fc")) != -1) {
		switch (ch) {
		case 'h':
			usage();
			exit(0);
		case 'v':
			print_version();
			exit(0);
		case 's':
			opts.ubus_sockpath = optarg;
			break;
		case 't':
			errno = 0;
			opts.refresh_int = strtol(optarg, &endptr, 10);
			if (errno || *endptr != '\0' ||
					opts.refresh_int < DECOLLECTOR_REFRESH_INT) {
				fprintf(stderr, "Invalid refresh interval: %s, using default\n", optarg);
				opts.refresh_int = DECOLLECTOR_REFRESH_INT;
			}
			break;
		case 'd':
			opts.debug_level++;
			break;
		case 'c':
#ifdef DECOLLECTOR_BUILD_TR181_PLUGIN
			dm_type++;
#endif
			break;
		case 'D':
			opts.daemonize = true;
			break;
		case 'l':
			opts.syslogging = true;
			break;
		case 'p':
			opts.pidfile = optarg;
			break;
		case 'r':
			errno = 0;
			opts.em_profile = strtol(optarg, &endptr, 10);
			if (errno || *endptr != '\0') {
				fprintf(stderr, "Invalid Multi-AP profile: %s\n", optarg);
				opts.em_profile = 0;
			}
			break;
		case 'o':
			opts.logfile = optarg;
			break;
		case 'f':
			opts.logfile_isfifo = true;
			break;
		default:
			break;
		}
	}

#ifdef DECOLLECTOR_BUILD_TR181_PLUGIN
	memset(&bbfdm_ctx, 0, sizeof(struct bbfdm_context));
	bbfdm_ubus_set_service_name(&bbfdm_ctx, SERVICE_NAME);
	bbfdm_ubus_set_log_level(opts.debug_level + 2);
	bbfdm_ubus_load_data_model(tDynamicObj);

	if (dm_type > 0) {
		int res = bbfdm_print_data_model_schema(&bbfdm_ctx, dm_type);
		exit(res);
	}
#endif

	/* By default use highest profile supported by build */
	if (opts.em_profile == 0 || opts.em_profile > SUPPORTED_MAP_PROFILE)
		opts.em_profile = SUPPORTED_MAP_PROFILE;

	fprintf(stderr, "Highest Multi-AP profile supported = %u\n", opts.em_profile);

	argc -= optind;
	argv += optind;

	if (opts.daemonize)
		do_daemonize(opts.pidfile);

	start_logging(&opts);

	ret = decollector_init(&decollector_handle, &opts);
	if (ret) {
		err("decollector: Failed to start.\n");
		goto out_exit;
	}

#ifdef DECOLLECTOR_BUILD_TR181_PLUGIN
	struct decollector_private *p = (struct decollector_private *)decollector_handle;

	bbfdm_collect_interval = opts.refresh_int;
	bbfdm_wifi_de = p->dm;
	bbfdm_ctx.ubus_ctx = p->ctx;

	ret = bbfdm_ubus_register_init(&bbfdm_ctx);
	if (ret) {
		err("decollector: Failed to register data model.\n");
		goto out_exit;
	}
#endif

	uloop_run();

out_exit:
	stop_logging();
#ifdef DECOLLECTOR_BUILD_TR181_PLUGIN
	bbfdm_ubus_register_free(&bbfdm_ctx);
#endif
	decollector_exit(decollector_handle);
	return 0;
}
