/*
 * Copyright {{Year}} {{Author}} <{{Email}}>
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 */

#include "config.h"

#include <fwupdplugin.h>

#include "fu-{{vendor_dash_example}}-firmware.h"
#include "fu-{{vendor_dash_example}}-struct.h"

struct _Fu{{VendorExample}}Firmware {
	FuFirmware parent_instance;
	guint16 start_addr;
};

G_DEFINE_TYPE(Fu{{VendorExample}}Firmware, fu_{{vendor_example}}_firmware, FU_TYPE_FIRMWARE)

static void
fu_{{vendor_example}}_firmware_export(FuFirmware *firmware,
				   FuFirmwareExportFlags flags,
				   XbBuilderNode *bn)
{
	Fu{{VendorExample}}Firmware *self = FU_{{VENDOR_EXAMPLE}}_FIRMWARE(firmware);
	fu_xmlb_builder_insert_kx(bn, "start_addr", self->start_addr);
}

static gboolean
fu_{{vendor_example}}_firmware_build(FuFirmware *firmware, XbNode *n, GError **error)
{
	Fu{{VendorExample}}Firmware *self = FU_{{VENDOR_EXAMPLE}}_FIRMWARE(firmware);
	guint64 tmp;

	/* TODO: load from .builder.xml */
	tmp = xb_node_query_text_as_uint(n, "start_addr", NULL);
	if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT16)
		self->start_addr = tmp;

	/* success */
	return TRUE;
}

static gboolean
fu_{{vendor_example}}_firmware_validate(FuFirmware *firmware,
					GInputStream *stream,
					gsize offset,
					GError **error)
{
	return fu_struct_{{vendor_example}}_header_validate_stream(stream,
						     offset,
						     error);
}

static gboolean
fu_{{vendor_example}}_firmware_parse(FuFirmware *firmware,
				 GInputStream *stream, FuFirmwareParseFlags flags,
				 GError **error)
{
	Fu{{VendorExample}}Firmware *self = FU_{{VENDOR_EXAMPLE}}_FIRMWARE(firmware);
	g_autoptr(GByteArray) st_hdr = NULL;

	/* TODO: parse firmware into images */
	st_hdr = fu_struct_{{vendor_example}}_hdr_parse_stream(stream, 0x0, error);
	if (st_hdr == NULL)
		return FALSE;
	self->start_addr = 0x1234;
	fu_firmware_set_version(firmware, "1.2.3");
	fu_firmware_set_bytes(firmware, fw);
	return TRUE;
}

static GByteArray *
fu_{{vendor_example}}_firmware_write(FuFirmware *firmware, GError **error)
{
	Fu{{VendorExample}}Firmware *self = FU_{{VENDOR_EXAMPLE}}_FIRMWARE(firmware);
	g_autoptr(GByteArray) buf = g_byte_array_new();
	g_autoptr(GBytes) fw = NULL;

	/* data first */
	fw = fu_firmware_get_bytes_with_patches(firmware, error);
	if (fw == NULL)
		return NULL;

	/* TODO: write to the buffer with the correct format */
	g_assert(self != NULL);
	fu_byte_array_append_bytes(buf, fw);

	/* success */
	return g_steal_pointer(&buf);
}

guint16
fu_{{vendor_example}}_firmware_get_start_addr(Fu{{VendorExample}}Firmware *self)
{
	g_return_val_if_fail(FU_IS_{{VENDOR_EXAMPLE}}_FIRMWARE(self), G_MAXUINT16);
	return self->start_addr;
}

static void
fu_{{vendor_example}}_firmware_init(Fu{{VendorExample}}Firmware *self)
{
	fu_firmware_add_flag(FU_FIRMWARE(self), FU_FIRMWARE_FLAG_HAS_STORED_SIZE);
	fu_firmware_add_flag(FU_FIRMWARE(self), FU_FIRMWARE_FLAG_HAS_CHECKSUM);
	fu_firmware_add_flag(FU_FIRMWARE(self), FU_FIRMWARE_FLAG_HAS_VID_PID);
}

static void
fu_{{vendor_example}}_firmware_class_init(Fu{{VendorExample}}FirmwareClass *klass)
{
	FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass);
	firmware_class->validate = fu_{{vendor_example}}_firmware_validate;
	firmware_class->parse = fu_{{vendor_example}}_firmware_parse;
	firmware_class->write = fu_{{vendor_example}}_firmware_write;
	firmware_class->build = fu_{{vendor_example}}_firmware_build;
	firmware_class->export = fu_{{vendor_example}}_firmware_export;
}

FuFirmware *
fu_{{vendor_example}}_firmware_new(void)
{
	return FU_FIRMWARE(g_object_new(FU_TYPE_{{VENDOR_EXAMPLE}}_FIRMWARE, NULL));
}
