/*
 * (C) 2012 by Holger Hans Peter Freyther <zecke@selfish.org>
 * All Rights Reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * 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 Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

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

#include <osmocom/core/application.h>
#include <osmocom/core/utils.h>

#include <openbsc/gsm_data.h>
#include <openbsc/abis_nm.h>
#include <openbsc/debug.h>

static const uint8_t simple_config[] = {
	/*0, 13, */
	66, 18, 0, 3, 1, 2, 3, 19, 0, 3, 3, 4, 5,
};

static const uint8_t dual_config[] = {
	/*0, 26, */
	66, 18, 0, 3, 1, 2, 3, 19, 0, 3, 3, 4, 5,
	66, 18, 0, 3, 9, 7, 5, 19, 0, 3, 6, 7, 8,
};

static const uint8_t load_config[] = {
	0x42, 0x12, 0x00, 0x08, 0x31, 0x36, 0x38, 0x64,
	0x34, 0x37, 0x32, 0x00, 0x13, 0x00, 0x0b, 0x76,
	0x32, 0x30, 0x30, 0x62, 0x31, 0x34, 0x33, 0x64,
	0x30, 0x00, 0x42, 0x12, 0x00, 0x08, 0x31, 0x36,
	0x38, 0x64, 0x34, 0x37, 0x32, 0x00, 0x13, 0x00,
	0x0b, 0x76, 0x32, 0x30, 0x30, 0x62, 0x31, 0x34,
	0x33, 0x64, 0x31, 0x00
};

static void test_simple_sw_config(void)
{
	struct abis_nm_sw_descr descr[1];
	int rc;

	rc = abis_nm_parse_sw_config(simple_config, ARRAY_SIZE(simple_config),
				&descr[0], ARRAY_SIZE(descr));
	if (rc != 1) {
		printf("FAILED to parse the File Id/File version\n");
		abort();
	}

	if (descr[0].len != 13) {
		printf("WRONG SIZE: %zu\n", descr[0].len);
		abort();
	}

	printf("Start: %td len: %zu\n", descr[0].start - simple_config, descr[0].len);
	printf("file_id:  %s\n", osmo_hexdump(descr[0].file_id, descr[0].file_id_len));
	printf("file_ver: %s\n", osmo_hexdump(descr[0].file_ver, descr[0].file_ver_len));
}

static void test_simple_sw_short(void)
{
	struct abis_nm_sw_descr descr[1];
	int i;

	for (i = 1; i < ARRAY_SIZE(simple_config); ++i) {
		int rc = abis_nm_parse_sw_config(simple_config,
				ARRAY_SIZE(simple_config) - i, &descr[0],
				ARRAY_SIZE(descr));
		if (rc >= 1) {
			printf("SHOULD not have parsed: %d\n", rc);
			abort();
		}
	}
}

static void test_dual_sw_config(void)
{
	struct abis_nm_sw_descr descr[2];
	int rc;

	rc = abis_nm_parse_sw_config(dual_config, ARRAY_SIZE(dual_config),
				&descr[0], ARRAY_SIZE(descr));
	if (rc != 2) {
		printf("FAILED to parse the File Id/File version\n");
		abort();
	}

	if (descr[0].len != 13) {
		printf("WRONG SIZE0: %zu\n", descr[0].len);
		abort();
	}

	if (descr[1].len != 13) {
		printf("WRONG SIZE1: %zu\n", descr[1].len);
		abort();
	}

	printf("Start: %td len: %zu\n", descr[0].start - dual_config, descr[0].len);
	printf("file_id:  %s\n", osmo_hexdump(descr[0].file_id, descr[0].file_id_len));
	printf("file_ver: %s\n", osmo_hexdump(descr[0].file_ver, descr[0].file_ver_len));

	printf("Start: %td len: %zu\n", descr[1].start - dual_config, descr[1].len);
	printf("file_id:  %s\n", osmo_hexdump(descr[1].file_id, descr[1].file_id_len));
	printf("file_ver: %s\n", osmo_hexdump(descr[1].file_ver, descr[1].file_ver_len));
}

static void test_sw_selection(void)
{
	struct abis_nm_sw_descr descr[8], tmp;
	int rc, pos;

	rc = abis_nm_parse_sw_config(load_config, ARRAY_SIZE(load_config),
				&descr[0], ARRAY_SIZE(descr));
	if (rc != 2) {
		printf("FAILED to parse the File Id/File version\n");
		abort();
	}

	printf("Start: %td len: %zu\n", descr[0].start - load_config, descr[0].len);
	printf("file_id:  %s\n", osmo_hexdump(descr[0].file_id, descr[0].file_id_len));
	printf("file_ver: %s\n", osmo_hexdump(descr[0].file_ver, descr[0].file_ver_len));

	printf("Start: %td len: %zu\n", descr[1].start - load_config, descr[1].len);
	printf("file_id:  %s\n", osmo_hexdump(descr[1].file_id, descr[1].file_id_len));
	printf("file_ver: %s\n", osmo_hexdump(descr[1].file_ver, descr[1].file_ver_len));

	/* start */
	pos = abis_nm_select_newest_sw(descr, rc);
	if (pos != 1) {
		printf("Selected the wrong version: %d\n", pos);
		abort();
	}
	printf("SELECTED: %d\n", pos);

	/* shuffle */
	tmp = descr[0];
	descr[0] = descr[1];
	descr[1] = tmp;
	pos = abis_nm_select_newest_sw(descr, rc);
	if (pos != 0) {
		printf("Selected the wrong version: %d\n", pos);
		abort();
	}
	printf("SELECTED: %d\n", pos);
}

int main(int argc, char **argv)
{
	osmo_init_logging(&log_info);
	test_simple_sw_config();
	test_simple_sw_short();
	test_dual_sw_config();
	test_sw_selection();

	return EXIT_SUCCESS;
}
