#include <cds/memory.h>
#include <cds/logger.h>
#include <cds/rr_serialize.h>

#ifdef SER

static void rr_dup(rr_t **dst, rr_t *pkg_rr)
{
	rr_t *tmp = NULL;
	int res;
	
	tmp = pkg_rr;
	
	while (pkg_rr) {
		res = shm_duplicate_rr(dst, pkg_rr);
		dst = &(*dst)->next;
		pkg_rr = pkg_rr->next;
	}
	if (tmp) free_rr(&tmp);
}

static int serialize_route(sstream_t *ss, rr_t **_r)
{
	int do_it = 0;
	int res = 0;
	if (is_input_sstream(ss)) { /* read route */
		if (serialize_int(ss, &do_it) != 0) return -1;
		*_r = NULL;
	}
	else { /* store route */
		if (*_r) do_it = 1;
		else do_it = 0;
		if (serialize_int(ss, &do_it) != 0) return -1;
	}
		
	if (do_it) {
		str s;
		if (*_r) {
			s.s = (*_r)->nameaddr.name.s;
			s.len = (*_r)->len;
		}

		res = serialize_str_ex(ss, &s) | res;
		if (is_input_sstream(ss)) {
			rr_t *pkg_rr = NULL;
			
			parse_rr_body(s.s, s.len, &pkg_rr);
			rr_dup(_r, pkg_rr);
		}
	}
	
	return res;
}

int serialize_route_set(sstream_t *ss, rr_t **route_set)
{
	rr_t *r, *first = NULL, *last = NULL;
	int res = 0;

	if (is_input_sstream(ss)) { /* read */
		do {
			res = serialize_route(ss, &r) | res;
			if (last) last->next = r; 
			else first = r;
			last = r;
			if (last) {
				/* due to parsing rr (may be more rr_t than 1) */
				while (last->next) last = last->next; 
			}
		} while (r);
		*route_set = first;
	}
	else {	/* store */
		r = *route_set;
		while (r) {
			serialize_route(ss, &r);
			r = r->next;
		}
		r = NULL;
		serialize_route(ss, &r); /* store terminating route */
	}
	
	return 0;
}

int route_set2str(rr_t *rr, str_t *dst_str)
{
	int res = 0;
	sstream_t store;
	
	init_output_sstream(&store, 256);
	
	if (serialize_route_set(&store, &rr) != 0) {
		ERROR_LOG("can't serialize route set\n");
		res = -1;
	}
	else {
		if (get_serialized_sstream(&store, dst_str) != 0) {
			ERROR_LOG("can't get serialized data\n");
			res = -1;
		}
	}

	destroy_sstream(&store);
	return res;
}

int str2route_set(const str_t *s, rr_t **rr)
{
	int res = 0;
	sstream_t store;

	if (!s) return -1;
	
	init_input_sstream(&store, s->s, s->len);
	if (serialize_route_set(&store, rr) != 0) {
		ERROR_LOG("can't de-serialize route set\n");
		res = -1;
	}	
	destroy_sstream(&store);
	
	return res;
}

#endif