#define BORDER_CHARS		1

U8   *buf;
I64	  size, mp_not_done_flags;
CDoc *doc;

U0 PDNormalize()
{
	U8 *r = MAlloc(size+2*BORDER_CHARS), *src = buf, *dst = r;
	I64 ch;

	*dst++ = '['; //Border
	while (size--)
	{
		ch = *src++;
		if ('a' <= ch <= 'z') //lower is most common so do first
			*dst++ = ch;
		else if ('A' <= ch <= 'Z')
			*dst++ = ch + 'a' - 'A'; //Convert to lower
	}
	*dst++ = ']'; //Border
	Free(buf);
	buf = r;
	size = dst - r - 2 * BORDER_CHARS;
}

U0 PDAnswer(U8 *a, I64 len)
{
	DocLock(doc);
	a -= (len - 1) / 2;
	DocPrint(doc, "CPU%02X Len:%2d ", Gs->num, len);
	while (len--)
		DocPrint(doc, "%C", *a++); //%C is toupper char
	DocPrint(doc, "\n");
	DocUnlock(doc);
}

U0 MPPalindrome(I64 dummy=0)
{
	no_warn dummy;
	U8 *src = buf + BORDER_CHARS + size * Gs->num / mp_count, *f, *b;
	I64 len, best = 0, my_size = (size + mp_count - 1) / mp_count;
	while (my_size--)
	{

		//Odd
		f = src + 1;
		b = src - 1;
		while (*f == *b)
		{
			f++;
			b--;
		}
		len = f - b + 1 - 2;
		if (len > best)
		{
			best = len;
			PDAnswer(src, len);
		}

		//Even
		f = src + 1;
		b = src;
		while (*f == *b)
		{
			f++;
			b--;
		}
		len = f - b + 1 - 2;
		if (len > best)
		{
			best = len;
			PDAnswer(src, len);
		}

		src++;
	}
	LBtr(&mp_not_done_flags, Gs->num);
}

U0 Palindrome(U8 *filename)
{
	I64 i;
	F64 t0 = tS;

	buf = FileRead(filename, &size);
	PDNormalize;

	doc = DocPut;
	mp_not_done_flags = 1 << mp_count - 1;
	for (i = 0; i < mp_count; i++)
		JobQueue(&MPPalindrome, NULL, i);
	while (mp_not_done_flags)
		Yield;

	Free(buf);
	"Time:%9.5f\n", tS - t0;
}

Palindrome("/Misc/Vocab.DD");
