/*
 * gawkpn - a gawk extension for phone number manipulation
 *
 * Copyright 2023 Sxmo Contributors
 * <sxmo.org>
 *
 * 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, version 3 of the License.
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <errno.h>
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <gawkapi.h>

#include "gawkpnimpl.h"

#define make_const_strz(str, result)	r_make_string(api, ext_id, str, (sizeof(str) - 1), 1, result)

int plugin_is_GPL_compatible;

static const gawk_api_t *api;
static awk_ext_id_t ext_id;
static const char *ext_version = NULL;

#if gawk_api_major_version < 2
#	define EXTFN_ARGS int num_actual_args, awk_value_t *result
#else /* gawk_api_major_version >= 2 */
#	define EXTFN_ARGS int num_actual_args, awk_value_t *result, struct awk_ext_func *finfo
#endif

awk_value_t *do_pn_set_country(EXTFN_ARGS) {
	awk_value_t arg1;

	if (get_argument(0, AWK_STRING, &arg1)) {
		set_country(arg1.u.s.str, arg1.u.s.len);
	}
	make_null_string(result);
	return result;
}

awk_value_t *do_pn_set_format(EXTFN_ARGS) {
	awk_value_t arg1;

	if (get_argument(0, AWK_STRING, &arg1)) {
		set_format(arg1.u.s.str, arg1.u.s.len);
	}
	make_null_string(result);
	return result;
}

awk_value_t *do_pn_set_leniency(EXTFN_ARGS) {
	awk_value_t arg1;

	if (get_argument(0, AWK_STRING, &arg1)) {
		set_leniency(arg1.u.s.str, arg1.u.s.len);
	}
	make_null_string(result);
	return result;
}

awk_value_t *do_pn_format(EXTFN_ARGS) {
	awk_value_t arg1;

	char *res;
	size_t res_len;

	if ((get_argument(0, AWK_STRING, &arg1))
			&& pn_format(arg1.u.s.str, arg1.u.s.len, &res, &res_len))
	{
		make_const_string(res, res_len, result);
		free(res);
	} else {
		make_null_string(result);
	}

	return result;
}

awk_value_t *do_pn_valid(EXTFN_ARGS) {
	awk_value_t arg1;

	int res;

	if (get_argument(0, AWK_STRING, &arg1))
	{
		res = pn_valid(arg1.u.s.str, arg1.u.s.len);
		make_number((double)res, result);
	} else {
		make_null_string(result);
	}

	return result;
}

awk_value_t *do_pn_find(EXTFN_ARGS) {
	awk_value_t arg1, arg2;
	struct str_list *pnl, *tmp;
	awk_value_t index, value;

	if (get_argument(0, AWK_STRING, &arg1) && get_argument(1, AWK_ARRAY, &arg2))
	{
		clear_array(arg2.u.a);
		pnl = pn_find(arg1.u.s.str, arg1.u.s.len);
		while(pnl) {
			make_const_string(pnl->str, pnl->len, &index);
			make_number((double)1, &value);
			set_array_element(arg2.u.a, &index, &value);
			tmp = pnl;
			pnl = pnl->prev;
			free(tmp);
		}
	} else {
		make_null_string(result);
	}

	return result;
}

awk_value_t *do_pn_info(EXTFN_ARGS) {
	awk_value_t arg1, arg2;
	awk_value_t index, value;

	struct pn_info res;

	memset(&res, 0, sizeof(res));

	if (get_argument(0, AWK_STRING, &arg1) && get_argument(1, AWK_ARRAY, &arg2))
	{
		clear_array(arg2.u.a);
		if (pn_info(arg1.u.s.str, arg1.u.s.len, &res)) {
			make_const_strz("prefix", &index);
			make_number((double)res.country_code, &value);
			set_array_element(arg2.u.a, &index, &value);

			make_const_strz("country", &index);
			make_const_string(res.country_name, 2, &value);
			set_array_element(arg2.u.a, &index, &value);

			make_const_strz("type", &index);
			make_number((double)res.type, &value);
			set_array_element(arg2.u.a, &index, &value);

			make_const_strz("location", &index);
			make_const_string(res.location, res.location_len, &value);
			set_array_element(arg2.u.a, &index, &value);
			if (res.location_len != 0) {
				free(res.location);
			}

			make_const_strz("possible_short_number", &index);
			make_number((double)res.possible_short_number, &value);
			set_array_element(arg2.u.a, &index, &value);

			make_const_strz("valid_short_number", &index);
			make_number((double)res.valid_short_number, &value);
			set_array_element(arg2.u.a, &index, &value);

			make_const_strz("emergency_number", &index);
			make_number((double)res.emergency_number, &value);
			set_array_element(arg2.u.a, &index, &value);
		}
	} else {
		make_null_string(result);
	}

	return result;
}

awk_value_t *do_pn_dialout(EXTFN_ARGS) {
	awk_value_t arg1, arg2;

	char *res;
	size_t res_len;


	if (get_argument(0, AWK_STRING, &arg1))	{
		if (get_argument(1, AWK_STRING, &arg2)) {
			pn_dialout(arg1.u.s.str, arg1.u.s.len, arg2.u.s.str, arg2.u.s.len, &res, &res_len);
		} else {
			pn_dialout(arg1.u.s.str, arg1.u.s.len, NULL, 0, &res, &res_len);
		}
		make_const_string(res, res_len, result);
		free(res);
	} else {
		make_null_string(result);
	}

	return result;
}

static awk_ext_func_t func_table[] = {
    { "pn_format", do_pn_format, 1 },
	{ "pn_valid", do_pn_valid, 1 },
	{ "pn_find", do_pn_find, 2 },
	{ "pn_info", do_pn_info, 2 },
	{ "pn_dialout", do_pn_dialout, 2 },
	{ "pn_set_country", do_pn_set_country, 1 },
	{ "pn_set_format", do_pn_set_format, 1 },
	{ "pn_set_leniency", do_pn_set_leniency, 1 },
};

static awk_bool_t init_func(void) {
	return pn_init() ? awk_true : awk_false;
}

dl_load_func(func_table, "phonenumber", "phonenumber")
