#include "lib_ccx.h"
#include "ccx_common_option.h"
#include "ccx_encoders_common.h"
#include "png.h"
#include "ocr.h"
#include "utility.h"
#include "ccx_encoders_helpers.h"

int write_stringz_as_sami(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end)
{
	int used;
	int len = 0;
	int ret = 0;
	unsigned char *unescaped = NULL;
	unsigned char *el = NULL;
	char str[1024];

	sprintf(str, "<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n", (unsigned long long)ms_start);
	if (context->encoding != CCX_ENC_UNICODE)
	{
		dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
	}

	used = encode_line(context, context->buffer, (unsigned char *)str);
	ret = write(context->out->fh, context->buffer, used);
	if (ret != used)
		return ret;

	len = strlen(string);
	unescaped = (unsigned char *)malloc(len + 1);
	if (unescaped == NULL)
	{
		mprint("In write_stringz_as_sami() - not enough memory for len %d.\n", len);
		return -1;
	}

	el = (unsigned char *)malloc(len * 3 + 1); // Be generous
	if (el == NULL)
	{
		mprint("In write_stringz_as_sami() - not enough memory for len %d.\n", len);
		ret = -1;
		goto end;
	}

	int pos_r = 0;
	int pos_w = 0;
	// Scan for \n in the string and replace it with a 0
	while (pos_r < len)
	{
		if (string[pos_r] == '\\' && string[pos_r + 1] == 'n')
		{
			unescaped[pos_w] = 0;
			pos_r += 2;
		}
		else
		{
			unescaped[pos_w] = string[pos_r];
			pos_r++;
		}
		pos_w++;
	}
	unescaped[pos_w] = 0;
	// Now read the unescaped string (now several string'z and write them)
	unsigned char *begin = unescaped;
	while (begin < unescaped + len)
	{
		unsigned int u = encode_line(context, el, begin);
		if (context->encoding != CCX_ENC_UNICODE)
		{
			dbg_print(CCX_DMT_DECODER_608, "\r");
			dbg_print(CCX_DMT_DECODER_608, "%s\n", context->subline);
		}
		ret = write(context->out->fh, el, u);
		if (ret != u)
			goto end;

		ret = write(context->out->fh, context->encoded_br, context->encoded_br_length);
		if (ret != context->encoded_br_length)
			goto end;

		ret = write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
		if (ret != context->encoded_crlf_length)
			goto end;

		begin += strlen((const char *)begin) + 1;
	}

	sprintf((char *)str, "</P></SYNC>\r\n");
	if (context->encoding != CCX_ENC_UNICODE)
	{
		dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
	}
	used = encode_line(context, context->buffer, (unsigned char *)str);
	ret = write(context->out->fh, context->buffer, used);
	if (ret != used)
		goto end;
	sprintf((char *)str,
		"<SYNC start=%llu><P class=\"UNKNOWNCC\">&nbsp;</P></SYNC>\r\n\r\n",
		(unsigned long long)ms_end);
	if (context->encoding != CCX_ENC_UNICODE)
	{
		dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
	}
	ret = write(context->out->fh, context->buffer, used);
	if (ret != used)
		goto end;

end:
	free(el);
	free(unescaped);
	return ret;
}

int write_cc_bitmap_as_sami(struct cc_subtitle *sub, struct encoder_ctx *context)
{
	int ret = 0;
#ifdef ENABLE_OCR
	struct cc_bitmap *rect;

	rect = sub->data;

	if (sub->flags & SUB_EOD_MARKER)
		context->prev_start = sub->start_time;

	char *token = NULL;
	char *buf = (char *)context->buffer;

	if (sub->data != NULL) //then we should write the sub
	{
		sprintf(buf,
			"<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n", (unsigned long long)sub->start_time);
		write_wrapped(context->out->fh, buf, strlen(buf));
		for (int i = sub->nb_data - 1; i >= 0; i--)
		{
			if (rect[i].ocr_text && *(rect[i].ocr_text))
			{
				if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
				{
					token = strtok(rect[i].ocr_text, "\r\n");
					sprintf(buf, "%s", token);
					token = strtok(NULL, "\r\n");
					write_wrapped(context->out->fh, buf, strlen(buf));
					if (i != 0)
						write_wrapped(context->out->fh, context->encoded_br, context->encoded_br_length);
					write_wrapped(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
				}
			}
		}
		sprintf(buf, "</P></SYNC>\r\n");
		write_wrapped(context->out->fh, buf, strlen(buf));
	}
	else //we write an empty subtitle to clear the old one
	{
		sprintf(buf,
			"<SYNC start=%llu><P class=\"UNKNOWNCC\">&nbsp;</P></SYNC>\r\n\r\n", (unsigned long long)sub->start_time);
		write_wrapped(context->out->fh, buf, strlen(buf));
	}
#endif

	sub->nb_data = 0;
	freep(&sub->data);
	return ret;
}

int write_cc_subtitle_as_sami(struct cc_subtitle *sub, struct encoder_ctx *context)
{
	int ret = 0;
	struct cc_subtitle *osub = sub;
	struct cc_subtitle *lsub = sub;
	while (sub)
	{
		if (sub->type == CC_TEXT)
		{
			ret = write_stringz_as_sami(sub->data, context, sub->start_time, sub->end_time);
			freep(&sub->data);
			sub->nb_data = 0;
		}
		lsub = sub;
		sub = sub->next;
	}
	while (lsub != osub)
	{
		sub = lsub->prev;
		freep(&lsub);
		lsub = sub;
	}

	return ret;
}

int write_cc_buffer_as_sami(struct eia608_screen *data, struct encoder_ctx *context)
{
	int used;
	int wrote_something = 0;
	char str[1024];

	sprintf(str, "<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n",
		(unsigned long long)data->start_time);
	if (context->encoding != CCX_ENC_UNICODE)
	{
		dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
	}
	used = encode_line(context, context->buffer, (unsigned char *)str);
	write_wrapped(context->out->fh, context->buffer, used);
	for (int i = 0; i < 15; i++)
	{
		if (data->row_used[i])
		{
			int length = get_decoder_line_encoded(context, context->subline, i, data);
			if (context->encoding != CCX_ENC_UNICODE)
			{
				dbg_print(CCX_DMT_DECODER_608, "\r");
				dbg_print(CCX_DMT_DECODER_608, "%s\n", context->subline);
			}
			write_wrapped(context->out->fh, context->subline, length);
			wrote_something = 1;
			if (i != 14)
				write_wrapped(context->out->fh, context->encoded_br, context->encoded_br_length);
			write_wrapped(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
		}
	}
	sprintf((char *)str, "</P></SYNC>\r\n");
	if (context->encoding != CCX_ENC_UNICODE)
	{
		dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
	}
	used = encode_line(context, context->buffer, (unsigned char *)str);
	write_wrapped(context->out->fh, context->buffer, used);
	sprintf((char *)str,
		"<SYNC start=%llu><P class=\"UNKNOWNCC\">&nbsp;</P></SYNC>\r\n\r\n",
		(unsigned long long)data->end_time - 1); // - 1 to prevent overlap
	if (context->encoding != CCX_ENC_UNICODE)
	{
		dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str);
	}
	used = encode_line(context, context->buffer, (unsigned char *)str);
	write_wrapped(context->out->fh, context->buffer, used);
	return wrote_something;
}
