// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef _EBPF_UTILS_H
#define _EBPF_UTILS_H

//#include "bpf_helpers.h"

#define TRACE_ID_SIZE 16
#define TRACE_ID_STRING_SIZE 32
#define SPAN_ID_SIZE 8
#define SPAN_ID_STRING_SIZE 16

static __always_inline int bpf_memcmp(char *s1, char *s2, s32 size)
{
    for (int i = 0; i < size; i++)
    {
        if (s1[i] != s2[i])  return 0;
    }

    return 1;
}

static __always_inline void generate_random_bytes(unsigned char *buff, u32 size)
{
#pragma clang loop unroll(full)
    for (int i = 0; i < (size / 4); i++)
    {
        u32 random = bpf_get_prandom_u32();
        buff[(4 * i)] = (random >> 24) & 0xFF;
        buff[(4 * i) + 1] = (random >> 16) & 0xFF;
        buff[(4 * i) + 2] = (random >> 8) & 0xFF;
        buff[(4 * i) + 3] = random & 0xFF;
    }
}

static __always_inline void bytes_to_hex_string(unsigned char *pin, u32 size, char *out) {
	char *pout = out;
#pragma clang loop unroll(full)
	for (u32 i = 0; i < size; i++) {
		unsigned char byte = *pin++;
		char high = byte >> 4;
		char low = byte & 0xF;
		*pout++ = high + (high < 10 ? '0' : 'a' - 10);
		*pout++ = low + (low < 10 ? '0' : 'a' - 10);
	}
}

static __always_inline void hex_string_to_bytes(char *str, u32 size, unsigned char *out) {
#pragma clang loop unroll(full)
	for (int i = 0; i < (size / 2); i++) {
		char ch0 = str[2 * i];
		char ch1 = str[2 * i + 1];
		u8 nib0 = (ch0 & 0xF) + (ch0 >> 6) | ((ch0 >> 3) & 0x8);
		u8 nib1 = (ch1 & 0xF) + (ch1 >> 6) | ((ch1 >> 3) & 0x8);
		out[i] = (nib0 << 4) | nib1;
	}
}

static __always_inline void copy_byte_arrays(unsigned char *src, unsigned char *dst, u32 size)
{
#pragma clang loop unroll(full)
    for (int i = 0; i < size; i++)
    {
        dst[i] = src[i];
    }
}

static __always_inline void custom_hash(const char *str, unsigned char *hash,u32 size) {
	u64 int_hash = 0;
#pragma clang loop unroll(full)
	for (int i = 0; i < APM_REMOTE_ADDR_MAX_LEN; i++) { // Assuming maximum string length is 256
		if (str[i] == '\0') break;
		int_hash = (int_hash * 31) + str[i] ;
	}
	// Convert int_hash to 16 bytes
#pragma clang loop unroll(full)
	for (int i = 0; i < size; i++) {
		hash[i] = int_hash % 10;
		int_hash /= 10;
	}
	if (hash[0] == 0) hash[0] = 1;

}

static __always_inline void set_assumed_app_id_arrays(char *host, unsigned char *dist, u32 size) {
	unsigned char hash[size];
	custom_hash(host, hash, size);
	hex_string_to_bytes((char *) hash, size, dist);
}

static __always_inline void bpf_memset(unsigned char *dst, u32 size, unsigned char value)
{
    for (int i = 0; i < size; i++)
    {
        dst[i] = value;
    }
}

static __always_inline bool bpf_is_zero(unsigned char *buff, u32 size)
{
    for (int i = 0; i < size; i++)
    {
        if (buff[i] != 0)
        {
            return false;
        }
    }

    return true;
}

#endif
