// 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 _SPAN_CONTEXT_H_
#define _SPAN_CONTEXT_H_

#include "utils.h"

#define SPAN_CONTEXT_STRING_SIZE 55
#define W3C_KEY_LENGTH 11 // length of the "traceparent" key
#define W3C_VAL_LENGTH 55

struct span_context {
	u8 TraceID[TRACE_ID_SIZE];
	u8 SpanID[SPAN_ID_SIZE];
	u8 TraceFlags;
	u8 padding[7];
};


static __always_inline struct span_context generate_span_context() {
	struct span_context context = {};
	generate_random_bytes(context.TraceID, TRACE_ID_SIZE);
	generate_random_bytes(context.SpanID, SPAN_ID_SIZE);
	return context;
}

static __always_inline void span_context_to_w3c_string(struct span_context *ctx, char *buff) {
	// W3C format: version (2 chars) - trace id (32 chars) - span id (16 chars) - sampled (2 chars)
	char *out = buff;

	// Write version
	*out++ = '0';
	*out++ = '0';
	*out++ = '-';

	// Write trace id
	bytes_to_hex_string(ctx->TraceID, TRACE_ID_SIZE, out);
	out += TRACE_ID_STRING_SIZE;
	*out++ = '-';

	// Write span id
	bytes_to_hex_string(ctx->SpanID, SPAN_ID_SIZE, out);
	out += SPAN_ID_STRING_SIZE;
	*out++ = '-';

	// Write sampled
	*out++ = '0';
	*out = '1';
}

static __always_inline void span_context_to_cw_string(struct apm_span_context *ctx, char *buff) {
	// W3C format: version (2 chars) - trace id (32 chars) - span id (16 chars) - sampled (2 chars)
	//	[type_from]:[sample]:[host_id]:[app_id]:[instance_id]:[trace_id]:[assumed_app_i d]:[span_id]
	//	2           2         16        16      16            32         16                16
	char *out = buff;

	// Write type_from
	*out++ = '0';
	*out++ = '0';
	*out++ = ':';

	// Write sample
	*out++ = '0';
	*out++ = '0';
	*out++ = ':';

	// Write host_id
	bytes_to_hex_string(ctx->host_id, APM_HOST_ID_SIZE, out);
	out += APM_HOST_ID_STRING_SIZE;
	*out++ = ':';

	// Write app_id
	bytes_to_hex_string(ctx->app_id, APM_APP_ID_SIZE, out);
	out += APM_APP_ID_STRING_SIZE;
	*out++ = ':';


	// Write instance_id
	bytes_to_hex_string(ctx->instance_id, APM_INSTANCE_ID_SIZE, out);
	out += APM_INSTANCE_ID_STRING_SIZE;
	*out++ = ':';

	// Write trace_id
	bytes_to_hex_string(ctx->trace_id, APM_TRACE_ID_SIZE, out);
	out += APM_TRACE_ID_STRING_SIZE;
	*out++ = ':';
	// Write assumed_app_id
	bytes_to_hex_string(ctx->assumed_app_id, APM_ASSUMED_APP_ID_SIZE, out);
	out += APM_ASSUMED_APP_ID_STRING_SIZE;
	*out++ = ':';

	// Write span_id
	bytes_to_hex_string(ctx->span_id, APM_SPAN_ID_SIZE, out);
	out += APM_SPAN_ID_STRING_SIZE;
//	*out++ = ':';

//	// Write trace id
//	bytes_to_hex_string(ctx->TraceID, TRACE_ID_SIZE, out);
//	out += TRACE_ID_STRING_SIZE;
//	*out++ = '-';
//	// Write trace id
//	bytes_to_hex_string(ctx->TraceID, TRACE_ID_SIZE, out);
//	out += TRACE_ID_STRING_SIZE;
//	*out++ = '-';
//	// Write trace id
//	bytes_to_hex_string(ctx->TraceID, TRACE_ID_SIZE, out);
//	out += TRACE_ID_STRING_SIZE;
//	*out++ = '-';
//
//	// Write span id
//	bytes_to_hex_string(ctx->SpanID, SPAN_ID_SIZE, out);
//	out += SPAN_ID_STRING_SIZE;
//	*out++ = '-';

	// Write sampled
//	*out++ = '0';
//	*out = '1';
}

#define MAX_SIZE 120
#define MAX_TOKENS 8

struct Token {
	u32 start;
	u32 len;
};
struct cw_header_token {
	struct Token token[MAX_TOKENS];
	u32 start[MAX_TOKENS];
	u32 a;
};

