/*
 * libptouch — context, errors, raster validation
 *
 * Author: knb
 * Email: knb@artif.org
 */

#include "libptouch_internal.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void ptouch_set_error(libptouch_ctx *ctx, libptouch_err_t code, const char *msg)
{
	if (!ctx)
		return;
	ctx->last_code = code;
	if (msg) {
		snprintf(ctx->last_msg, sizeof(ctx->last_msg), "%s", msg);
	} else {
		ctx->last_msg[0] = '\0';
	}
}

void ptouch_set_error_usb(libptouch_ctx *ctx, int libusb_err, const char *what)
{
	char buf[256];
	snprintf(buf, sizeof(buf), "%s: %s", what,
		 libusb_strerror((enum libusb_error)libusb_err));
	ptouch_set_error(ctx, LIBPTOUCH_ERR_USB, buf);
}

libptouch_ctx *libptouch_create(void)
{
	libptouch_ctx *ctx = calloc(1, sizeof(*ctx));
	if (!ctx)
		return NULL;
	ctx->last_code = LIBPTOUCH_OK;
	ctx->last_msg[0] = '\0';
	ctx->usb_open = 0;
	ctx->usb_ctx = NULL;
	ctx->usb_handle = NULL;
	ctx->claimed_interface = -1;
	ctx->bulk_out_ep = 0;
	ctx->bulk_in_ep = 0;
	return ctx;
}

void libptouch_destroy(libptouch_ctx *ctx)
{
	if (!ctx)
		return;
	libptouch_close(ctx);
	free(ctx);
}

const char *libptouch_strerror(const libptouch_ctx *ctx)
{
	if (!ctx)
		return "(null ctx)";
	return ctx->last_msg[0] ? ctx->last_msg : "ok";
}

libptouch_err_t libptouch_last_error(const libptouch_ctx *ctx)
{
	if (!ctx)
		return LIBPTOUCH_ERR_ARG;
	return ctx->last_code;
}

libptouch_err_t libptouch_check_raster(libptouch_ctx *ctx,
				       const uint8_t *data, size_t data_len,
				       const libptouch_raster_params_t *params)
{
	if (!ctx || !params) {
		if (ctx)
			ptouch_set_error(ctx, LIBPTOUCH_ERR_ARG, "null argument");
		return LIBPTOUCH_ERR_ARG;
	}
	if (!data && data_len > 0) {
		ptouch_set_error(ctx, LIBPTOUCH_ERR_ARG, "data is null but len > 0");
		return LIBPTOUCH_ERR_ARG;
	}

	size_t row = (params->width_dots + 7u) / 8u;
	size_t expected = (size_t)params->height_dots * row;
	if (data_len != expected) {
		char buf[160];
		snprintf(buf, sizeof(buf),
			 "data_len mismatch: got %zu, expected %zu (w=%u h=%u)",
			 data_len, expected, params->width_dots,
			 params->height_dots);
		ptouch_set_error(ctx, LIBPTOUCH_ERR_ARG, buf);
		return LIBPTOUCH_ERR_ARG;
	}

	ptouch_set_error(ctx, LIBPTOUCH_OK, "");
	return LIBPTOUCH_OK;
}
