
#include "smartcolsP.h"
#include "mbsalign.h"

/* This is private struct to work with output data */
struct libscols_buffer {
	char	*begin;		/* begin of the buffer */
	char	*cur;		/* current end of  the buffer */
	char	*encdata;	/* encoded buffer mbs_safe_encode() */

	size_t	bufsz;		/* size of the buffer */
	size_t	art_idx;	/* begin of the tree ascii art or zero */
};

struct libscols_buffer *new_buffer(size_t sz)
{
	struct libscols_buffer *buf = malloc(sz + sizeof(struct libscols_buffer));

	if (!buf)
		return NULL;

	buf->cur = buf->begin = ((char *) buf) + sizeof(struct libscols_buffer);
	buf->encdata = NULL;
	buf->bufsz = sz;

	DBG(BUFF, ul_debugobj(buf, "alloc (size=%zu)", sz));
	return buf;
}

void free_buffer(struct libscols_buffer *buf)
{
	if (!buf)
		return;
	DBG(BUFF, ul_debugobj(buf, "dealloc"));
	free(buf->encdata);
	free(buf);
}

int buffer_reset_data(struct libscols_buffer *buf)
{
	if (!buf)
		return -EINVAL;

	/*DBG(BUFF, ul_debugobj(buf, "reset data"));*/
	buf->begin[0] = '\0';
	buf->cur = buf->begin;
	buf->art_idx = 0;
	return 0;
}

int buffer_append_data(struct libscols_buffer *buf, const char *str)
{
	size_t maxsz, sz;

	if (!buf)
		return -EINVAL;
	if (!str || !*str)
		return 0;
	if (!buf->cur || !buf->begin)
		return -EINVAL;

	sz = strlen(str);
	maxsz = buf->bufsz - (buf->cur - buf->begin);

	if (maxsz <= sz)
		return -EINVAL;
	memcpy(buf->cur, str, sz + 1);
	buf->cur += sz;
	return 0;
}

int buffer_append_ntimes(struct libscols_buffer *buf, size_t n, const char *str)
{
	size_t i;

	for (i = 0; i < n; i++) {
		int rc = buffer_append_data(buf, str);
		if (rc)
			return rc;
	}
	return 0;
}

int buffer_set_data(struct libscols_buffer *buf, const char *str)
{
	int rc = buffer_reset_data(buf);
	return rc ? rc : buffer_append_data(buf, str);
}

/* save the current buffer position to art_idx */
void buffer_set_art_index(struct libscols_buffer *buf)
{
	if (buf) {
		buf->art_idx = buf->cur - buf->begin;
		/*DBG(BUFF, ul_debugobj(buf, "art index: %zu", buf->art_idx));*/
	}
}

char *buffer_get_data(struct libscols_buffer *buf)
{
	return buf ? buf->begin : NULL;
}

size_t buffer_get_size(struct libscols_buffer *buf)
{
	return buf ? buf->bufsz : 0;
}

/* encode data by mbs_safe_encode() to avoid control and non-printable chars */
char *buffer_get_safe_data(struct libscols_table *tb,
				  struct libscols_buffer *buf,
				  size_t *cells,
				  const char *safechars)
{
	char *data = buffer_get_data(buf);
	char *res = NULL;

	if (!data)
		goto nothing;

	if (!buf->encdata) {
		buf->encdata = malloc(mbs_safe_encode_size(buf->bufsz) + 1);
		if (!buf->encdata)
			goto nothing;
	}

	if (scols_table_is_noencoding(tb)) {
		*cells = mbs_width(data);
		strcpy(buf->encdata, data);
		res = buf->encdata;
	} else {
		res = mbs_safe_encode_to_buffer(data, cells, buf->encdata, safechars);
	}

	if (!res || !*cells || *cells == (size_t) -1)
		goto nothing;
	return res;
nothing:
	*cells = 0;
	return NULL;
}

/* returns size in bytes of the ascii art (according to art_idx) in safe encoding */
size_t buffer_get_safe_art_size(struct libscols_buffer *buf)
{
	char *data = buffer_get_data(buf);
	size_t bytes = 0;

	if (!data || !buf->art_idx)
		return 0;

	mbs_safe_nwidth(data, buf->art_idx, &bytes);
	return bytes;
}