static __always_inline void w3c_string_to_span_context(char *str, struct span_context *ctx) {
//	GO:0:10154813500555812:5450531005555981:5610250100539899:304775019cd3218a:1001025098564810:140acc88cde8773f:110
//	00-95b5ec2b81e2374a4a27ce36ab71d349-18f65a5a3ab22213-02
//	JAVA:0:10675555109846866:10675555109846867:10675555109846868:1541924974244&c69a3a5f4f9c46eb9c85d164b702ee68:10675555109846869:10675555109846861
	u32 trace_id_start_pos = 3;
	u32 span_id_start_pod = 36;


	hex_string_to_bytes(str + trace_id_start_pos, TRACE_ID_STRING_SIZE, ctx->TraceID);
	hex_string_to_bytes(str + span_id_start_pod, SPAN_ID_STRING_SIZE, ctx->SpanID);


}

//	00000000GO:00:1015481350055581:5450531005555981:5610250100539899:304775019cd3218a304775019cd3218a:1001025098564810:140acc88cde8773f
//	00:00:1015481350055581:5450531005555981:5610250100539899:304775019cd3218a304775019cd3218a:1001025098564810:140acc88cde8773f
//	[type_from]:[sample]:[host_id]:[app_id]:[instance_id]:[trace_id]:[assumed_app_i d]:[span_id]
//	10          2         16        16      16            32         16                16
static __always_inline void cw_string_to_span_context(char *str, struct apm_span_context *ctx) {
	// 简化后的逻辑
	char current_header_val[CW_HEADER_VAL_LENGTH];
	bpf_probe_read(current_header_val, sizeof(current_header_val), str);

	hex_string_to_bytes(current_header_val, APM_TYPE_FROM_STRING_SIZE, ctx->type_from);
	hex_string_to_bytes(current_header_val + APM_TYPE_FROM_STRING_SIZE + 1, APM_SAMPLE_STRING_SIZE, ctx->sample);
	hex_string_to_bytes(current_header_val + APM_TYPE_FROM_STRING_SIZE + APM_SAMPLE_STRING_SIZE + 2, APM_HOST_ID_STRING_SIZE, ctx->host_id);
	hex_string_to_bytes(current_header_val + APM_TYPE_FROM_STRING_SIZE + APM_SAMPLE_STRING_SIZE + APM_HOST_ID_STRING_SIZE + 3, APM_APP_ID_STRING_SIZE, ctx->app_id);
	hex_string_to_bytes(current_header_val + APM_TYPE_FROM_STRING_SIZE + APM_SAMPLE_STRING_SIZE + APM_HOST_ID_STRING_SIZE + APM_APP_ID_STRING_SIZE + 4, APM_INSTANCE_ID_STRING_SIZE, ctx->instance_id);
	hex_string_to_bytes(current_header_val + APM_TYPE_FROM_STRING_SIZE + APM_SAMPLE_STRING_SIZE + APM_HOST_ID_STRING_SIZE + APM_APP_ID_STRING_SIZE + APM_INSTANCE_ID_STRING_SIZE + 5, APM_TRACE_ID_STRING_SIZE, ctx->trace_id);
	hex_string_to_bytes(current_header_val + APM_TYPE_FROM_STRING_SIZE + APM_SAMPLE_STRING_SIZE + APM_HOST_ID_STRING_SIZE + APM_APP_ID_STRING_SIZE + APM_INSTANCE_ID_STRING_SIZE + APM_TRACE_ID_STRING_SIZE + 6, APM_ASSUMED_APP_ID_STRING_SIZE, ctx->assumed_app_id);
	hex_string_to_bytes(current_header_val + APM_TYPE_FROM_STRING_SIZE + APM_SAMPLE_STRING_SIZE + APM_HOST_ID_STRING_SIZE + APM_APP_ID_STRING_SIZE + APM_INSTANCE_ID_STRING_SIZE + APM_TRACE_ID_STRING_SIZE + APM_ASSUMED_APP_ID_STRING_SIZE + 7, APM_SPAN_ID_STRING_SIZE, ctx->span_id);
}

