/* This file was generated by generate-wire.py */
/* Do not modify this file! Modify the _csv file it was generated from. */
/* Original template can be found at tools/gen/impl_template */

#include <${header_filename}>
#include <assert.h>
#include <ccan/array_size/array_size.h>
#include <ccan/mem/mem.h>
#include <ccan/tal/str/str.h>
#include <common/utils.h>
#include <stdio.h>

#ifndef SUPERVERBOSE
#define SUPERVERBOSE(...)
#endif

% for comment in top_comments:
/*${comment} */
% endfor
% for enum_set in enum_sets:

const char *${enum_set['name']}_name(int e)
{
	static char invalidbuf[sizeof("INVALID ") + STR_MAX_CHARS(e)];

	switch ((enum ${enum_set['name']})e) {
    % for msg in enum_set['set']:
	case ${msg.enum_name()}: return "${msg.enum_name()}";
    % endfor
	}

	snprintf(invalidbuf, sizeof(invalidbuf), "INVALID %i", e);
	return invalidbuf;
}

bool ${enum_set['name']}_is_defined(u16 type)
{
	switch ((enum ${enum_set['name']})type) {
    % for msg in enum_set['set']:
	case ${msg.enum_name()}:;
    % endfor
	      return true;
	}
	return false;
}

% endfor
## START PARTIALS
## Subtype and TLV-msg towire_
<%def name="towire_subtype_field(fieldname, f, type_obj, is_single_ptr, ptr)">\
% if f.is_array() or f.is_varlen():
    % if type_obj.has_array_helper():
towire_${type_obj.name}_array(${ptr}, ${fieldname}, ${f.size('tal_count(' + fieldname + ')')});
    % else:
	for (size_t i = 0; i < ${f.size('tal_count(' + fieldname + ')')}; i++)
	% if type_obj.is_assignable() or type_obj.has_len_fields():
		towire_${type_obj.name}(${ptr}, ${fieldname}[i]);
	% else:
		towire_${type_obj.name}(${ptr}, ${fieldname} + i);
	% endif
    % endif
% elif f.len_field_of:
towire_${type_obj.name}(${ptr}, ${f.name});
% elif is_single_ptr:
towire_${type_obj.name}(${ptr}, ${'*' if type_obj.is_assignable() else ''}${fieldname});
% else:
towire_${type_obj.name}(${ptr}, ${'' if type_obj.is_assignable() else '&'}${fieldname});
% endif
</%def>
## Subtype and TLV-msg fromwire
<%def name="fromwire_subtype_field(fieldname, f, ctx, is_ptr)">\
<%
    type_ = f.type_obj.name
    typename = f.type_obj.type_name()
    if f.type_obj.is_varsize():
	typename += ' *'
%>\
% if f.is_array() or f.is_varlen():
    % if f.type_obj.has_array_helper():
    ## We assume array helpers only deal with things literally transcribed!!
	% if f.is_varlen():
${fieldname} = ${f.size('*plen')} ? tal_arr(${ctx}, ${typename}, ${f.size('*plen')}) : NULL;
	% endif
fromwire_${type_}_array(cursor, plen, ${fieldname}, ${f.size('*plen')});
    % else:
	% if f.is_varlen():
