/*
 * Copyright (c) 2016, Natacha Porté
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <inttypes.h>

#include "dict_tools.h"

static bool
check_length(Tuple *tuple, const char *context) {
	if (tuple->length == 1 || tuple->length == 2 || tuple->length == 4) {
		return true;
	}

	APP_LOG(APP_LOG_LEVEL_ERROR,
	    "Unexpected length %" PRIu16 " in %s dictionary entry",
	    tuple->length, context);
	return false;
}

static int32_t
raw_read_int(Tuple *tuple) {
	switch (tuple->length) {
	    case 1:
		return tuple->value->int8;
	    case 2:
		return tuple->value->int16;
	    case 4:
		return tuple->value->int32;
	    default:
		return 0;
	}
}

static uint32_t
raw_read_uint(Tuple *tuple) {
	switch (tuple->length) {
	    case 1:
		return tuple->value->uint8;
	    case 2:
		return tuple->value->uint16;
	    case 4:
		return tuple->value->uint32;
	    default:
		return 0;
	}
}

int32_t
tuple_int(Tuple *tuple) {
	if (!tuple) return 0;
	switch (tuple->type) {
	    case TUPLE_INT:
		if (!check_length(tuple, "integer")) return 0;
		return raw_read_int(tuple);
	    case TUPLE_UINT:
		if (!check_length(tuple, "integer")) return 0;
		uint32_t u = raw_read_uint(tuple);
		if (u > 2147483647) {
			APP_LOG(APP_LOG_LEVEL_ERROR,
			    "Integer overflow in signed dictionary entry %"
			    PRIu32, u);
			return 0;
		}
		return u;
	    default:
		APP_LOG(APP_LOG_LEVEL_ERROR,
		    "Unexpected type %d for integer dictionary entry",
		    (int)tuple->type);
		return 0;
	}
}

uint32_t
tuple_uint(Tuple *tuple) {
	if (!tuple) return 0;
	switch (tuple->type) {
	    case TUPLE_UINT:
		if (!check_length(tuple, "unsigned")) return 0;
		return raw_read_uint(tuple);
	    case TUPLE_INT:
		if (!check_length(tuple, "unsigned")) return 0;
		int32_t i = raw_read_int(tuple);
		if (i < 0) {
			APP_LOG(APP_LOG_LEVEL_ERROR,
			    "Integer underflow in unsigned dictionary entry %"
			    PRIi32, i);
			return 0;
		}
		return i;
	    default:
		APP_LOG(APP_LOG_LEVEL_ERROR,
		    "Unexpected type %d for unsigned dictionary entry",
		    (int)tuple->type);
		return 0;
	}
}