static __always_inline void cw_string_to_span_context2(const char *str, struct apm_span_context *ctx, int off) {
	// 简化后的逻辑
	char current_header_val[CW_HEADER_VAL_LENGTH];
	bpf_probe_read(current_header_val, sizeof(current_header_val), str+off);

	bpf_probe_read(ctx->type_from, sizeof(ctx->type_from), current_header_val);
	bpf_probe_read(ctx->sample, sizeof(ctx->sample), current_header_val + APM_TYPE_FROM_STRING_SIZE + 1);
	bpf_probe_read(ctx->type_from, sizeof(ctx->type_from), current_header_val + APM_TYPE_FROM_STRING_SIZE + APM_SAMPLE_STRING_SIZE + 2);
	bpf_probe_read(ctx->sample, sizeof(ctx->sample), current_header_val + APM_TYPE_FROM_STRING_SIZE + APM_SAMPLE_STRING_SIZE + APM_HOST_ID_STRING_SIZE + 3);
	bpf_probe_read(ctx->host_id, sizeof(ctx->host_id), current_header_val + APM_TYPE_FROM_STRING_SIZE + APM_SAMPLE_STRING_SIZE + APM_HOST_ID_STRING_SIZE + APM_APP_ID_STRING_SIZE + 4);
	bpf_probe_read(ctx->app_id, sizeof(ctx->app_id), current_header_val + APM_TYPE_FROM_STRING_SIZE + APM_SAMPLE_STRING_SIZE + APM_HOST_ID_STRING_SIZE + APM_APP_ID_STRING_SIZE + APM_INSTANCE_ID_STRING_SIZE + 5);
	bpf_probe_read(ctx->instance_id, sizeof(ctx->instance_id), current_header_val + APM_TYPE_FROM_STRING_SIZE + APM_SAMPLE_STRING_SIZE + APM_HOST_ID_STRING_SIZE + APM_APP_ID_STRING_SIZE + APM_INSTANCE_ID_STRING_SIZE + APM_TRACE_ID_STRING_SIZE + 6);
	bpf_probe_read(ctx->trace_id, sizeof(ctx->trace_id), current_header_val + APM_TYPE_FROM_STRING_SIZE + APM_SAMPLE_STRING_SIZE + APM_HOST_ID_STRING_SIZE + APM_APP_ID_STRING_SIZE + APM_INSTANCE_ID_STRING_SIZE + APM_TRACE_ID_STRING_SIZE + APM_ASSUMED_APP_ID_STRING_SIZE + 7);


//	hex_string_to_bytes(str+off, APM_TYPE_FROM_STRING_SIZE, ctx->type_from);
//	hex_string_to_bytes(str+off + APM_TYPE_FROM_STRING_SIZE + 1, APM_SAMPLE_STRING_SIZE, ctx->sample);
//	hex_string_to_bytes(str+off + APM_TYPE_FROM_STRING_SIZE + APM_SAMPLE_STRING_SIZE + 2, APM_HOST_ID_STRING_SIZE, ctx->host_id);
//	hex_string_to_bytes(str+off + APM_TYPE_FROM_STRING_SIZE + APM_SAMPLE_STRING_SIZE + APM_HOST_ID_STRING_SIZE + 3, APM_APP_ID_STRING_SIZE, ctx->app_id);
//	hex_string_to_bytes(str+off + APM_TYPE_FROM_STRING_SIZE + APM_SAMPLE_STRING_SIZE + APM_HOST_ID_STRING_SIZE + APM_APP_ID_STRING_SIZE + 4, APM_INSTANCE_ID_STRING_SIZE, ctx->instance_id);
//	hex_string_to_bytes(str+off + APM_TYPE_FROM_STRING_SIZE + APM_SAMPLE_STRING_SIZE + APM_HOST_ID_STRING_SIZE + APM_APP_ID_STRING_SIZE + APM_INSTANCE_ID_STRING_SIZE + 5, APM_TRACE_ID_STRING_SIZE, ctx->trace_id);
//	hex_string_to_bytes(str+off + APM_TYPE_FROM_STRING_SIZE + APM_SAMPLE_STRING_SIZE + APM_HOST_ID_STRING_SIZE + APM_APP_ID_STRING_SIZE + APM_INSTANCE_ID_STRING_SIZE + APM_TRACE_ID_STRING_SIZE + 6, APM_ASSUMED_APP_ID_STRING_SIZE, ctx->assumed_app_id);
//	hex_string_to_bytes(str+off + APM_TYPE_FROM_STRING_SIZE + APM_SAMPLE_STRING_SIZE + APM_HOST_ID_STRING_SIZE + APM_APP_ID_STRING_SIZE + APM_INSTANCE_ID_STRING_SIZE + APM_TRACE_ID_STRING_SIZE + APM_ASSUMED_APP_ID_STRING_SIZE + 7, APM_SPAN_ID_STRING_SIZE, ctx->span_id);
}


#endif