${fieldname} = ${f.size('*plen')} ? tal_arr(${ctx}, ${typename}, 0) : NULL;
	% endif
        % if f.is_implicit_len():
	for (size_t i = 0; *plen != 0; i++) {
	% else:
	for (size_t i = 0; i < ${f.size()}; i++) {
        % endif
		${typename} tmp;
	% if f.type_obj.is_assignable():
		tmp = fromwire_${type_}(cursor, plen);
	% elif f.is_varlen() and f.type_obj.is_varsize():
		tmp = fromwire_${type_}(${ctx}, cursor, plen);
	% else:
		fromwire_${type_}(cursor, plen, &tmp);
	% endif
		tal_arr_expand(&${fieldname}, tmp);
	}
    % endif
% else:
    % if is_ptr:
    ${fieldname} = tal(${ctx}, ${typename});
    <% fieldname = '*' + fieldname %>
    % endif
    % if f.type_obj.is_assignable():
${ f.name if f.len_field_of else fieldname} = fromwire_${type_}(cursor, plen);
    % elif f.type_obj.is_varsize():
${fieldname} = *fromwire_${type_}(${ctx}, cursor, plen);
    % else:
fromwire_${type_}(cursor, plen, &${fieldname});
    % endif
%endif
</%def>
## END PARTIALS
## FIXME: extract out partials for the method declarations
## (shared between here and header_template)
% for subtype in subtypes: ## START Subtypes

/* SUBTYPE: ${subtype.name.upper()} */
    % for c in subtype.type_comments:
/*${c} */
    % endfor
<%
    static = '' if options.expose_subtypes else 'static '
%>\
${static}void towire_${subtype.name}(u8 **p, const ${subtype.type_name()} *${subtype.name})
{
	% for f in subtype.get_len_fields():
	${f.type_obj.type_name()} ${f.name} = tal_count(${subtype.name}->${f.len_field_of});
	% endfor

	% for f in subtype.fields.values():
	    % for c in f.field_comments:
	/*${c} */
	    % endfor
<%
   fieldname = '{}->{}'.format(subtype.name,f.name)
%>\
	${towire_subtype_field(fieldname, f, f.type_obj, False, 'p')}\
	% endfor
}
% if subtype.is_varsize():
${static}${subtype.type_name()} *
fromwire_${subtype.name}(const tal_t *ctx, const u8 **cursor, size_t *plen)
% else:
${static}void fromwire_${subtype.name}(${'const tal_t *ctx, ' if subtype.needs_context() else ''}const u8 **cursor, size_t *plen, ${subtype.type_name()} *${subtype.name})
% endif
{
% if subtype.is_varsize():
	${subtype.type_name()} *${subtype.name} = tal(ctx, ${subtype.type_name()});
% endif
	## Length field declarations
	% for f in subtype.get_len_fields():
	${f.type_obj.type_name()} ${f.name};
	% endfor

	% for f in subtype.fields.values():
	    % for c in f.field_comments:
	/*${c} */
	    % endfor
<%
    fieldname = '{}->{}'.format(subtype.name,f.name)
    ctx = subtype.name
%> \
	${fromwire_subtype_field(fieldname, f, ctx, False)}\
	% endfor
% if subtype.is_varsize():

	return ${subtype.name};
% endif
}
% endfor ## END Subtypes
<%def name="fromwire_phrase(f, type_, varsized)" >\
%if f.type_obj.is_assignable():
*${f.name} = fromwire_${type_}(&cursor, &plen);
% elif varsized:
*${f.name} = fromwire_${type_}(ctx, &cursor, &plen);
% else:
fromwire_${type_}(${'ctx, ' if f.needs_context() else ''}&cursor, &plen, ${'*' if f.is_optional else ''}${f.name});
% endif
</%def>
% for tlv in tlvs.values(): ## START TLV's

${tlv.type_name()} *${tlv.struct_name()}_new(const tal_t *ctx)
{
	/* Initialize everything to NULL. (Quiet, C pedants!) */
	${tlv.type_name()} *inst = talz(ctx, struct ${tlv.struct_name()});

	/* Initialized the fields to an empty array. */
	inst->fields = tal_arr(inst, struct tlv_field, 0);
	return inst;
}

    % for msg in tlv.messages.values():
/* ${tlv.name.upper()} MSG: ${msg.name} */
static u8 *towire_${msg.struct_name()}(const tal_t *ctx, const void *vrecord)
{
	const struct ${tlv.struct_name()} *r = vrecord;
	u8 *ptr;

	if (!r->${msg.name})
		return NULL;

	% for f in msg.get_len_fields():
	${f.type_obj.type_name()} ${f.name} = tal_count(r->${msg.name}->${f.len_field_of});
	% endfor

	ptr = tal_arr(ctx, u8, 0);
	% for f in msg.fields.values():
<%
    if msg.singleton():
        fieldname = 'r->{}'.format(msg.name)
	type_obj = msg.singleton().type_obj
    else:
        fieldname = 'r->{}->{}'.format(msg.name, f.name)
	type_obj = f.type_obj
%>
	${towire_subtype_field(fieldname, f, type_obj, msg.singleton(), '&ptr')}\
	% endfor
	return ptr;
}
static void fromwire_${msg.struct_name()}(const u8 **cursor, size_t *plen, void *vrecord)
{
	struct ${tlv.struct_name()} *r = vrecord;
	## Length field declarations
	% for f in msg.get_len_fields():
	${f.type_obj.type_name()} ${f.name};
	% endfor

	% if not msg.singleton():
	r->${msg.name} = tal(r, struct ${msg.struct_name()});
	% endif
	% for f in msg.fields.values():
<%
    if msg.singleton():
        fieldname = 'r->{}'.format(msg.name)
        ctx = 'r'
    else:
        fieldname = 'r->{}->{}'.format(msg.name, f.name)
        ctx = 'r->{}'.format(msg.name)
%>\
	${fromwire_subtype_field(fieldname, f, ctx, msg.singleton())}\
	% endfor
}
    % endfor

<% static = '' if tlv.name in options.expose_tlv_type else 'static '
%>\
${static}const struct tlv_record_type tlvs_${tlv.name}[] = {
    % for msg in tlv.ordered_msgs():
	{ ${msg.number}, towire_${msg.struct_name()}, fromwire_${msg.struct_name()} },
    % endfor
};

void towire_${tlv.name}(u8 **pptr,
			const void *record)
{
	size_t num_types = ${len(tlv.messages)};
	const struct tlv_record_type *types = tlvs_${tlv.name};
	if (!record)
		return;

	for (size_t i = 0; i < num_types; i++) {
		u8 *val;
		if (i != 0)
			assert(types[i].type > types[i-1].type);
		val = types[i].towire(NULL, record);
		if (!val)
			continue;

		/* BOLT #1:
		 *
		 * The sending node:
		 ...
		 *  - MUST minimally encode `type` and `length`.
		 */
		towire_bigsize(pptr, types[i].type);
		towire_bigsize(pptr, tal_bytelen(val));
		towire(pptr, val, tal_bytelen(val));
		tal_free(val);
	}
}


bool fromwire_${tlv.name}(const u8 **cursor, size_t *max, struct ${tlv.struct_name()} *record)
{
	size_t num_types = ${len(tlv.messages)};
	const struct tlv_record_type *types = tlvs_${tlv.name};
	while (*max > 0) {
		struct tlv_field field;

		/* BOLT #1:
		 *
		 * A `varint` is a variable-length, unsigned integer encoding
		 * using the [BigSize](#appendix-a-bigsize-test-vectors)
		 * format
		 */
		field.numtype = fromwire_bigsize(cursor, max);

		/* BOLT #1:
		 *  - if a `type` or `length` is not minimally encoded:
		 *    - MUST fail to parse the `tlv_stream`.
		 */
		if (!*cursor) {
			SUPERVERBOSE("type");
			goto fail;
		}
		field.length = fromwire_bigsize(cursor, max);

		/* BOLT #1:
		 *  - if a `type` or `length` is not minimally encoded:
		 *    - MUST fail to parse the `tlv_stream`.
		 */
		if (!*cursor) {
			SUPERVERBOSE("length");
			goto fail;
		}

		/* BOLT #1:
		 *  - if `length` exceeds the number of bytes remaining in the
		 *    message:
		 *    - MUST fail to parse the `tlv_stream`.
		 */
		if (field.length > *max) {
			SUPERVERBOSE("value");
			goto fail;
		}
		field.value = tal_dup_arr(record, u8, *cursor, field.length, 0);

		/* BOLT #1:
		 * - if `type` is known:
		 *   - MUST decode the next `length` bytes using the known
		 *     encoding for `type`.
		 */
		field.meta = NULL;
		for (size_t i = 0; i < num_types; i++) {
			if (types[i].type == field.numtype)
				field.meta = &types[i];
		}

		if (field.meta) {
			/* Length of message can't exceed 16 bits anyway. */
			size_t tlvlen = field.length;
			field.meta->fromwire(cursor, &tlvlen, record);

			if (!*cursor)
				goto fail;

			/* BOLT #1:
			 *  - if `length` is not exactly equal to that required
			 *    for the known encoding for `type`:
			 *    - MUST fail to parse the `tlv_stream`.
			 */
			if (tlvlen != 0) {
				SUPERVERBOSE("greater than encoding length");
				goto fail;
			}
		} else {
			/* We didn't read from *cursor through a fromwire, so
			 * update manually. */
			*cursor += field.length;
		}
		/* We've read bytes in ->fromwire, so update max */
		*max -= field.length;
		tal_arr_expand(&record->fields, field);
	}
	return true;
fail:
	fromwire_fail(cursor, max);
	return false;
}

bool ${tlv.name}_is_valid(const struct ${tlv.struct_name()} *record, size_t *err_index)
{
	size_t numfields = tal_count(record->fields);
	bool first = true;
	u64 prev_type = 0;
	for (int i=0; i<numfields; i++) {
		struct tlv_field *f = &record->fields[i];
		if (f->numtype % 2 == 0 && f->meta == NULL) {
			/* BOLT #1:
			 * - otherwise, if `type` is unknown:
			 *   - if `type` is even:
			 *     - MUST fail to parse the `tlv_stream`.
			 *   - otherwise, if `type` is odd:
			 *     - MUST discard the next `length` bytes.
			 */
			SUPERVERBOSE("unknown even");
			if (err_index != NULL)
				*err_index = i;
			return false;
		} else if (!first && f->numtype <= prev_type) {
			/* BOLT #1:
			 *  - if decoded `type`s are not monotonically-increasing:
			 *    - MUST fail to parse the `tlv_stream`.
			 */
			if (f->numtype == prev_type)
				SUPERVERBOSE("duplicate tlv type");
			else
				SUPERVERBOSE("invalid ordering");
			if (err_index != NULL)
				*err_index = i;
			return false;
		}
		first = false;
		prev_type = f->numtype;
	}
	return true;
}

% endfor ##  END TLV's
% for msg in messages: ## START Wire Messages

    % if msg.if_token:
#if ${msg.if_token}
    % endif
/* WIRE: ${msg.name.upper()} */
    % for c in msg.msg_comments:
/*${c} */
    % endfor
u8 *towire_${msg.name}(const tal_t *ctx${''.join([f.arg_desc_to() for f in msg.fields.values()])})
{
## FIXME: we're ignoring TLV's rn
	% for f in msg.get_len_fields():
	${f.type_obj.type_name()} ${f.name} = tal_count(${f.len_field_of});
	% endfor
	u8 *p = tal_arr(ctx, u8, 0);

	towire_u16(&p, ${msg.enum_name()});
	% for f in msg.fields.values():
	    % for c in f.field_comments:
	/*${c} */
	    % endfor
	% if f.is_array() or f.is_varlen():
	    % if f.type_obj.has_array_helper():
	towire_${f.type_obj.name}_array(&p, ${f.name}, ${f.size('tal_count(' + f.name + ')')});
	    % else:
	for (size_t i = 0; i < ${f.size('tal_count(' + f.name + ')')}; i++)
		% if f.type_obj.is_assignable() or f.type_obj.is_varsize():
		towire_${f.type_obj.name}(&p, ${f.name}[i]);
		% else:
		towire_${f.type_obj.name}(&p, ${f.name} + i);
		% endif
	    % endif
	% elif f.type_obj.is_tlv():
	towire_${f.type_obj.tlv.name}(&p, ${f.name});
        % elif f.is_optional: ## is optional?
	if (!${f.name})
		towire_bool(&p, false);
	else {
		towire_bool(&p, true);
		towire_${f.type_obj.name}(&p, ${'*' if f.type_obj.is_assignable() else ''}${f.name});
	}
	% else: ## all other cases
	towire_${f.type_obj.name}(&p, ${f.name});
	% endif
	% endfor

	return memcheck(p, tal_count(p));
}
bool fromwire_${msg.name}(${'const tal_t *ctx, ' if msg.needs_context() else ''}const void *p${''.join([f.arg_desc_from() for f in msg.fields.values()])})
{
	% if msg.get_len_fields():
	    % for f in msg.get_len_fields():
	${f.type_obj.type_name()} ${f.name};
	    % endfor

	% endif
	const u8 *cursor = p;
	size_t plen = tal_count(p);

	if (fromwire_u16(&cursor, &plen) != ${msg.enum_name()})
		return false;
	% for f in msg.fields.values():
<%
	    typename = f.type_obj.type_name()
	    if f.type_obj.is_varsize():
		typename = typename + ' *'
	    type_ = f.type_obj.name
	    varsized = f.type_obj.is_varsize()
	%> \
	    % for c in f.field_comments:
	/*${c} */
	    % endfor
	% if f.is_varlen():
	// 2nd case ${f.name}
	*${f.name} = ${f.size('plen')} ? tal_arr(ctx, ${typename}, ${f.size('plen')}) : NULL;
	% endif
	% if f.len_field_of:
	${f.name} = fromwire_${type_}(&cursor, &plen);
	% elif f.type_obj.is_tlv():
	fromwire_${f.type_obj.tlv.name}(&cursor, &plen, ${f.name});
	% elif f.is_array() or f.is_varlen():
	    % if f.type_obj.has_array_helper():
	fromwire_${type_}_array(&cursor, &plen, ${'*' if f.is_varlen() else ''}${f.name}, ${f.size('plen')});
	    % else:
	        % if f.is_implicit_len():
	for (size_t i = 0; plen != 0; i++)
	    	% else:
	for (size_t i = 0; i < ${f.size()}; i++)
	        % endif
		% if not varsized and not f.type_obj.is_assignable():
		    % if f.is_varlen():			
		fromwire_${type_}(&cursor, &plen, *${f.name} + i);
		    % else:
		fromwire_${type_}(&cursor, &plen, &(${f.name}[i]));
		    % endif
		% else:
		(${'' if f.type_obj.is_assignable() and f.is_array() else '*'}${f.name})[i] = fromwire_${type_}(${'*'+f.name+', ' if varsized else ''}&cursor, &plen);
		% endif
	    % endif
	% else:
	    % if not f.is_optional:
	${fromwire_phrase(f, type_, varsized)}\
	    % else: ## Start optional
	if (!fromwire_bool(&cursor, &plen))
		*${f.name} = NULL;
	else {
		% if not varsized:
		*${f.name} = tal(ctx, ${typename});
		% endif
		${'*' if f.type_obj.is_assignable() else ''}${fromwire_phrase(f, type_, varsized)}\
	}
	    % endif ## End optional
	% endif
	% endfor
	return cursor != NULL;
}
    % if msg.if_token:
#endif /* ${msg.if_token} */
    % endif
% endfor ## END Wire Messages