#include "cgit.h"
#include "html.h"
#include "ui-shared.h"

extern int use_ssdiff;

static int current_old_line, current_new_line;

struct deferred_lines {
	int line_no;
	char *line;
	struct deferred_lines *next;
};

static struct deferred_lines *deferred_old, *deferred_old_last;
static struct deferred_lines *deferred_new, *deferred_new_last;

static char *longest_common_subsequence(char *A, char *B)
{
	int i, j, ri;
	int m = strlen(A);
	int n = strlen(B);
	int L[m + 1][n + 1];
	int tmp1, tmp2;
	int lcs_length;
	char *result;

	for (i = m; i >= 0; i--) {
		for (j = n; j >= 0; j--) {
			if (A[i] == '\0' || B[j] == '\0') {
				L[i][j] = 0;
			} else if (A[i] == B[j]) {
				L[i][j] = 1 + L[i + 1][j + 1];
			} else {
				tmp1 = L[i + 1][j];
				tmp2 = L[i][j + 1];
				L[i][j] = (tmp1 > tmp2 ? tmp1 : tmp2);
			}
		}
	}

	lcs_length = L[0][0];
	result = xmalloc(lcs_length + 2);
	memset(result, 0, sizeof(*result) * (lcs_length + 2));

	ri = 0;
	i = 0;
	j = 0;
	while (i < m && j < n) {
		if (A[i] == B[j]) {
			result[ri] = A[i];
			ri += 1;
			i += 1;
			j += 1;
		} else if (L[i + 1][j] >= L[i][j + 1]) {
			i += 1;
		} else {
			j += 1;
		}
	}
	return result;
}

static int line_from_hunk(char *line, char type)
{
	char *buf1, *buf2;
	int len;

	buf1 = strchr(line, type);
	if (buf1 == NULL)
		return 0;
	buf1 += 1;
	buf2 = strchr(buf1, ',');
	if (buf2 == NULL)
		return 0;
	len = buf2 - buf1;
	buf2 = xmalloc(len + 1);
	strncpy(buf2, buf1, len);
	buf2[len] = '\0';
	int res = atoi(buf2);
	free(buf2);
	return res;
}

static char *replace_tabs(char *line)
{
	char *prev_buf = line;
	char *cur_buf;
	int linelen = strlen(line);
	int n_tabs = 0;
	int i;
	char *result;
	char *spaces = "        ";

	if (linelen == 0) {
		result = xmalloc(1);
		result[0] = '\0';
		return result;
	}

	for (i = 0; i < linelen; i++)
		if (line[i] == '\t')
			n_tabs += 1;
	result = xmalloc(linelen + n_tabs * 8 + 1);
	result[0] = '\0';

	while (1) {
		cur_buf = strchr(prev_buf, '\t');
		if (!cur_buf) {
			strcat(result, prev_buf);
			break;
		} else {
			strcat(result, " ");
			strncat(result, spaces, 8 - (strlen(result) % 8));
			strncat(result, prev_buf, cur_buf - prev_buf);
		}
		prev_buf = cur_buf + 1;
	}
	return result;
}

static int calc_deferred_lines(struct deferred_lines *start)
{
	struct deferred_lines *item = start;
	int result = 0;
	while (item) {
		result += 1;
		item = item->next;
	}
	return result;
}

static void deferred_old_add(char *line, int line_no)
{
	struct deferred_lines *item = xmalloc(sizeof(struct deferred_lines));
	item->line = xstrdup(line);
	item->line_no = line_no;
	item->next = NULL;
	if (deferred_old) {
		deferred_old_last->next = item;
		deferred_old_last = item;
	} else {
		deferred_old = deferred_old_last = item;
	}
}

static void deferred_new_add(char *line, int line_no)
{
	struct deferred_lines *item = xmalloc(sizeof(struct deferred_lines));<style>pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Ins