/*
 * Copyright (C) 2023 iopsys Software Solutions AB
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation
 *
 *	  Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
 *
 */

#include "common.h"

void ppp___update_sections(struct uci_section *s_from, struct uci_section *s_to)
{
	char *proto = NULL;
	char *device = NULL;
	char *username = NULL;
	char *password = NULL;
	char *pppd_options = NULL;
	char *service = NULL;
	char *ac = NULL;
	char sec_name[128] = {0};

	dmuci_get_value_by_section_string(s_from, "proto", &proto);
	dmuci_get_value_by_section_string(s_from, "device", &device);
	dmuci_get_value_by_section_string(s_from, "username", &username);
	dmuci_get_value_by_section_string(s_from, "password", &password);
	dmuci_get_value_by_section_string(s_from, "pppd_options", &pppd_options);
	dmuci_get_value_by_section_string(s_from, "service", &service);
	dmuci_get_value_by_section_string(s_from, "ac", &ac);

	if (DM_STRLEN(device) == 0) {
		device = dmstrdup(section_name(s_to));
	}

	dmuci_set_value_by_section(s_to, "proto", proto);
	dmuci_set_value_by_section(s_to, "username", username);
	dmuci_set_value_by_section(s_to, "password", password);
	dmuci_set_value_by_section(s_to, "pppd_options", pppd_options);
	dmuci_set_value_by_section(s_to, "service", service);
	dmuci_set_value_by_section(s_to, "ac", ac);

	dmuci_set_value_by_section(s_to, "device", device);

	snprintf(sec_name, sizeof(sec_name), "%s.%s", section_config(s_to), section_name(s_to));
	struct uci_section *dmmap_s = get_dup_section_in_dmmap_opt("IP", "Interface", "__section_name__", sec_name);
	if (dmmap_s != NULL) {
		dmuci_set_value_by_section(dmmap_s, "device", device);
	}
}

void ppp___reset_options(struct uci_section *ppp_s)
{
	char sec_name[128] = {0};

	dmuci_set_value_by_section(ppp_s, "device", section_name(ppp_s));

	snprintf(sec_name, sizeof(sec_name), "%s.%s", section_config(ppp_s), section_name(ppp_s));
	struct uci_section *dmmap_s = get_dup_section_in_dmmap_opt("IP", "Interface", "__section_name__", sec_name);
	if (dmmap_s != NULL) {
		dmuci_set_value_by_section(dmmap_s, "device", section_name(ppp_s));
	}

	dmuci_set_value_by_section(ppp_s, "username", "");
	dmuci_set_value_by_section(ppp_s, "password", "");
	dmuci_set_value_by_section(ppp_s, "pppd_options", "");
	dmuci_set_value_by_section(ppp_s, "service", "");
	dmuci_set_value_by_section(ppp_s, "ac", "");
}

void firewall__create_zone_section(const char *s_name)
{
	struct uci_section *s = NULL;
	char *input = NULL;
	char *output = NULL;
	char *forward = NULL;

	dmuci_get_option_value_string("firewall", "@defaults[0]", "input", &input);
	dmuci_get_option_value_string("firewall", "@defaults[0]", "output", &output);
	dmuci_get_option_value_string("firewall", "@defaults[0]", "forward", &forward);

	dmuci_add_section("firewall", "zone", &s);
	dmuci_rename_section_by_section(s, s_name);
	dmuci_set_value_by_section(s, "name", s_name);
	dmuci_set_value_by_section(s, "input", input);
	dmuci_set_value_by_section(s, "output", output);
	dmuci_set_value_by_section(s, "forward", forward);

	dmuci_add_list_value_by_section(s, "network", s_name);
}

/* get the name that linux generates based on ifname of tunnel */
void gre___get_tunnel_system_name(struct uci_section *iface_section, char *device_str, size_t device_str_size)
{
	char *proto = NULL;

	if (!iface_section || !device_str || !device_str_size)
		return;

	dmuci_get_value_by_section_string(iface_section, "proto", &proto);

	// to generate appropriate device name
	if (proto && !DM_LSTRCMP(proto, "grev6")) {
		snprintf(device_str, device_str_size, "gre6-%s", section_name(iface_section));
	} else {
		snprintf(device_str, device_str_size, "gre4-%s", section_name(iface_section));
	}
}

bool ip___is_gre_protocols(const char *proto)
{
	if (!DM_LSTRCMP(proto, "gre"))
		return true;

	if (!DM_LSTRCMP(proto, "grev6"))
		return true;

	if (!DM_LSTRCMP(proto, "gretap"))
		return true;

	if (!DM_LSTRCMP(proto, "grev6tap"))
		return true;

	return false;
}

bool ip___is_ip_interface_instance_exists(const char *iface_name, const char *device)
{
	struct uci_section *dmmap_obj = NULL;

	if (DM_STRLEN(device) == 0)
		return false;

	uci_path_foreach_sections(bbfdm, "IP", "Interface", dmmap_obj) {
		char *curr_dev = NULL, *sec_name = NULL, *curr_iface_name = NULL;

		dmuci_get_value_by_section_string(dmmap_obj, "__section_name__", &sec_name);
		struct uci_section *iface_sec = get_config_section_from_dmmap_section_name(sec_name);
		curr_iface_name = section_name(iface_sec);

		dmuci_get_value_by_section_string(dmmap_obj, "device", &curr_dev);
		if (DM_STRCMP(curr_dev, device) == 0 && DM_STRCMP(curr_iface_name, iface_name) != 0)
			return true;
	}

	return false;
}

void ip___update_child_interfaces(const char *device, const char *option_name, const char *option_value)
{
	struct uci_section *s = NULL;

	if (DM_STRLEN(device) == 0)
		return;

	uci_foreach_option_eq("network", "interface", "device", device, s) {
		dmuci_set_value_by_section(s, option_name, option_value);
		if (DM_STRCMP(option_name, "device") == 0) {
			char sec_name[128] = {0};

			snprintf(sec_name, sizeof(sec_name), "network.%s", section_name(s));
			struct uci_section *dmmap_s = get_dup_section_in_dmmap_opt("IP", "Interface", "__section_name__", sec_name);
			if (dmmap_s != NULL) {
				dmuci_set_value_by_section(dmmap_s, option_name, option_value);
			}
		}
	}
}

static void ip___Update_IP_Interface_Layer(const char *path, const char *linker)
{
	struct uci_section *dmmap_s = NULL;

	uci_path_foreach_option_eq(bbfdm, "IP", "Interface", "LowerLayers", path, dmmap_s) {
		struct uci_section *iface_s = NULL;
		char *sec_name = NULL;
		char *curr_device = NULL;

		dmuci_get_value_by_section_string(dmmap_s, "__section_name__", &sec_name);
		if (!DM_STRLEN(sec_name))
			continue;

		iface_s = get_config_section_from_dmmap_section_name(sec_name);
		if (!iface_s)
			continue;

		dmuci_get_value_by_section_string(iface_s, "device", &curr_device);

		ip___update_child_interfaces(curr_device, "device", DM_STRLEN(linker) ? linker : section_name(iface_s));
	}
}

void ppp___Update_PPP_Interface_Top_Layers(const char *path, const char *linker)
{
	char *p = DM_STRRCHR(path, '.');
	if (p) *p = 0;

	// Update IP Interface instance if exists
	ip___Update_IP_Interface_Layer(path, linker);
}
